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实例添加name
和age
属性。
为了达到限制的目的,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__