基于Python 2.7.13测试。
Python是动态语言,在类定义了之后,还可以动态地绑定属性和方法。
下面先来看怎么给类的实例动态地绑定属性和方法。
>>> class Student(object): ... pass ... >>> stu1 = Student(); >>> stu1.name = 'Tom' >>> print(stu1.name) Tom >>> print(dir(stu1)) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribut e__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_e x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_ _weakref__', 'name'] >>> >>> def set_age(self, age): ... self.age = age ... >>> set_age(stu1, 20) >>> print(stu1.age) 20 >>> print(dir(stu1)) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribut e__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_e x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_ _weakref__', 'age', 'name'] >>> #并没有绑定方法到实例上 ... >>> from types import MethodType >>> stu1.set_age = MethodType(set_age, stu1) >>> stu1.set_age(33) >>> print(stu1.age) 33 >>> print(dir(stu1)) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribut e__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_e x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_ _weakref__', 'age', 'name', 'set_age'] >>> #绑定的属性和方法只属于stu1的,对于其他实例不起作用 ... >>> stu2 = Student() >>> print(dir(stu2)) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribut e__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_e x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_ _weakref__']
看怎么给类动态地绑定属性和方法。
>>> class Student(object): ... pass ... >>> def set_name(self, name): ... self.name = name ... >>> from types import MethodType >>> Student.set_name = MethodType(set_name, Student) >>> print(dir(Student)) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribut e__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_e x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_ _weakref__', 'set_name'] >>> stu1 = Student() >>> stu1.set_name('Rose') >>> stu2 = Student() >>> stu2.set_name('Jack') >>> print(stu1.name) Jack >>> print(stu2.name) Jack >>> ######## >>> class Student(object): ... pass ... >>> def set_name(self, name): ... self.name = name ... >>> Student.set_name = set_name >>> print(dir(Student)) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribut e__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_e x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_ _weakref__', 'set_name'] >>> stu1 = Student() >>> stu1.set_name('Rose') >>> stu2 = Student() >>> stu2.set_name('Jack') >>> print(stu1.name) Rose >>> print(stu2.name) Jack
想要限制实例属性,只允许对Student实例添加name和age属性。__slots__变量,来限制该class实例能添加的属性。
>>> class Student(object): ... __slots__ = ('name', 'age') ... >>> stu1 = Student() >>> stu1.name = 'John' >>> stu1.addr = 'Beijing' Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Student' object has no attribute 'addr'
__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用。
>>> class MidStudent(Student): ... pass ... >>> stu2 = MidStudent() >>> stu2.addr = 'Beijing' >>> print(stu2.addr) Beijing
slots只能限制添加属性,不能限制通过添加方法来添加属性。
>>> from types import MethodType >>> >>> class School(object): ... __slots__ = ('name') ... >>> def set_city(self, city): ... self.city = city ... >>> School.set_city = MethodType(set_city, School) >>> >>> sch = School() >>> sch.set_city('BeiJing') >>> print(sch.city) BeiJing
Python创建class的方法就是使用type()函数。 type()函数既可以返回一个对象的类型,又可以创建出新的类型。
>>> def fun(self, name='World'): ... print('Hello %s' % name) ... >>> #创建Hello类 ... Hello = type('Hello', (object,), dict(hello=fun)) >>> >>> h = Hello() >>> h.hello() Hello World
要创建一个class对象,type()函数依次传入3个参数:
- class的名称。
- 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法。
- class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。
通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。