python-面向对象(3)

1 类的内置函数

  • issubclass(子类,基类):检测一个类是否是另一个类的子类

  • isinstance(实例,类):检测一个对象是否是一个类的实例

  • hasattr(ins, 'attr'):检测一个对象是否有成员xxx

  • getattr(ins, 'attr',default=None):获取对象的属性

    class A():
    name = 'cc'
    def func(self):
    return 'hello world'
    getattr(A(), func)()

  • setattr(ins, 'attr', value): 设置对象属性

  • delattr(ins, 'attr'): 删除对象属性

  • 案例

    class Person():
    def init(self, name, age, color):
    self.name = name
    self.age = age
    self.color = color

    def say(self):
    print('hello world')

    print(issubclass(Person, object))
    p = Person('chenpingan', 18, 'yellow')
    print(isinstance(p, Person))
    print(hasattr(p, 'name'))
    # 已经表明p的实例,就不用多写self,否则会判断没有这个属性
    #print(hasattr(p, 'self.name'))
    print(getattr(p, 'weight', None))
    setattr(p, 'weight', 64)
    print(hasattr(p, 'weight'))
    print(getattr(p, 'weight'))
    delattr(p, 'age')
    print(hasattr(p, 'age'))
    >>>
    True
    True
    True
    None
    True
    64
    False

  • dir: 获取对象的成员列表

    class A():
    pass
    print(dir(A))
    a = A()
    print('--'*20)
    print(dir(a))
    >>>
    ['class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'gt', 'hash', 'init', 'init_subclass',
    'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref']
    ----------------------------------------
    ['class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'gt', 'hash', 'init', 'init_subclass',
    'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref']

  • 获取对象的类

    • type(s)

    • s.class

      class A():
      pass
      a = A()
      print(type(a))
      print(a.class)
      >>>
      <class 'main.A'>
      <class 'main.A'>

  • Python内置函数列表可参考:

2. 类的成员描述符(属性)

  • 类的成员描述符是为了在类中对类的成员属性进行相关操作而创建的一种方式

    • get: 获取属性的操作
    • set:修改或者添加属性操作
    • delete: 删除属性的操作
  • 如果想使用类的成员描述符,大概有三种方法

    • 使用类实现描述器
    • 使用属性修饰符
    • 使用property函数
      • property函数很简单
      • property(fget, fset, fdel, doc)
  • 无论哪种修饰符都是为了对成员属性进行相应的控制

    • 类的方式: 适合多个类中的多个属性共用用一个描述符
    • property:使用当前类中使用,可以控制一个类中多个属性,这些属性都需要进行某种相同的操作
    • 属性修饰符: 使用于当前类中使用,控制一个类中的一个属性
  • 案例:通过类实现设置描述器

    class Student():
    def init(self, name):
    self.name = name
    self.setName()
    def setName(self):
    self.name = self.name.title()
    s = Student('chen ping an')
    print(s.name)
    >>>
    Chen Ping An

  • 案例property

    class Person():
    def fget(self):
    return self._name
    def fset(self, name):
    self._name = name.title()

    def fdel(self):
    self._name = 'Noname'

    name = property(fget, fset, fdel, '对name的操作')
    p = Person()
    p.name = 'hello world'
    print(p.name)
    >>>
    Hello World

3. 类的内置属性

  • dict:以字典的方式显示类的成员组成

  • doc: 获取类的文档信息

  • name:获取类的名称,如果在模块中使用,获取模块的名称

  • bases: 获取某个类的所有父类,以元组的方式显示

  • 案例

    类的内置属性举例

    print(Person.dict)
    print(Person.doc)
    print(Person.name)
    print(Person.bases)

4. 类的常用魔术方法

  • 魔术方法就是不需要人为调用的方法,基本是在特定的时刻自动触发

  • 魔术方法的统一的特征,方法名被前后各两个下滑线包裹

  • 操作类

    • __init__: 构造函数
    • __new__: 对象实例化方法,此函数较特殊,一般不需要使用
    • __call__: 对象当函数使用的时候触发,当前类作为其他类的属性的时候,此时__call__函数不会触发
    • __str__: 当对象被当做字符串使用的时候调用
    • __repr__: 返回字符串,跟__str__具体区别请百度
  • 描述符相关:也称为描述符协议:当前类被作为其他类的属性的时候调用

    • __set__():为一个属性赋值时触发
    • __get__():当前类被作为其他类的属性的时候调用会自动调用此函数,
    • object.get(self, instance, owner)
    • 如果class定义了它,则这个class就可以称为descriptor。
      • owner是所有者的类,instance是访问descriptor的实例,如果不是通过实例访问,
      • 而是通过类访问的话,instance则为None。
    • (descriptor的实例自己访问自己是不会触发__get__,而会触发__call__,
    • 只有descriptor作为其它类的属性才有意义。)
    • __delete__():使用del属性时触发
  • 案例

    class S():
    name = 'chenpingan'
    age = 18
    def get(self, instance, owner):
    print('S get')

    def set(self, instance, owner):
    print('S set')

    def delete(self, instance):
    print('S delete')

    class I():
    def get(self, instance, owner):
    print('I get')

    def set(self, instance, owner):
    print('I set')

    def delete(self, instance):
    print('I delete')

    class Person():
    name = S()
    age = I()
    # name被Str类代理,age被Int类代理,就相当于变成另一个类的属性
    def init(self, name, age):
    self.name = name
    self.age = age
    # 实例化有参数传递的时候就会自动调用,传参的过程本就带有获取和赋值
    p1=Person('alex',18)
    print('-------------')
    #描述符Str的使用
    p1.name
    print('--'20)
    p1.name='egon'
    #print(p1.name)
    del p1.name
    print('--'
    20)
    #描述符Int的使用
    p1.age
    p1.age=18
    #print(p1.age)
    del p1.age
    print('--'*20)
    >>>
    S set
    I set
    -------------
    S get
    ----------------------------------------
    S set
    S delete
    ----------------------------------------
    I get
    I set
    I delete
    ----------------------------------------

  • 属性操作相关

    • 使用点属性操作符的时候会自动触发,无论属性是否存在都会触发
    • __getattr__: 访问一个不存在的属性时触发
    • __setattr__: 对成员属性进行设置的时候触发
      • 参数:
        • self用来获取当前对象
        • 被设置的属性名称,以字符串形式出现
        • 需要对属性名称设置的值
      • 作用:进行属性设置的时候进行验证或者修改
      • 注意: 在该方法中不能对属性直接进行赋值操作,否则死循环
  • 参看案例

    class Foo:
    x=1
    def init(self,y):
    self.y=y
    def getattr(self, item):
    print('----> from getattr:你找的属性不存在')
    def setattr(self, key, value):
    print('----> from setattr')
    # self.key=value #这就无限递归了
    # self.dict[key]=value #应该使用它
    def delattr(self, item):
    print('----> from delattr')
    # del self.item #无限递归了
    self.dict.pop(item)

    __setattr__添加/修改属性会触发它的执行

    f1=Foo(10)
    print(f1.dict) # 因为重写了__setattr__,凡是赋值操作都会触发它的运行,什么都没写,就是根本没有执行赋值操作,除非手动操作属性字典,否则无法赋值
    f1.z=3
    print(f1.dict)

    __delattr__删除属性的时候会触发

    f1.dict['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
    del f1.a
    print(f1.dict)

    __getattr__只有在使用点调用属性且属性不存在的时候才会触发

    f1.xxxxxx
    >>>
    ----> from setattr
    {}
    ----> from setattr
    {}
    ----> from delattr
    {}
    ----> from getattr:你找的属性不存在

  • 案例

    getattr

    class A():
    name = "NoName"
    age = 18

    def getattr(self, name):
    print("没找到呀没找到")
    print(name)

    a = A()
    print(a.name)
    print(a.addr)
    >>>
    NoName
    没找到呀没找到
    addr
    None

  • 案例

    __setattr__案例

    class Person():
    def init(self):
    pass

    def setattr(self, name, value):
    print("设置属性: {0}".format(name))
    # 下面语句会导致问题,死循环
    #self.name = value
    # 此种情况,为了避免死循环,规定统一调用父类魔法函数
    super().setattr(name, value)

    p = Person()
    print(p.dict)
    p.age = 18
    print(p.dict)
    >>>
    {}
    设置属性: age

  • 运算分类相关魔术方法

    • __gt__: 进行大于判断的时候触发的函数
      • 参数:
        • self
        • 第二个参数是第二个对象
        • 返回值可以是任意值,推荐返回布尔值
  • 案例

    gt

    class Student():
    def init(self, name):
    self._name = name

    def gt(self, obj):
    print("哈哈, {0} 会比 {1} 大吗?".format(self, obj))
    return self._name > obj._name

    字符串的比较是按什么规则

    stu1 = Student("one")
    stu2 = Student("two")

    print(stu1 > stu2)

  • 魔法函数

8. 类和对象的三种方法

  • 实例方法

    • 需要实例化对象才能使用的方法,使用过程中可能需要截止对象的其他对象的方法完成
  • 静态方法

    • 不需要实例化,通过类直接访问
  • 类方法

    • 不需要实例化
  • 参看案例

    三种方法的案例

    class Person:
    # 实例方法
    def eat(self):
    print(self)
    print("Eating.....")

    类方法

    类方法的第一个参数,一般命名为cls,区别于self

    @classmethod
    def play(cls):
    print(cls)
    print("Playing.....")

    静态方法

    不需要用第一个参数表示自身或者类

    @staticmethod
    def say():

    print("Saying....")

    yueyue = Person()

    实例方法

    yueyue.eat()
    # 类方法
    Person.play()
    yueyue.play()
    #静态方法
    Person.say()
    yueyue.say()

10. 抽象类

  • 抽象方法: 没有具体实现内容的方法成为抽象方法

  • 抽象方法的主要意义是规范了子类的行为和接口

  • 抽象类的使用需要借助abc模块

    import abc

  • 抽象类:包含抽象方法的类叫抽象类,通常成为ABC类

  • 抽象类的使用

    • 抽象类可以包含抽象方法,也可以包含具体方法
    • 抽象类中可以有方法也可以有属性
    • 抽象类不允许直接实例化
    • 必须继承才可以使用,且继承的子类必须实现所有继承来的抽象方法
    • 假定子类没有是现实所有继承的抽象方法,则子类也不能实例化
    • 抽象类的主要作用是设定类的标准,以便于开发的时候具有统一的规范
  • 案例

    抽象

    class Animel():
    def sayHello(self):
    pass
    class Dog(Animel):
    pass
    class Person(Animel):

    def sayHello(self):
    print("Kiss me")
    d = Dog()
    d.sayHello()
    p = Person()
    p.sayHello()
    >>>
    Kiss me

  • 案例

    抽象类的实现

    import abc

    声明一个类并且指定当前类的元类

    class Human(metaclass=abc.ABCMeta):

    定义一个抽象的方法

    @abc.abstractmethod
    def smoking(self):
    pass

    定义类抽象方法

    @abc.abstractclassmethod
    def drink():
    pass

    定义静态抽象方法

    @abc.abstractstaticmethod
    def play():
    pass

    def sleep(self):
    print("Sleeping.......")

11. 自定义类

  • 类其实是一个类定义和各种方法的自由组合

  • 可以定义类和函数,然后自己通过类直接赋值

  • 可以借助于MethodType实现

  • 借助于type实现

  • 利用元类实现- MetaClass

    • 元类是类
    • 备用来创造别的类
  • 案例

    自己组装一个类

    class A():
    pass

    def say(self):
    print("Saying... ...")

    class B():
    def say(self):
    print("Saying......")

    say(9)
    A.say = say

    a = A()
    a.say()

    b = B()
    b.say()
    >>>
    Saying... ...
    Saying... ...
    Saying......

  • 案例

    from types import MethodType

    class A():
    pass

    def say(self):
    print("Saying... ...")

    a = A()
    a.say = MethodType(say, A)
    a.say()
    >>>
    Saying

  • 案例

    利用type造一个类

    先定义类应该具有的成员函数

    def say(self):
    print("Saying.....")

    def talk(self):
    print("Talking .....")

    用type来创建一个类

    A = type("AName", (object, ), {"class_say":say, "class_talk":talk})

    然后可以像正常访问一样使用类

    a = A()

    a.class_say()
    a.class_talk()
    >>>
    Saying.....
    Talking .....

  • 案例

    元类演示

    元类写法是固定的,必须继承自type

    元类一般命名以MetaClass结尾

    class TulingMetaClass(type):
    # 注意以下写法
    def new(cls, name, bases, attrs):
    #自己的业务处理
    print("哈哈,我是元类呀")
    attrs['id'] = '000000'
    attrs['addr'] = "北京海淀区公主坟西翠路12号"
    return type.new(cls, name, bases, attrs)

    元类定义完就可以使用,使用注意写法

    class Teacher(object, metaclass=TulingMetaClass):
    pass

    t = Teacher()
    >>>
    哈哈,我是元类呀

posted @ 2020-02-18 22:50  声凉冫  阅读(117)  评论(0)    收藏  举报