zoukankan      html  css  js  c++  java
  • 面向对象

    第四章 面向对象

    1.面向对象初识

    1.1 面向对象过程vs函数式编程vs面向对象编程
    s1 = 'fkjgkrsge'
    count = 1
    for i in s1:
    	count += 1 
    l1 = [1,2,3,4,5]
    
    def my_len(a):
    	count = 1
    		for i in a:
    	count += 1 
    提高了代码的可读性,减少了代码的重复性....
    上面统称为面向过程式编程.
    面向过程式编程:
    好处:出色的完成你之前布置的所有的需求.
    坏处:但凡更改或者增加一条需求,可能整个项目都随之改变.
    
    1.2面向对象的结构
    1. 类是相似功能的集合体.
    2. 类 你要站在上帝的角度去考虑问题.
    类: 具有相似功能和特性的一类事物.
    对象:类的具体体现.
    一定要有宏观的概念,区分类与对象.
    类的第二个优点: 你要站在 的角度去考虑,类一个公共模板,对象是从这个公共的模板产出的.
    结构上分析:
    Human 类名要具有描述性,类名首字母大写,类名不宜用_
    
    1.3从类名的角度使用类
    class Student:
        """
        此类是构建学生类
        """
        daily = '学习'
        examination = '考试'
        def work(self):
            print('每天要上课')
    
        def homework(self):
            print('家庭作业')
    

    1562294549262

    类名的角度调用类中的属性,

    1.查看类中的所有的内容.类名.__dict__只用于获取类中的全部.

    print(Student.__dict__)
    print(Student.__dict__['daily'])
    

    2.万能的 . 点

    class Student:
    	daily = '学习'
    	examination = '考试'
    	def work(self):
    		print('每天上课')
    	def homework(self):
    		print('家庭作业')
    print(Student.daily)#查
    Student.cloth = '校服'#增
    Student.examination = '不考试'#改
    del Student.daily #删
    print(Student.__dict__)
    

    一般类中的属性都是通过类名. 的方式 去操控的.

    类名的角度调用类中的方法.(一般类中的方法(除去类方法,静态方法外)不通过类名调用)

    Student.work(5565) # 工作中不用类名调用

    1562299522885

    1.4从对象的角度分析类
    class Student:
        """
        此类是构建学生类
        """
    
        daily = '学习'
        examination = '考试'
    
        def __init__(self,n,a,h):
            self.name = n
            self.age = a
            self.hobby = h
    
        def work(self,c):
            self.color = c
            print(f'{self.name}每天要上课')
    
        def homework(self):
            # 利用self 对象空间,为所欲为
            print('家庭作业')
    
    obj = Student()  # 类名() 过程就叫做实例化过程,实例化一个对象
    print(obj)  # 对象,实例
    obj1 = Student()
    print(obj1)
    obj = Student()
    print(obj)
    

    对象可以操作对象空间的属性 万能的点

    obj = Student('xiaohong',12,'运动')
    obj.age = '29'  # 增
    del obj.name  # 删
    obj.sex = '女'# 改
    print(obj.age)  # 查
    daming = Student('大明',21,'工作')
    Tom = Student('汤姆',12,'学习')
    对象查看全部属性
    print(obj.__dict__)
    {'age': '29', 'hobby': '运动', 'sex': '女'}
    

    对象查看类中的属性

    print(daming.daily)
    daming.daily = '活动'不会修改,只会在对象空间的属性中增加这样一个属性
    

    对象调用类中的方法

    liye = Student('小黑',21,'音乐')
    liye.work('红色')
    print(liye.__dict__)
    
    1.5实例化对象
    obj = Student()  # 类名() 过程就叫做实例化过程,实例化一个对象
    print(obj)  # 对象,实例
    实例化一个对象时发生了三件事:
    1. 在内存中创建一个对象空间.
    2. 自动执行__init__方法,并且将对象空间传给self参数.
    3. 执行__init__方法里面的代码,给对象空间封装其属性.
    
    1.6self

    self 就是类中方法的第一个位置参数, 如果通过对象执行此方法,解释器就自动的将此对象空间当做实参传给self.约定俗称: 类中的方法第一个参数一般都设置成self.

    1.7从空间角度研究类
    class A:
    
        address = '美丽富饶的沙河'
    
        def __init__(self, name):
            self.name = name
    
        def func(self):
            if self.name == 'aa':
                self.skins = '吉利服'
    
        def func1(self):
            print(self.__dict__)
            A.aaa = '易水寒'
    obj = A('aa')
    类外面可以给对象封装属性
    response = input('今天天气热不热')
    if  response == '热':
        obj.weapon = 'abc'
    print(obj.__dict__)
    >>>{'name': 'aa', 'weapon': 'abc'}
    类内部封装属性
    obj.func()
    print(obj.__dict__)
    >>>{'name': 'aa', 'skins': '吉利服'}
    obj = A('db')
    A.func1(111)
    A.func1(obj)把对象传到类的方法中
    print(A.__dict__)#类空间增加了一个静态属性
    
    class Person:
    
        mind = '有思想'
        language = '会使用语言'
    
        def __init__(self, name, age):
    
            self.name = name
            self.age = age
    
        def work(self):
            print('人类一般都需要工作')
    
    p1 = Person('dsb', 21)
    del p1.mind  # 报错,不能通过对象删除类的静态属性
    p1.mind = '无脑'# 对象空间增加了一个属性
    print(p1.mind)#无脑
    print(Person.mind)#有思想
    对象如果查询一个属性: 对象空间  ----> 类空间 ----> 父类空间  --->
    类查询一个属性: 类空间  ----> 父类空间  ---->
    单向不可逆
    对象与对象之间原则上互相独立(除去组合这种特殊的关系之外).
    
    1562553549390
    1.8类与类之间的关系

    1.依赖关系(主从关系)

    大象进冰箱
    方法一:将一个对象传给另一个类的的方法中:
    class Elephant:
    	def __init__(self,name):
    		self.name = name
    	def open(self,ref1):
    		print(f'{self.name}大象默念三声:芝麻开门')
    		ref1.open_door()
    	def close(self,ref2):
    		print(f'{self.name}大象默念三声:芝麻关门')
    		ref2.close_door()
    class Refrigerator:
    	def __init__(self,name):
    		self.name = name
    	def open_door(self):
    		print(f'{self.name}冰箱门被打开了')
    	def close_door(self):
    		print(f'{self.name}冰箱门被关上了')
    ele = Elephant('琪琪')
    re = Refrigerator('美菱')
    ele.open(re)
    ele.close(re)
    注:当传的是对象的时候,无需再ref1.open_door()括号中添加东西,调用这个方法,会自动将对象传给self.
    方法二:将一个类名传到另一个类的方法中:
    class Elephant:
    	def __init__(self,name):
    		self.name = name
    	def open(self,ref1):
    		print(f'{self.name}大象默念三声:芝麻开门')
    		ref1.open_door(re)
    	def close(self,ref2):
    		print(f'{self.name}大象默念三声:芝麻关门')
    		ref2.close_door(re)
    class Refrigerator:
    	def __init__(self,name):
    		self.name = name
    	def open_door(self):
    		print(f'{self.name}冰箱门被打开了')
    	def close_door(self):
    		print(f'{self.name}冰箱门被关上了')
    ele = Elephant('琪琪')
    re = Refrigerator('美菱')
    ele.open(Refrigerator)
    ele.close(Refrigerator)
    '''
    琪琪大象默念三声:芝麻开门
    美菱冰箱门被打开了
    琪琪大象默念三声:芝麻关门
    美菱冰箱门被关上了
    '''
    注:当传的是类名的时候,需再ref1.open_door()括号中添加东西,调用这个方法,需将对象re传给self.
    依赖关系: 将一个类的类名或者对象传给另一个类的方法中.
     实现两个:
    大象执行open方法:
    显示: '哪个大象  大象默念三声: 芝麻开门'
    显示: '哪个冰箱门 冰箱门被打开了....'
    关门的流程也需要完成.
    

    2.组合:(聚合,组合,关联)

    class Boy:
    
        def __init__(self, name):
            self.name = name
    
        def meet(self, girl_friend=None):
    
            self.girl_friend = girl_friend  # wu对象空间 : girl_friend : object对象
    
        def have_diner(self):  # self = wu这个对象空间
    
            if self.girl_friend:
                print(f'{self.name}请年龄为:{self.girl_friend.age},姓名为{self.girl_friend.name}一起吃六块钱的麻辣烫')
                self.girl_friend.shopping(self)  # (self = wu对象空间)
            else:
                print('单身狗,吃什么吃')
    class Girl:
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def shopping(self,boy_friend):
            print(f'{boy_friend.name},{self.name}一起去购物!')
    
    wu = Boy('吴超')
    flower = Girl('如花', 28)
    wu.meet(flower)
    wu.have_dinner()
    >>>
    吴超请年龄为:28,姓名为如花一起吃六块钱的麻辣烫
    吴超,如花一起去购物!
    组合: 将一个类的对象封装成另一个类的对象的属性.
    
    

    1562592912562

    上面例题的难点:
    一个类的方法只能有此类的对象去调用.
    一个类的方法的第一个self只接受此类的对象.

    3.模拟英雄联盟写一个游戏人物的类(升级题).

    要求:
    1. 创建一个 Game_role的类.
    2. 构造方法中给对象封装name,ad(攻击力),hp(血量).三个属性.
    3. 创建一个attack方法,此方法是实例化两个对象,互相攻击的功能:
           例: 实例化一个对象 盖伦,ad为10, hp为100
           实例化另个一个对象 剑豪 ad为20, hp为80
           盖伦通过attack方法攻击剑豪,此方法要完成 '谁攻击谁,谁掉了多少血,  还剩多少血'的提示功能.
    
    

    方法一:

    class GameRole:
    	def __init__(self,n,ad,hp):
    		self.name = n
    		self.ad = ad
    		self.hp = hp
    	def attack(self,p1):
    		p1.hp = p1.hp - self.ad
    		print(f'{self.name}攻击了{p1.name},{p1.name}掉了{self.ad}血,还剩{p1.hp}血')
    gailun = GameRole('草丛伦', 10, 100)
    jianhao = GameRole('风男', 20, 80)
    gailun.attack(jianhao)
    gailun.attack(jianhao)
    返回结果:
    草丛伦攻击了风男,风男掉了10血,还剩70血
    草丛伦攻击了风男,风男掉了10血,还剩60血
    
    

    方法二:

    class GameRole:
    	def __init__(self,n,ad,hp):
    		self.name = n
    		self.ad = ad
    		self.hp = hp
    	def equit_weapon(self,wea):
    		self.weapon = wea
    class Weapon:
    	def __init__(self,name,ad):
    		self.name = name
    		self.ad = ad
    	def weapon_attack(self,p1,p2):
    		p2.hp = p2.hp - self.ad
    		if p2.hp >= 0:
    			print(f'{p1.name}利用{self.name}攻击了{p2.name},{p2.name}还剩{p2.hp}血')
    		else:
    			print('%s已死'%p2.name)
    gailun = GameRole('盖伦',10,100)
    zhaoxin = GameRole('赵信',20,90)
    great_sword = Weapon('大宝剑',30)
    spear = Weapon('红缨枪',50)
    gailun.equit_weapon(spear)#依赖关系
    gailun.weapon.weapon_attack(gailun,zhaoxin)# gailun.weapon == spear
    gailun.weapon.weapon_attack(gailun,zhaoxin)
    返回结果:
    盖伦利用红缨枪攻击了赵信,赵信还剩40血
    赵信已死
    
    

    2.三大特性之继承(单,多继承)

    1. 什么是继承?

      • 专业角度: B 继承 A类, B就叫做A的子类,派生类, A叫做B的父类,基类,超类. B类以及B类的对象使用A类的所有的属性以及方法.
      • 字面意思: 继承就是继承父母所有的资产.
      • 单继承,多继承.
      • 如果多各类中有相同的方法,为了避免重复编写,可以将其放在父类中(基类)中
    2. 继承的优点:

      1. 节省代码.
      2. 增强的耦合性.
      3. 代码规范化.

      继承分为单继承与多继承.
      Person Dog Cat : 子类,派生类
      Animal: 父类, 基类, 超类
      单继承: 使用.
      多继承:有区别.

    2.1从类名执行父类的属性。
    class Animal(object):
    
        live = '有生命的'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def eat(self):
            print(f'self----> {self}')
            print('动物都需要进食')
    
    
    class Person(Animal):
        pass
    print(Person.__dict__)
    print(Person.live)
    Person.eat(55)
    返回结果:
    {'__module__': '__main__', '__doc__': None}
    有生命的
    self----> 55
    动物都需要进食
    
    

    1562673399366

    2.2从对象执行父类的一切。

    实例化对象一定一定会执行三件事. 一定会执行__init__

    class Animal(object):
    
        live = '有生命的'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def eat(self):
            print(f'self----> {self}')
            print('动物都需要进食')
    
    
    class Person(Animal):
        pass
    p1 = Person('dsb', 21, 'laddy_boy')
    print(p1.__dict__)
    print(p1.live)
    p1.eat()
    print(f'p1--->{p1}')
    返回结果:
    {'name': 'dsb', 'age': 21, 'sex': 'laddy_boy'}
    有生命的
    self----> <__main__.Person object at 0x0000006797AB8A20>
    动物都需要进食
    p1--->    <__main__.Person object at 0x0000006797AB8A20>
    
    

    注意: 子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改).

    class Animal(object):
    
        live = '有生命的'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def eat(self):
            print(f'self----> {self}')
            print('动物都需要进食')
    
    
    class Person(Animal):
    
        def eat(self):
            print('人类需要进食')
    
    
    
    p1 = Person('dsb', 21, 'laddy_boy')
    # 子类将父类的方法覆盖了,(重写父类的方法)
    p1.eat = '李业'
    print(p1.__dict__)
    p1.eat()  # 对象查找顺序先从对象空间找名字, 子类找名字, 父类找名字.会直接报错
    
    
    2.3同时执行父类方法和执行子类方法
    class Animal:
        def __init__(self,n,a,s):
            self.name = n
            self.age = a
            self.sex = s
        def eat(self):
            print(f'self------->{self}')
            print('动物需要进食')
    class Person(Animal):
        def __init__(self,name,age,sex,hobby):
            # 方法一:
            Animal.__init__(self,name,age,sex)
            # 方法二:
            # super(Person, self).__init__(name,age,sex)
            super().__init__(name,age,sex) # 和上面的一样,默认不写,已经传了Person,self
            self.hobby = hobby
    
        def eat(self):
            print('人类需要进食')
            super().eat()
    p1 = Person('小红',12,'女','唱歌')
    print(p1.__dict__)
    print(f'p1--------->{p1}')
    p1.eat()
    返回结果:
    {'name': '小红', 'age': 12, 'sex': '女', 'hobby': '唱歌'}
    p1---------><__main__.Person object at 0x0000007F50BB1B38>
    人类需要进食
    self-------><__main__.Person object at 0x0000007F50BB1B38>
    动物需要进食
    
    

    习题

    class Base:
    
        def __init__(self, num):
            self.num = num
    
        def func1(self):
            print(self.num)
    
    class Foo(Base):
        pass
    
    obj = Foo(123)
    obj.func1()
    返回结果:123
    class Base:
        def __init__(self, num):
            self.num = num
    
        def func1(self):
            print(self.num)
    
    class Foo(Base):
    
        def func1(self):
            print("Foo. func1", self.num)
    
    obj = Foo(123)
    obj.func1()
    返回结果:Foo. func1 123
    
    class Base:
        def __init__(self, num):  # 2
            self.num = num
    
        def func1(self):  # 4
            print(self.num)  # 123
            self.func2()  # self ---> obj  # 对象查询顺序:
    
        def func2(self):
            print("Base.func2")
    
    class Foo(Base):
        def func2(self):
            print("Foo.func2")
    
    obj = Foo(123)  # 1
    obj.func1() # 3
    返回结果:
    123
    Foo.func2
    class Base:
        def __init__(self, num):
            self.num = num
        def func1(self):
    
            print(self.num)
            self.func2()
    
        def func2(self):
            print(111, self.num)
    
    class Foo(Base):
    
        def func2(self):
            print(222, self.num)
    
    lst = [Base(1), Base(2), Foo(3)]
    
    for obj in lst:
        obj.func2()
    返回结果:
    111,1
    222,2
    333,3
    class Base:
    
        def __init__(self, num):
            self.num = num
    
        def func1(self):
            print(self.num)
            self.func2()
    
        def func2(self):
            print(111, self.num)
    
    
    class Foo(Base):
    
        def func2(self):
            print(222, self.num)
    
    
    lst = [Base(1), Base(2), Foo(3)]
    for obj in lst:
        obj.func1()
    返回结果:
    1
    111 1
    2
    111 2
    3
    222 3
    
    
    2.4多继承

    面向对象:

    python2.2之前:都是经典类。

    python2.2直至python2.7之间存在两种类型: 经典类,新式类.

    经典类: 基类不继承object类,查询规则:深度优先的原则.

    新式类: 基类继承object类,python3x 只有新式类.查询规则: mro算法.

    经典类:Foo-> H -> G -> F -> E -> D -> B -> A -> C.深度优先
    img
    python2x
    class A:  # 经典类
        pass
    
    class B(object):  # 新式类
        pass
    
    
    python3x:(默认继承object)
    class C: # 新式类
        pass
    
    
    class O:
        pass
    
    class D(O):
        pass
    
    class E(O):
        pass
    
    class F(O):
        pass
    
    class B(D,E):
        pass
    
    class C(E,F):
        pass
    
    class A(B,C):
        pass
    
    # 工作中用mro()方法研究新式类的继承顺序
    print(A.mro())
    返回结果:
    [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.F'>, <class '__main__.O'>, <class 'object'>]
    mro算法  面试中有可能会遇到
    
    
    2.5c3算法
    mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
    mro(Foo(H,G)) = [Foo] + merge(mro(H), mro(G),[H,G])
    
    表头:
      列表的第一个元素
    
    表尾:
      列表中表头以外的元素集合(可以为空)
    表头,表尾
    [A,B,C] : 表头: A 表尾: [B,C]
    [A] : 表头: A 表尾: []
    mro(A) = mro(A(B,C))
           = [A] + merge(mro(B), mro(C), [B,C])
    
    mro(B) = mro(B(D,E))
           = [B] + merge(mro(D), mro(E), [D,E])
           = [B] + merge([D,O], [E,O], [D,E])
           = [B,D] + merge([O], [E,O], [E])
           = [B,D,E,O]
           
    mro(C) = mro(C(E,F))
           = [C] + merge(mro(E), mro(F),[E,F])
           = [C] + merge([E,O],[F,O],[E,F])
           = [C,E] + merge([O],[F,O],[F])
           = [C,E,F,O]
    
    mro(A) = mro(A(B,C))
           = [A] + merge([B,D,E,O], [C,E,F,O], [B,C])
           = [A,B] + merge([D,E,O], [C,E,F,O], [C])
           = [A,B,D] + merge([E,O], [C,E,F,O], [C])
           = [A,B,D,C] + merge([E,O], [E,F,O])
           = [A,B,D,C,E] + merge([O], [F,O])
           = [A,B,D,C,E,F,O]
    
    
    

    3.三大特性封装多态(鸭子类型)

    3.1多态,封装

    ​ 1.方法封装到类中.

    ​ 2.数据封装到对象中.

    ​ 封装:将一些东西内容封装到一个地方,你还可以取出来.

    ​ 类设置静态属性,设置一些方法,

    ​ 对象.对象可以在其对象空间中封装一些属性.

    ​ 多态: 一个事物产生多种形态. 水: 气态液态固态.

    ​ python中 默认支持多态.

    ​ python中 定义变量不用规定变量的类型

    3.2鸭子类型
    class A:
    
        def login(self):
            pass
    
        def register(self):
            pass
    
    
    class B:
    
        def login(self):
            pass
    
        def register(self):
            pass
    
    

    A,B两个类,没有任何关系,独立两个,但是里面的功能相似,所以python一般会将类似于A,B两个类

    里面的相似功能让其命名相同

    1.A,B虽然无关系,但是很默契的制定了一个规范,让你使用起来更方便.

    3.3super()
    1.
    class A:
        def f1(self):
            print('in A f1')
    
        def f2(self):
            print('in A f2')
    
    
    class Foo(A):
        def f1(self):
            # super().f2()
            super(Foo, self).f2()
            print('in A Foo')
    
    
    obj = Foo()
    obj.f1()
    '''
    in A f2
    in A Foo
    '''
    2.
    class A:
        def f1(self):
            print('in A')
    
    class Foo(A):
        def f1(self):
            super(Foo,self).f1()
            print('in Foo')  # 2
    
    class Bar(A):
        def f1(self):
            print('in Bar')  # 1
    
    class Info(Foo,Bar):
    
        def f1(self):
            super(Info,self).f1()
            print('in Info f1')  # 3
    
    obj = Info()
    print(Info.mro())  # [Info, Foo, Bar, A]
    obj.f1()
    '''
    [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]
    in Bar
    in Foo
    in Info f1
    '''
    super() 严格意义并不是执行父类的方法.
    单继承: super() 肯定是执行父类的方法.
    多继承: super(S,self) 严格按照self从属于的类的mro的执行顺序,执行 S类的下一位.
    
    
    class A:
        def f1(self):
            print('in A')
    
    class Foo(A):
    
        def f1(self):
            super().f1()
            print('in Foo')
    
    class Bar(A):
    
        def f1(self):  # self = obj
            print('in Bar')
    
    class Info(Foo,Bar):
    
        def f1(self):  # self = obj
            super(Foo,self).f1()
            print('in Info f1')
    
    obj = Info()  # [Info, Foo, Bar, A]
    obj.f1()
    多继承: super(S,self) 严格按照self从属于的类的mro的执行顺序,执行 S类的下一位.
    
    

    super补充

    特别注意:super().__init__会给对象封装新的属性,直接将原有的实例化对象中的name,a值覆盖掉.

    class A:
    	def __init__(self):
    		self.name = 'Myclass'
    		self.a    = 3 
    class B(A):
    	def __init__(self,name,a):
    		self.name = name 
    		self.a = a
    		super().__init__()
    	def run(self):
    		print(self.name)
    b = B('xiaohong',1)
    print(b.__dict__)
    b.run()
    输出结果:
    {'name': 'Myclass', 'a': 3}
    Myclsoas
    		
    
    

    继承父类的方法中没有封装此属性,则不会覆盖.

    class A:
    	def __init__(self):
    		self.a    = 3
    	def rer(self):
    		self.name = 'Myclass'
    class B(A):
    	def __init__(self,name,a):
    		self.name = name
    		self.a = a
    		super().__init__()
    	def run(self):
    		print(self.name)
    b = B('xiaohong',1)
    print(b.__dict__)
    b.run()
    返回结果:
    {'name': 'xiaohong', 'a': 3}
    xiaohong
    
    
    
    3.4类的约束
    class QQpay:
    
        def pay(self, money):
            print(f'利用qq支付了{money}')
    
    
    class Alipay:
    
        def pay(self, money):
            print(f'利用支付宝支付了{money}')
    
    
    支付功能 规划一下
    
    def pay(obj,money):  # 归一化设计
        obj.pay(money)
    
    obj1 = QQpay()
    obj2 = Alipay()
    
    pay(obj1,100)
    pay(obj2,200)
    
    

    在上面的情况下(在一些重要的逻辑,与用户数据相关等核心部分),我们要建立一种约束,避免发生此类错误.类的约束有两种解决方式:1. 在父类建立一种约束.2. 模拟抽象类(指定一种规范)的概念,建立一种约束.

    第一种解决方式:
    
    class Payment:
    
        def pay(self,money):  # 约定俗称定义一种规范,子类要定义pay方法.
            raise Exception('子类必须定义此方法')
    
    
    class QQpay(Payment):
    
        def pay(self, money):
            print(f'利用qq支付了{money}')
    
    
    class Alipay(Payment):
    
        def pay(self, money):
            print(f'利用支付宝支付了{money}')
    
    class Wechatpay(Payment):
        def pay(self,money):
            print(f'利用微信支付了{money}')
    
    class Wechatpay(Payment):
        def fuqian(self,money):
            print(f'利用微信支付了{money}')
    
    支付功能 规划一下
    
    def pay(obj,money,choice):  # 归一化设计
    
        obj.pay(money)
        
    obj3 = Wechatpay()
    pay(obj3,300)
    obj3.fuqian(300)
    print(11)
        raise Exception('子类必须定义此方法')
    Exception: 子类必须定义此方法
    第一种约束:在父类定义一个pay方法,主动抛出异常,如果子类没有定义pay方法,并且沿用了父类的pay方法
    即会报错. python推荐的一种约束方式.
    
    
    第二种:
    from abc import ABCMeta,abstractmethod
    
    class Payment(metaclass=ABCMeta):
                # 抽象类 接口类  规范和约束  metaclass指定的是一个元类
        @abstractmethod
        def pay(self, money):
            pass  # 抽象方法
    
    
    class QQpay(Payment):
    
        def pay(self, money):
            print(f'利用qq支付了{money}')
    
    
    class Alipay(Payment):
    
        def pay(self, money):
            print(f'利用支付宝支付了{money}')
    
    class Wechatpay(Payment):
        def fuqian(self,money):
            print(f'利用微信支付了{money}')
    
        # def pay(self,money):
        #     pass
    
    
    obj3 = Wechatpay()
    TypeError: Can't instantiate abstract class Wechatpay with abstract methods pay
    利用抽象类的概念: 基类如上设置,子类如果没有定义pay方法,在实例化对象时就会报错.
    
    

    4.类的私有成员

    1. 对于类的公有静态属性,类的外部,类的内部,派生类都可以访问.
    class B:
    	school_name = '老男孩教育'
    class A(B):
    	class_name = 'python23'
    	def func(self):
    		print(self.class_name)
    obj = A()
    print(obj.class_name)
    obj.func()
    print(obj.school_name)
    '''
    python23
    python23
    老男孩教育
    '''
    
    
    1. 私有静态属性:类外部,派生类不能访问,类内部可以访问
    class B:
    	school_name = '老男孩教育'
    	__consc_edu = '良心教育'
    class A(B):
    	class_name = 'python23'
    	__girlnum = '1个'
    	def func(self):
    		print(self.class_name)
    		print(self.__girlnum)  # 可以访问
    		print(self.__consc_edu)# 派生类不可访问
    obj = A()
    # 私有静态属性:类外部不能访问
    print(obj.__girlnum) #不能访问
    print(A.__girlnum)   #不能访问
    # 私有静态属性:类内部可以访问
    obj.func()#派生类不可以访问
    
    
    1. 对象的私有属性
    class B:
    	school_name = '老男孩教育'
    	__consc_edu = '教育'
    	def __init__(self,weight):
    		self.__weight = weight
    class A(B):
    	def __init__(self,name,age,weight):
    		super().__init__(weight)
    		self.name = name
    		self.__age = age
    	def func(self):
    		print(self.__age) #类的内部可以使用
    		# print(self.__weight) #派生类中也不可以访问
    obj = A('张强',18,180)
    # print(obj.__age)#类的外部不能访问
    obj.func()
    
    
    1. 私有方法
    class B:
    	def __func(self):
    		print('B的类内部可以访问')
    	def func3(self):
    		self.__func()
    class A(B):
    	def __func1(self):
    		print('类外部不可以访问')
    	def func(self):
    		self.__func1()
    		super().func3()
    		super(A, self).func3()
    obj = A()
    obj.func()
    '''
    类外部不可以访问
    B的类内部可以访问
    B的类内部可以访问
    '''
    
    
    • 如果想设定一些私有的或者是不想让类外面用到,密码,加密方式,等设置成私有成员.
    • 拓展: 私有成员除了在类内部,当真访问不到么?
    class A:
    	__girlnum = '1个'
    print(A.__dict__)
    {'__module__': '__main__', '_A__girlnum': '1个', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
    python中所有的私有成员: 就是在私有成员前面加上 _类名而已.
    print(A._A__girlnum)#在前面加上_就可以访问,千万不要这么去访问!!!
    print(A.__dict__['_A__girlnum'])# 和上面的一样的
    
    

    5.类方法与静态方法

    5.1.类方法:
    class A:
    	num = 1
    	def func(self):
    		print('实例方法')
    	@classmethod #类方法:由类名直接调用的方法,他会自动的将类名传给cls
    	def a_func(cls):
    		print(cls.num)
    		'''
    		类内部可以实例化
    		obj1 = cls()
    		print(obj1)
    		
    		'''
    		print(cls)
    obj = A()
    A.a_func()
    print(A)
    obj.a_func() #对象也可以调用类方法,但是会自动将其从属于的类名传给cls
    '''
    1
    <class '__main__.A'>
    <class '__main__.A'>	
    '''
    
    

    定义一个Student类,我要统计学生的个数.

    class Student:
    	num = 0
    	def __init__(self,name):
    		self.name = name
    		self.count()
    	@classmethod
    	def count(cls):
    		cls.num += 1
    	@classmethod
    	def get_num(cls):
    		return cls.num
    obj = Student('xi')
    obj1 = Student('xi')
    obj2 = Student('xi')
    obj3 = Student('xi')
    obj4 = Student('xi')
    print(Student.get_num())
    
    
    5.2静态方法:

    不依赖于类,也不依赖于对象,他就是一个普通的函数放置于类中是结构更加清晰与合理.

    class A:
    	def func(self):
    		print(111)
    	@classmethod
    	def a_func(cls):
    		print(cls)
    	@staticmethod
    	def static_func(a,b,c):
    		print(f'{a},{b},{c}静态方法')
    # def static_func(a,b,c):
    # 	print(f'{a},{b},{c}静态方法')
    A.static_func(2,3,4)
    obj = A()
    obj.static_func(1,2,3)
    2,3,4静态方法
    1,2,3静态方法
    
    
    import time
    class TimeTest(object):
    	def __int__(self,hour,minute,second):
    		self.hour = hour
    		self.minute = minute
    		self.second = second
    
    	def get_year(self):
    		pass
    
    	def get_day(self):
    		pass
    
    	def last_year(self):
    		pass
    	@staticmethod
    	def showTime():
    		return time.strftime('%H:%M:%S',time.localtime())
    print(TimeTest.showTime())
    obj = TimeTest(1,20,60)
    obj.showTime()
    
    

    6.属性

    bmi值测试人体体脂:
    
    class Bmi:
    
        def __init__(self, name, weight, height):
    
            self.name = name
            self.weight = weight
            self.height = height
    
        def bmi(self):
            return self.weight / self.height**2
    
    tb = Bmi('太白',80, 1.75)
    print(tb.bmi())
    
    
    

    我们要让bmi方法伪装成属性,虽然在代码级别没有提升,但是看起来更合理.

    class Bmi:
    	def __init__(self,name,weight,height):
    		self.name = name
    		self.weight = weight
    		self.height = height
    	@property
    	def bmi(self):
    		return self.weight / self.height**2
    xw = Bmi('小王',60,1.72)
    print(xw.bmi)# 伪装属性时,不用在函数名后面加()了
    print(xw.weight)
    
    
    6.1property setter deleter
    class Foo:
        def __init__(self,name):
            self.name = name
        @property
        def	aaa(self):
            print('get的时候运行我啊')
        @aaa.setter
        def aaa(self,v):
            print('修改的时候运行我啊')
        @aaa.deleter
        def aaa(self):
            print('删除的时执行我')
    obj = Foo('alex')
    obj.aaa
    obj.aaa = 'taibai'
    del obj.aaa
    返回结果:
    get的时候运行我啊
    修改的时候运行我啊
    删除的时执行我
    
    
    6.2设置属性的另外一种写法:
    class Foo:
    
        def get_AAA(self):
            print('get的时候运行我啊')
    
        def set_AAA(self,value):
            print('set的时候运行我啊')
    
        def delete_AAA(self):
            print('delete的时候运行我啊')
    
        bbb = property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应
    
    
    f = Foo()
    f.bbb
    f.bbb = 'aaa'
    del f.bbb
    '''
    get的时候运行我啊
    set的时候运行我啊
    delete的时候运行我啊
    '''
    
    

    7.isinstance,issubclass

    1. isinstance
    class A:
    	pass
    class B(A):
    	pass
    class C(B):
    	pass
    obj = B()
    print(isinstance(obj,B))
    print(isinstance(obj,A))
    print(isinstance(obj,C))
    True
    True
    False
    
    
    • 对象与类之间的关系
      isinstance(obj,N): 判断 obj对象 是由N类(N的派生类)实例化的对象 返回 True.
      print(isinstance(obj, A))

    2.issubclass

    class A:
        pass
    
    class B(A):
        pass
    
    class C(B):
        pass
    类与类之间的关系
    issubclass(M,N) 判断是M类是N类的子孙.
    print(issubclass(C, B))
    print(issubclass(C, A))
    
    

    7.type元类

    from collections import Iterable
    from collections import Iterator
    
    s1 = 'seewfsdkfl'  # class str(Iterable)   Iterable
    l1 = [1, 2, 3]
    print(type(s1)) # 判断的是对象从属于哪个类
    print(type(l1))
    print("__iter__" in dir(s1))
    print(isinstance(s1, Iterable))
    
    
    • type 到底是什么?
    • type 元类 python中一切皆对象 , 一个类也是一个对象.么这个(类)对象肯定是由类实例化出来的.python中你创建的所有类,以及大部分list str等等这些类,都是从type元类实例化得来的.
    • python中继承object类都是新式类.object 也是由type元类实例化得来的.type

    8.异常处理

    1. 什么叫异常?
      • 你的程序出现中断,飘红,致使你的整个项目中断了.

    9.函数vs方法

    9.1通过函数名可以大致判断
    def func():
    	pass
    class A:
    	def func(self):
    		pass
    print(func)#<function func at 0x00000000005D1EA0>
    obj = A()
    print(obj.func) # <bound method A.func of <__main__.A object at 0x0000000001DE1CF8>>
    
    
    9.2通过types模块去验证
    from types import FunctionType
    from types import MethodType
    
    
    def func():
        pass
    
    
    class A:
    
        def func(self):
            pass
    
        @staticmethod
        def f():
            pass
    print(isinstance(func,FunctionType))# True
    print(isinstance(func,MethodType))# False
    类名调用func 就是一个函数
    print(isinstance(A.func, FunctionType))
    print(isinstance(A.func, MethodType))
    obj = A()
    对象调用func 就是一个方法
    print(isinstance(obj.func, FunctionType))
    print(isinstance(obj.func, MethodType))
    对于静态方法的研究,是一个函数
    print(isinstance(A.f,FunctionType))
    print(isinstance(A.f,MethodType))
    obj = A()
    对象调用func,也是一个函数
    print(isinstance(obj.f,FunctionType))
    print(isinstance(obj.f,MethodType))
    
    
    9.3函数与方法
    • 函数:全部都是显性传参
    • 方法:存在隐性传参

    10.反射

    ​ 通过字符串去操作一个对象
    字符串:字符串类型
    对象:实例,类,当前文件(模块),其他模块.

    10.1从实例的角度去研究反射
    class A:
    	static_field = '静态属性'
    	
    	def __init__(self,name,age):
    		self.name = name 
    		self.age = age
    	def func(self):
    		print('in A func')
    obj = A('小王',18)
    print(obj.name)
    print(obj.__dict__)
    print(hasattr(obj,'name')) #True
    print(hasattr(obj,'name1'))#False
    print(getattr(obj,'name')) #小王
    print(getattr(obj,'name1',None)) #None
    setattr(obj,'hobby','玩')#增加了一个属性
    print(getattr(obj,'hobby'))
    delattr(obj,'name') 删除
    print(hasattr(obj,'name'))False
    if hasattr(obj,'static_field'):
    	print(getattr(obj,'static_field'))#静态属性
    if hasattr(obj,'func'): #字符串操作.
    	print(getattr(obj,'func')) # 得到一个方法
    	getattr(obj,'func')() #可以执行函数.
    
    
    10.2从类的角度研究反射
    class A:
    	static_field = '静态属性'
    	
    	def __init__(self,name,age):
    		self.name = name 
    		self.age = age
    	def func(self):
    		print('in A func')
    obj = A('小张',18)
    print(hasattr(A, 'static_field'))
    print(getattr(A, 'static_field'))
    print(getattr(A, 'func'))  # <function A.func at 0x0000003423EDFEA0>
    getattr(A, 'func')(obj)
    返回结果:
    True
    静态属性
    <function A.func at 0x0000009C6A2732F0>
    in A func
    
    
    10.3从当前脚本研究反射.
    class B:
    	static = 'B类'
    	
    import sys
    
    # print(sys.modules)
    this_modules = sys.modules[__name__]
    cls = getattr(this_modules, 'B')
    print(cls)#<class '__main__.B'>
    obj = cls()
    print(obj.static)#B类
    2.
    def func1():
    	print('in func1')
    def func2():
    	print('in func2')
    def func3():
    	print('in func3')
    l1 = [func1,func2,func3]
    l1 = [f'func{i}'for i in range(1,4)]
    for i in l1:
    	getattr(this_modules,i)()
    '''
    in func1
    in func2
    in func3
    '''
    
    
    other_modules
    def test():
    	print('in test')	
    在其它模块研究反射
    import other_modules as om 
    om.test()
    getattr(om,'test')() 也可以执行
    
    
    class Auth:
    
    	function_list = [('login','请登录'), ('register','请注册'), ('exit', '退出')]
    
    	def login(self):
    		print('登录函数')
    
    
    	def register(self):
    		print('注册函数')
    
    
    	def exit(self):
    		print('退出...')
    
    
    while 1:
    	obj = Auth()
    	for num,option in enumerate(Auth.function_list,1):
    		print(num,option[1])
    	choice_num = input('请选择:').strip()
    	if hasattr(obj,Auth.function_list[int(choice_num)-1][0]):
    		getattr(obj,Auth.function_list[int(choice_num)-1][0])()
    
    

    11.python中特殊的双下方法

    11.1__len__
    class A:
    
        def __init__(self,name,age,hobby):
    
            self.name = name
            self.age = age
            self.hobby = hobby
            # print(111)
    
        def __len__(self):
            # print('触发__len__方法')
            return len(self.__dict__)
    obj = A('亚伟',1,2)
    ret = len(obj)#触发__len__
    print(ret)>>>3
    一个对象之所以可以使用len()函数,根本原因是这个对象从输入的类中有__len__方法,
    
    
    11.2__hash__
    class A:
    
        pass
    
    hash(obj) 会调用obj这个对象的类(基类)的__hash__方法
    obj = A()
    print(hash(obj))#53552261170
    
    
    11.3 __str__ , __repr__***
    class Student:
    
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
            
        def __str__(self):
            return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}123'
    
    obj = Student('小智', 18, '男')
    obj1 = Student('dj智', 18, '男')
    obj2 = Student('mc智', 18, '男')
    #
    print(str(obj))
    print(str(obj))  # 会触发__str__
    print(obj)  # 打印输出实例会触发__str__
    print('此对象为%s' %obj)  # 格式化输出会触发__str__
    '''
    姓名:小智年龄:18性别:男123
    姓名:小智年龄:18性别:男123
    姓名:小智年龄:18性别:男123
    此对象为姓名:小智年龄:18性别:男123
    '''
    
    
    class Student:
    
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
            
        def __repr__(self):
            return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}'
    
    obj = Student('小智', 18, '男')
    obj1 = Student('dj智', 18, '男')
    obj2 = Student('mc智', 18, '男')
    print(obj)  # 触发__repr__
    print('此对象是%r' %obj)  # 触发__repr__
    '''
    姓名:小智年龄:18性别:男
    此对象是姓名:小智年龄:18性别:男
    '''
    
    

    两者合一

    class Student:
    
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    
        def __repr__(self):
            return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}'
    
        def __str__(self):
            return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}123'
    
    obj = Student('小智', 18, '男')
    obj1 = Student('dj智', 18, '男')
    print(obj) 先触发__str__方法
    '''
    姓名:小智年龄:18性别:男123
    '''
    
    
    11.4__call__
    class A:
        def __init__(self):
            self.a = 1
            print(111)
    
        def __call__(self, *args, **kwargs):
            print('触发__call__')
    
    obj = A()触发__init__
    obj()触发__call__
    '''
    111
    触发__call__
    '''
    
    
    11.5__eq__
    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __eq__(self,obj):
            print(111)
            return True
            if  self.a == obj.a and self.b == obj.b:
                return True
    a = A()
    b = A()
    print(a == b)  # 对一个类的两个对象进行比较操作,就会触发__eq__方法
    '''
    111
    True
    '''
    
    

    11.6 __del__

    __del__ 析构方法
    class A:
    
        def __del__(self):
            print(111)
    
    obj = A()
    '''
    111
    '''
    
    
    11.7__new__
     __new__ 构造方法
    __new__创造并返回一个新对象.
    
    
    class A(object):
    
        def __init__(self):
            print('in __init__')
    
        def __new__(cls, *args, **kwargs):
            # print(cls)  cls == A
            print('in __new__')
            object1 = object.__new__(cls)
            return object1
    obj = A()
    类名() 先触发__new__ 并且将类名自动传给cls.
    print(obj)
    
    

    1562985912465

    11.8单例模式

    一个类只能实例化一个对象,无论你实例化多少次,内存中都只有一个对象.

    class A:
    	__instance = None
    	def __new__(cls, *args, **kwargs):
    		if not cls.__instance:
    			object1 = object.__new__(cls)
    			cls.__instance = object1
    		return cls.__instance
    obj = A()
    obj1 = A()
    obj2 = A()
    print(obj,obj1,obj2)
    
    
    11.9 __item__
    对对象进行类似于字典的操作
    
    class Foo:
        def __init__(self, name):
            self.name = name
    
        def __getitem__(self, item):
            print(item)
            print('get时 执行我')
    
        def __setitem__(self, key, value):
            self.name = value
            print('set时执行我')
    
        def __delitem__(self, key):
            print(f'del obj{[key]}时,我执行')
    
    obj = Foo('御姐')
    # obj.__dict__
    # obj['name']
    # obj['name'] = '萝莉'
    # print(obj.name)
    del obj['name']
    
    
    11.10 __enter__ __exit__
    __enter__ __exit__
    
    class A:
        def __init__(self,name):
            self.name = name
    
        def __enter__(self):
            print(111)
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print(222)
    
    # obj = A('mc小龙')
    
    # 对一个对象类似于进行with语句上下文管理的操作, 必须要在类中定义__enter__ __exit__
    with A('mc小龙') as obj:
        print(555)
    # print(obj.name)
    
    
    class A:
    
        def __init__(self, text):
            self.text = text
    
        def __enter__(self):  # 开启上下文管理器对象时触发此方法
            self.text = self.text + '您来啦'
            return self  # 将实例化的对象返回f1
    
        def __exit__(self, exc_type, exc_val, exc_tb):  # 执行完上下文管理器对象f1时触发此方法
            self.text = self.text + '这就走啦'
    
    # f1 = A('大爷')
    with A('大爷') as f1:
        print(f1.text)
    print(f1.text)
    
    
  • 相关阅读:
    主成分分析法(PCA)答疑
    搜索引擎的高级用法
    Makefile 编写实例
    GCC常用命令
    一个进程最多能开多少个线程?
    归并排序
    选择排序(数组、链表)
    求连续子数组的最大和
    生产者-消费者问题(1)
    基于cmake编译安装MySQL-5.5
  • 原文地址:https://www.cnblogs.com/pythonblogs/p/11253076.html
Copyright © 2011-2022 走看看