1.面向对象(上)

1.1定义

  • 面向对象编程:oop [object oriented programming] 是一种python的编程思路;
  • 面向过程:就是我们一开始学习的,按照解决问题的步骤去写代码 【根据业务逻辑去写代码】,在思考问题的时候, 首先分析'怎么按照步骤去实现' 然后将问题解决拆解成若干个步骤,并将这些步骤对应成方法一步一步的 最终完成功能。
  • 面向对象:关注的是设计思维【找洗车店 给钱洗车】

1.2类和对象

类和对象

类:类是具有一组 相同或者相似特征【属性】和行为【方法】的一系列[多个]对象组合

现实世界    计算机世界
行为---------> 方法
特征---------->属性

对象: 对象是实实在在的一个东西,类的实例化,具象化

类是对象的抽象化  而对象是类的一个实例

1.3定义类和创建对象、实例方法和属性、init方法

实例方法:在类的内部,使用def 关键字来定义  第一个参数默认是 self
【名字标识可以是其他的名字,但是这个位置必须被占用】

实例方法是归于 类的实例所有

属性:类属性  实例属性
在类的内部定义的变量【类属性】
在方法内部定义的【通过类似于self.变量名】 变量,是实例属性
# 定义类和对象
# 类结构  类名  属性  方法
# class 类名:
#     属性
#     方法

class Person:
    '''
    对应人的特征
    '''
    # name='小明'  #类属性
    age=20       #类属性
    '''
    对应人的行为  实例方法
    '''
    def __init__(self):
        self.name='小明'   #实例属性
        pass
    def eat(parms):
        print("大口的吃饭")
        pass
    def run(self):   #实例方法
        print('飞快的跑')
        pass
    pass
def printInfo():
    '''
    普通方法
    :return:
    '''
    pass
# 创建一个对象【类的实例化】
# 规则格式  对象名=类名()
xm=Person()
xm.eat() #调用函数
xm.run()
print("{}的年龄是:{}".format(xm.name,xm.age))

# 创建另外一个实例对象
xw=Person()
xw.eat()  #实例方法

1.4 init方法

# init传递参数 改进
class Pepole:
    def __init__(self,name,sex,age):
        '''
        实例属性的声明
        '''
        self.name=name
        self.sex=sex
        self.age=age
        pass
    def eat(self,food):
        '''
        吃的行为
        :return:
        '''
        print(self.name+'喜欢吃'+food)
    pass

zp=Pepole('张鹏','男生',18)
print(zp.name,zp.age)
zp.eat('香蕉')
lh=Pepole('李辉','男生',28)
lh.eat('苹果')
print(lh.name,lh.age)

xh=Pepole('小花','女生',20)
xh.eat('橘子')
print(xh.name,xh.age)

# 总结 __init__
# 1. python 自带的内置函数 具有特殊的函数   使用双下划线 包起来的【魔术方法】
# 2. 是一个初始化的方法 用来定义实例属性 和初始化数据的,在创建对象的时候自动调用  不用手动去调用
# 3. 利用传参的机制可以让我们定义功能更加强大并且方便的 类

1.5 self理解

python学习总结--面向对象_类属性

小结  self特点
self只有在类中定义 实例方法的时候才有意义,在调用时候不必传入相应的参数 而是由解释器 自动去指向;![在这里插入图片描述](https://img-blog.csdnimg.cn/6021b15274424412930d9e9cfee67965.png)

self的名字是可以更改的  可以定义成其他的名字,只是约定俗成的定义成了 self
self 指的是 类实例对象本身, 相当于java中 this
class Person:
    def __init__(self,pro,name,food):
        '''

        :param pro: 专业
        :param name: 姓名
        :param food: 食物
        '''
        self.pro=pro  #实例属性的定义
        self.name=name
        self.food=food
        print('----init-----函数执行')
        pass
    '''
   定义类
    '''
    def eat(self,name,food):
        '''
        实例方法
        :return:
        '''
        # print('self=%s',id(self))
        print('%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro))
        pass
 
    pass


# xw是一个新的实例化对象
xw=Person('心理学','小王','榴莲')
# print('xw=%s',id(xw))
# xw.eat('小王','榴莲')
print(xw)  #直接输出对象

1.6 魔术方法

  • 定义:
class Person:
    def __init__(self,pro,name,food):
        '''

        :param pro: 专业
        :param name: 姓名
        :param food: 食物
        '''
        self.pro=pro  #实例属性的定义
        self.name=name
        self.food=food
        print('----init-----函数执行')
        pass
    '''
   定义类
    '''
    def eat(self,name,food):
        '''
        实例方法
        :return:
        '''
        # print('self=%s',id(self))
        print('%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro))
        pass
    def __str__(self):
        '''
        打印对象 自定义对象 是内容格式的
        :return:
        '''
        return '%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro)
        pass
    def __new__(cls, *args, **kwargs):
        '''
        创建对象实例的方法  每调用一次 就会生成一个新的对象 cls 就是class的缩写

        场景:可以控制创建对象的一些属性限定 经常用来做单例模式的时候来使用
        :param args:
        :param kwargs:
        '''
        print('----new-----函数的执行')
        return object.__new__(cls) #在这里是真正创建对象实例的
        pass
    pass


# xw是一个新的实例化对象
xw=Person('心理学','小王','榴莲')
# print('xw=%s',id(xw))
# xw.eat('小王','榴莲')
print(xw)  #直接输出对象
# 小结  self特点
# self只有在类中定义 实例方法的时候才有意义,在调用时候不必传入相应的参数 而是由解释器 自动去指向
# self的名字是可以更改的  可以定义成其他的名字,只是约定俗成的定义成了 self
# self 指的是 类实例对象本身, 相当于java中 this

# __new__和__init___函数的区别
# __new__ 类的实例化方法 必须要返回该实例 否则对象就创建不成功
# __init___ 用来做数据属性的初始化工作  也可以认为是实例的构造方法  接受类的实例 self 并对其进行构造
# __new__   至少有一个参数是 cls 代表要实例化的类 ,此参数在实例化时由python解释器自动提供
# __new__  函数 执行要早于 __init___ 函数

2.面向对象(中)

2.1析构方法

class Animal:
    def __init__(self,name):
        self.name=name
        print('这是构造初始化方法')
        pass
    def __del__(self):
        # 主要的应用就是来操作 对象的释放  一旦释放完毕  对象便不能在使用
        print('当在某个作用域下面 没有被使用【引用】的情况下 解析器会自动的调用此函数 来释放内存空间')
        print('这是析构方法')
        print('%s 这个对象 被彻底清理了 内存空间也释放了'%self.name)
    pass

cat=Animal('小花猫')
# del cat  #手动的去清理删除对象  会指定__del__函数
print(cat.name)
input('程序等待中.....')
# print('*'*40)
# dog=Animal('柯基小狗')

2.2单继承

class Animal:
    def  eat(self):
        '''
        吃
        :return:
        '''
        print('吃饭了')
        pass
    def drink(self):
        '''
        喝
        :return:
        '''
        pass

class Dog(Animal): #继承了Animal 父类 此时dog就是子类
    def wwj(self):
        '''
        子类独有的实现
        :return:
        '''
        print('小狗汪汪叫')
    pass
class Cat(Animal):
    def mmj(self):
        '''
         子类独有的实现
        :return:
        '''
        print('小猫喵喵叫')
    pass

d1=Dog()
d1.eat() #具备了吃的行为  是继承了父类的行为
d1.wwj()
print('**************cat 的行为**********************')
c1=Cat()
c1.eat()
c1.mmj()

2.3多继承

注:# 问题是 当多个父类当中存在相同方法的时候 应该去调用哪一个呢? 答:广度优先/(print(A.mro) #可以显示类的依次继承关系)

class shenxian:
    def fly(self):
        print("神仙都会飞")
    pass
class Monkey:
    def chitao(self):
        print('猴子喜欢吃桃')
    pass
class Sunwukong(shenxian,Monkey): #即使神仙  同时也是猴子
    pass

# swk=Sunwukong()
# swk.chitao()
# swk.fly()
####################################################
# 问题是  当多个父类当中存在相同方法的时候  应该去调用哪一个呢
class D(object):
    def eat(self):
        print('D.eat')
        pass
    pass
class C(D):
    def eat(self):
        print('C.eat')
        pass
    pass
class B(D):
    pass
class A(B,C):
    pass
a=A()
a.eat()
print(A.__mro__) #可以显示类的依次继承关系
#在执行eat的方法时 查找方法的顺序是
# 首先到A里面去查找  如果A中没有 则继续的去B类中去查找 如果B中没有
# 则去C中查找 如果C类中没有 则去D类中去查找,如果还是没有找到 就会报错
# A-B-C-D  也是继承的顺序

2.4间接继承

class GrandFather:
    def eat(self):
        print('吃的 方法')
        pass
    pass
class Father(GrandFather):
    pass

class Son(Father):
    pass

son=Son()
print(Son.__mro__)
son.eat() #此方法 是从GrandFather继承过来的

2.5重写和调用父类方法

  • 所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
  • 为什么要重写, 父类的方法已经不满足子类的需要,那么子类就可以重写父类或者完善父类的方法
class Dog:
    def __init__(self,name,color):
        self.name=name
        self.color=color

    def bark(self):
        print('汪汪叫....')
        pass
    pass
class kejiquan(Dog):
    def __init__(self,name,color):#属于重写父类的方法
        # 针对这种需求  我们就需要去调用父类的函数了
        # Dog.__init__(self,name,color) #手动调用  调用父类的方法了 执行完毕就可以具备name,color这两个实例属性了\
        super().__init__(name,color) #super是自动找到父类 进而调用方法, 假设继承了多个父类,那么会按照顺序逐个去找 然后在调用
        # 拓展其他的属性
        self.height=90
        self.weight=20
        pass
    def __str__(self):
        return '{}的颜色会{} 它的身高是{}cm 体重是:{}'.format(self.name,self.color,self.height,self.weight
                                                  )
    def bark(self): #属于重写类的方法
        super().bark() #调用父类的方法
        print('叫的跟神一样')
        print(self.name)
    pass

kj=kejiquan('柯基犬','红色')
kj.bark()
print(kj)

注: super是自动找到父类 进而调用方法

2.6 类属性和实例属性

注: 类属性 就是类对象所拥有的属性(类对象不同于实例对象,这里和java有点不同,这里所说的类对象应该就是java里面的元对象)

  • 小结
  • 类属性是可以 被类对象和实例对象共同访问使用的
  • 实例属性只能由实例对象所访问
class Student:
    name='李明' #属于类属性  就是student类对象所拥有的
    def __init__(self,age):
        self.age=age #实例属性
        pass
    @staticmethod
    def aaa(x,y):
        print(x+y)
    pass

Student.name='李易峰' #通过类对象去修改数据 可以修改的  因为name的所拥有的权利属于类对象

lm=Student(18)
print(lm.name) #通过实例对象去访问类属性
# lm.name='刘德华'  #通过实例对象 对类属性进行修改 可以吗? 不可以的
print(lm.name)
print(lm.age)
Student.aaa(4,6)
print('---------xh的数据---------------')
xh=Student(28)
print(xh.name)
print(xh.age)
print('---------通过类对象 student 去访问name---------------')
# print(Student.name)  如 类名.属性名 形式去访问
# print(Student.age)
# 小结
# 类属性是可以 被类对象和实例对象共同访问使用的
# 实例属性只能由实例对象所访问

分析:

python学习总结--面向对象_类属性_02

2.7类方法和静态方法

  • 类方法是类所拥有的,可以访问类变量,可以通过类对象和实例对象访问。必须传参数。
  • 静态方法和类方法差不多,但是不必须传参数。
  • 为什么要使用静态方法呢?1. 由于静态方法主要来存放逻辑性的代码,本身和类以及实例对象没有交互;2.也就是说,在静态方法中,不会涉及到类中方法和属性的操作;3.数据资源能够得到有效的充分利用。
class  People:
    country='china'
    #类方法 用 classmethod 来进行修饰
    @classmethod
    def get_country(cls):
        return cls.country #访问类属性
        pass
    @classmethod
    def change_country(cls,data):
        cls.country=data #修改类属性的值  在类方法中
        pass
    @staticmethod
    def getData():
        return People.country  #通过类对象去引用
        pass
    @staticmethod
    def add(x,y):
        return x+y
        pass


print(People.add(10,56)) #带有参数的静态方法

# print(People.getData())

# print(People.get_country()) #通过类对象去引用
p=People()
print(p.getData()) #注意 一般情况下 我们不会通过实例对象去访问静态方法
# print('实例对象访问 %s'%p.get_country())
# print('-----------------修改之后---------------------------')
# People.change_country('英国')
# print(People.get_country()) #通过类对象去引用

# 为什么要使用静态方法呢
# 由于静态方法主要来存放逻辑性的代码,本身和类以及实例对象没有交互,
# 也就是说,在静态方法中,不会涉及到类中方法和属性的操作
# 数据资源能够得到有效的充分利用

# demo  返回当前的系统时间
import  time # 引入第三方的时间模块
class TimeTest:
    def __init__(self,hour,min,second):
        self.hour=hour
        self.min = min
        self.second = second

    @staticmethod
    def showTime():
        return time.strftime("%H:%M:%S",time.localtime())
        pass
    pass

print(TimeTest.showTime())
t=TimeTest(2,10,15)
print(t.showTime()) #没有必要通过这种方式去访问 静态方法

2.8三种方法对比

  • 从方法定义的形式可以看出来
  • 1.类方法的第一个参数是类对象 cls 进而去引用类对象的属性和方法 必须用装饰器 @classmethod来修饰
  • 2.实例方法的第一个参数必须是self,通过这个self 可以去引用类属性或者实例属性,若存在相同名称实例属性和类属性的话,实例属性的优先级最高
  • 3.静态方法不需要定义额外的参数,若是要引用属性的话 则可以通过类对象或者是实例对象去引用即可 必须用装饰器 @staticmethod来修饰

2.9多态

  • 多态:顾名思义就是多种状态、形态,就是同一种行为 对于不同的子类【对象】有不同的行为表现
  • 要想实现多态 必须的有两个前提需要遵守:
  • 1、继承:多态必须发生在父类和子类之间
  • 2、重写: 子类重写父类的方法
  • 多态有什么用: 增加程序的灵活性;增加程序的拓展性。
# 案例演示
class Animal:
    '''
    父类【基类】
    '''
    def say_who(self):
        print('我是一个动物....')
        pass
    pass
class Duck(Animal):
    '''
      鸭子类 【子类】 派生类
    '''
    def say_who(self):
        '''
        在这里重写父类的方法
        :return:
        '''
        print('我是一只漂亮的鸭子')
        pass
    pass
class Dog(Animal):
    '''
     小狗类 【子类】 派生类
    '''
    def say_who(self):
        print('我是一只哈巴狗')
        pass
    pass

class Cat(Animal):
    '''
        小猫类 【子类】 派生类
    '''
    def say_who(self):
        print('我是一只小花猫 喵喵喵喵')
        pass
    pass


class Bird(Animal):
    '''
    新增鸟类 无需修改原来的代码
    '''
    def say_who(self):
        print('我是一只黄鹂鸟')
    pass

class People:
    def say_who(self):
        print('我是人类')
    pass


class student(People):
    def say_who(self):
        print('我是一年级的学习 张明')
    pass

def commonInvoke(obj):
    '''
    统一调用的方法
    :param obj: 对象的实例
    :return:
    '''
    obj.say_who()

# duck1=Duck()
# duck1.say_who()
# dog1=Dog()
# dog1.say_who()
# cat1=Cat()
# cat1.say_who()

listObj=[Duck(), Dog(),Cat(),Bird(),student()]
for item in listObj:
    '''
     循环去调用函数
    '''
    commonInvoke(item)

2.10 三大特征(面向对象)

  • 在python中展现面向对象的三大特征:
  • 封装、继承、多态
  • 封装:指的是把内容封装到某个地方,便于后面的使用 他需要: 把内容封装到某个地方 从另外一个地方去调用被封装的内容 对于封装来说 其实就是使用初始化构造方法将内容封装到对象中,然后通过对象直接或者self来获取被封装的内容
  • 继承: 和现实生活当中的继承是一样的:也就是 子可以继承父的内容【属性和行为】(爸爸有的儿子都有,相反 儿子有的爸爸不一定有) 所以对于面向对象的继承来说 其实就是将多个类共有的方法提取到父类中 子类仅需继承父类而不必一一去实现 这样就可以极大的提高效率 减少代码的重复编写,精简代码的层级结构 便于拓展
class 类名(父类):
      '''
       子类就可以继承父类中公共的属性和方法
      '''
 	pass
  • 多态:顾名思义就是多种状态、形态,就是同一种行为 对于不同的子类【对象】有不同的行为表现 要想实现多态 必须的有两个前提需要遵守: 1、继承:多态必须发生在父类和子类之间 2、重写: 子类重写父类的方法

3.面向对象(下)

3.1私有化属性

  • 使用私有属性的场景
  • 1.把特定的一个属性隐藏起来 不想让类的外部进行直接调用
  • 2.我想保护这个属性 不想让属性的值随意的改变
  • 3.保护这个属性 不想让派生类【子类】去继承
class Person:
    __hobby='跳舞'  #私有的类属性
    def __init__(self):
        self.__name='李四' #加两个下划线 将此属性私有化之后  就不能再外部直接访问了,当然在类的内部是可以防蚊贴
        self.age=30
        pass
    def __str__(self):
        '''
        私有化的属性在内部可以使用 self.__name
        :return:
        '''
        return '{}的年龄是{} 爱好是{}'.format(self.__name,self.age,Person.__hobby)
    def  changeValue(self):
        Person.__hobby='唱歌'
class Student(Person):
    def printInfo(self):
        # print(self.__name)  #在此访问父类中的私有属性 可以吗?   不可以
        print(self.age)
    pass


stu=Student()
# print(stu.__name)
stu.printInfo()
stu.changeValue() #修改私有属性的值
print(stu)
# print(stu.__hobby) #实例对象访问类属性
# print(Person.__hobby) #实例对象访问类属性

# xl=Person()
# # print(xl.__name) #是通过类对象 在外部访问的 不能访问私有属性
# print(xl)

# 小结:
# 1 私有化的【实例】属性 不能再外部直接的访问  可以在类的内部随意的使用
# 2.子类不能继承父类的私有化属性【只能继承父类公共的属性和行为】
# 3. 在属性名的前面直接加‘ __’  就可以变为私有化了

3.2私有化方法

class Animal:
    def __eat(self):
        print('吃东西')
        pass
    def run(self):
        self.__eat() #在此调用私有化的方法
        print('飞快的跑')
    pass

class Bird(Animal):
    pass

b1=Bird()
# print(b1.eat())
# b1.eat()
b1.run()

3.3Property属性函数(意义不大)

  • 目的:不需要通过函数的形式,来访问私有属性
class Person(object):
    def __init__(self):
        self.__age = 18 # 定义一个私有化属性,属性名字前加连个 __ 下滑线
    # def get_age(self): # 访问私有实例属性
    #     return self.__age
    # def set_age(self,age): # 修改私有实例属性
    #     if age < 0:
    #         print('年龄不能小于0')
    #     else:
    #         self.__age=age
    #         pass
    #     pass
    # 定义一个类属性  实现通过直接访问属性的形式去访问私有的属性
    # age=property(get_age,set_age)
    # 实现方式2  通过装饰器的方式去声明
    @property  #用装饰器修饰 添加属性标志  提供一个getter方法
    def age(self):
        return self.__age
    @age.setter   #提供一个setter方法
    def age(self,parms):
        if parms < 0:
            print('年龄不能小于0')
        else:
            self.__age=parms
            pass
        pass


    pass
p1=Person()
print(p1.age)
p1.age=30
print(p1.age)
# p1.get_age()
# p1.set_age()

3.4__new__方法

class Animal:
    def __init__(self):
        self.color='红色'
        pass
    #在python当中, 如果不重写 __new__ 默认结构如下
    def __new__(cls, *args, **kwargs):
        return super().__new__(cls,*args, **kwargs)
        # return object.__new__(cls, *args, **kwargs)
    pass

tigger=Animal() #实例化的过程会自动调用__new__去创建实例
# 在新式类中 __new__  才是真正的实例化的方法,为类提供外壳制造出实例框架,然后调用该框架内的构造方法__init__ 进行丰满操作
# 比喻建房子 __new__   方法负责开发地皮 打地基 并将原料存放在工地,而__init__ 负责从工地取材料建造出地皮开发图纸规定的大楼,
# 负责细节设计、建造 最终完成

3.5单例模式

  • 单例模式 是一种常用的软件设计模式 目的:确保某一个类只有一个实例存在
  • 如果希望在真个系统中 某个类只能出现一个实例的时候,那么这个单例对象就满足要求
  • 创建一个单例对象 基于__new__去实现的【推荐的一种】
class DataBaseClass(object):
    def __new__(cls, *args, **kwargs):
        # cls._instance=cls.__new__(cls)  不能使用自身的new方法
            # 容易造成一个深度递归,应该调用父类的new方法
        if not hasattr(cls,'_instance'):  #如果不存在就开始创建
            cls._instance=super().__new__(cls,*args, **kwargs)
        return cls._instance
    pass

class DBoptSingle(DataBaseClass):
    pass

db1=DBoptSingle()
print(id(db1))
db2=DBoptSingle()
print(id(db2))
db3=DBoptSingle()
print(id(db3))