Python学习 Day14 python中MethodType的使用解析、__slots__、 __str__和__repr__

python中MethodType的使用解析

MethodType: 
用MethodType将方法绑定到类,并不是将这个方法直接写到类内部,而是在内存中创建一个link指向外部的方法,在创建实例的时候这个link也会被复制。

情况一:把方法绑定到某个类的实例上

class Student(object):
    pass

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

s1 = Student()
s2 = Student()
s3 = Student()
from types import MethodType
#将set_name方法绑定到s1实例上
s1.set_name = MethodType(set_name, s1)
s2.set_name = MethodType(set_name, s2)
s1.set_name('tom')
s2.set_name('tony')
print(s1.name, ',', s2.name)

结果:

tom , tony

>>> print s3.name

Traceback (most recent call last):
  File "<pyshell#23>", line 1, in <module>
    print s3.name
AttributeError: 'Student' object has no attribute 'name'

解析:MethodType把方法绑定在类实例上时,每个实例有自己单独的指向区域,互不干扰。

情况二:将方法绑定在类上

class Student(object):
    pass

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

s1 = Student()
s2 = Student()
s3 = Student()
from types import MethodType
#将set_name方法绑定到s1实例上
Student.set_name = MethodType(set_name,Student)
s1.set_name('tom')
s2.set_name('tony')
print(s1.name, ',', s2.name)

结果:

tony , tony

解析:MethodType把方法绑定在类上并且没有第二个None参数时,通过该类创建的实例都会指向相同的区域,导致后面实例的值会覆盖前面实例的值。

解析

Student类本身并没有属性和方法,所以用这个类创建的实例也没有属性和方法。用MethodType将set_age方法绑定到Student类,并不是将这个方法直接写到Student类内部,而是在Student内存中创建一个link指向外部的方法,在创建Student实例的时候这个link也会被复制。所以不管创建多少实例,这些实例和Student类都指向同一个set_name方法。s1.set_name('tom')并没有在S1这个实例内部创建name属性,而是将name属性创建在外部set_name方法的内存区中。因为s1和s1内部link都指向外部set_name方法的内存区,所以不管s1还是s1在调用set_name方法的时候改变的是set_name方法内存区里的name属性,所以s2改了s1也就改了,如果新建一个实例C在没有调用set_name方法的前提下也会有name属性,因为C的link指向的set_name方法的内存区,而set_name之前被A或者B调用过了。

总结

大概意思就是通过这样绑定的方法设置的属性有点java中静态变量的意思

 

通常情况下,上面的set_score方法可以直接定义在class中,但动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。

使用__slots__

但是,如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加nameage属性。

为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

然后,我们试试:

>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

由于'score'没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。

使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的

>>> class GraduateStudent(Student):
...     pass
...
>>> g = GraduateStudent()
>>> g.score = 9999

除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__

__str__和__repr__

如果要把一个类的实例变成 str(先理解为用字符串表示一个实例),就需要实现特殊方法__str__():

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
    def __str__(self):
        return '(Person: %s, %s)' % (self.name, self.gender)
>>> p = Person('Bob', 'male')
>>> print p

结果:

(Person: Bob, male)

但是,如果直接敲变量 p:

>>> p
<main.Person object at 0x10c941890>

似乎__str__() 不会被调用。

因为 Python 定义了__str__()和__repr__()两种方法,__str__()用于显示给用户,而__repr__()用于显示给开发人员。

有一个偷懒的定义__repr__的方法:

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
    def __str__(self):
        return '(Person: %s, %s)' % (self.name, self.gender)
    __repr__ = __str__

 

posted @ 2018-04-27 20:49  paulzhang511  阅读(184)  评论(0编辑  收藏  举报