Python:面向对象编程2

 

  • types.MethodType
  • __slot__
  • @property,  @xxx.setter
  • Python的多重继承和MinIn

 

如何在class创建后,给实例绑定属性和方法? (动态绑定/定义)

class Student(object):
    pass

s = Student()
s.name = 'Michael' # 动态给实例绑定一个属性

def set_age(self, age): # 定义一个函数作为s的实例方法
    self.age = age

from types import MethodType

s.set_age = MethodType(set_age, s) # 给实例绑定一个方法

types.MethodType(obj, s) 给一个实例绑定一个方法。这个方法的第一参数即默认是“使用这个方法的对象”,一般用self表示。

 

上面的代码给实例s绑定了一个方法set_age, 但其他实例不共享set_age。

如果要所有实例都能使用的话,可以这样:

Student.set_score = set_score   #Python3

如此,就给Student绑定了一个方法。它的所有实例都可以调用。

 

解释一下:

动态定义方法,就是在代码开始运行后,通过定义一个新方法并绑定到已经定义的类或实例对象上,让类的所有实例或实例自身可以使用它。

绑定即bound。特点是绑定后可以在函数内使用self关键字。self就代表实例对象了。如果是这样:

s.set_age =  set_age  #还是上面的例子

 

那么,set_age指针只是指向了set_age方法而已。

 

types.MethodType的主要用途

The type of methods of user-defined class instances.即判断一个方法是不是自定义的类的实例方法。

class Student(object):
    pass

    def set_name(self, name):
        self.name = name

#将方法绑定在类上(没有None参数)
if type(Student().set_name) == MethodType:
    print('It is true!')
#https://github.com/python/cpython/blob/3.8/Lib/types.py
class _C:
    def _m(self): pass
MethodType = type(_C()._m)
#<class 'Method'>

  

但是,我们想要Student的实例的属性不能随意添加,必须限制,怎么做? 👇


 

 

使用__slots__

class Student(object):
    __slot__ = ('name', 'age')

如果再想要,给实例添加其他属性就会报告❌AttributeError

 

使用@property

给类的实例添加属性。

首先,一个对一个实例属性的正常操作包括写入和读取,即要两个方法。

class Student(object):

    def get_score(self):
         return self._score

    def set_score(self, value):
        self._score = value

 

但这么写很费劲,而且调用的时候,不能直接使用属性的名字score。

Python也没有类似Ruby的写法:⚠️下面代码是模仿Ruby。Ruby的 "name="也可以是方法名,并且有了赋值的功能。

class Student(object):

    def score(self):
         return self._score

    def score=(self, value):
        self._score = value
s = Student()
s.score = 11
print(s.score)

 

 

所以说很费劲。因此Python使用了自己的方法,这就是装饰器(decorator)的方法:@property

class Student(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        self._score = value

 

>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60

 

相当于score定义外面加了一层或几层定义def,这种代码的写法叫做装饰器

@property相当于加上读方法,@xxx.setter相当于加上写方法。 

 

⚠️Ruby更简单直接用attr_accessor(symbol)来完成读写方法的定义。

 

Python例子:

  1. ⚠️如果使用@property,那么格式需要注意:self._xxx。加上一个下划线。
  2. resolution是一个只读属性。他的内部是用self._width * self._height。
  3. 如果设resolution为一个普通方法,返回的是<bound method Screen.resolution of <__main__.Screen object at 0x1094e2f10>>。必须@property装饰后,才能用_xxx格式。
class Screen(object):
    @property
    def width(self):
      return self._width

    @width.setter
    def width(self, value):
        self._width = value

    @property
    def height(self):
      return self._width

    @height.setter
    def height(self, value):
        self._height = value

    @property
    def resolution(self):
        a = self._width * self._height
        return a

s = Screen()
s.width = 1024
s.height = 768
print('resolution =', s.resolution)
if s.resolution == 786432:
    print('测试通过!')
else:
    print('测试失败!')

 

 



 

没找到types, MethodType方法带参数的源代码

后来浏览了https://stackoverflow.com/questions/46525069/how-is-types-methodtype-used



 

 

多重继承

 

例子:Dog类继承哺乳动物类和,跑类。

class Dog(Mammal, Runnable):
    pass

 

通过多重继承,一个子类就可以同时获得多个父类的所有功能。

 

MixIn

Python有多重继承 ,但一般设计,主要是单一继承。如果需要混入额外的功能,就通过多重继承,这就是混入。不过混入的类的名字加上MixIn,以便看出继承关系。

class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
    pass

 

简单来说,搜索的方式,是深度优先,从左到右

  1. 查找一个方法runing, 先看Dog。没有的话:
  2. 查找Manmmal。没有的话,递归到Manmmal的基类去搜索,如果还没有,👇:
  3. 再到RunnalbeMixIn搜索,并依次类推。

真实情况更复杂,方法的解析顺序可能发生动态改变。这是因为要支持super()方法的协调。这种方式也被其他语言叫做后续方法调用

动态改变顺序必要行:因为所有多重继承的情况都会显示出一个或更多的菱形关联(即至少有一个父类可通过多条路径被最底层类所访问)。 比如object类是其他所有类的父类,但在一次搜索中,无需访问多次,所以需要动态协调。

 

Ruby的单一继承和混入

Ruby不支持多重继承,有一个继承链条。但也支持混入模块,Module#include。

需要注意的是,混入的模块加入到了继承的链条上去。所以一个实例寻找方法,是安装链条上的继承关系来从下向上找的。

Ruby用Module#ancestor来得到继承链条。superclass则返回一个类的父类。

 

Python有两个内置函数可被用于继承机制

  •  issubclass(class, classinfo) 检查类的父类。如果class是classinfo的子类(直接,间接,虚拟的),返回true
  •  isinstance() 检查一个实例的类型

 


 

 

 

 

 

 

posted @ 2019-11-10 11:06  Mr-chen  阅读(383)  评论(0)    收藏  举报