Python是一门动态语言,这使得我们可以在程序运行的时候给对象绑定新的属性或方法,这就是动态语言的灵活性。
我们先定义一个class:
class Person(object):
def __init__(self, name, age):
self._name = name
self._age = age
然后创建一个实例并动态为这个实例绑定一个属性和方法,但是为实例绑定的属性和方法对另一个实例并不起作用,如果需要应用在多个实例上,则需要将其绑定到类上:
from types import MethodType
def fly(self):
print('fly with me. hahha...')
def set_grade(self, grade):
self._grade = grade
p1 = Person('王大锤', 18)
p2 = Person('爱丽丝', 16)
# 绑定一个属性
p1._gender # '男'
# 绑定一个方法
p1.fly = MethodType(fly, p1)
p1.fly() # fly with me. hahha...
# p1绑定的属性和方法对p2无效
p2._gender # AttributeError: 'Person' object has no attribute '_gender'
p2.fly() # AttributeError: 'Person' object has no attribute 'fly'
# 将属性和方法绑定到类上
Person._school = 'A大'
# 在直接绑定或用MethodType绑定都可以
# Person.set_grade = set_grade
Person.set_grade = MethodType(set_grade, Person)
p1._school # 'A大'
p1._grade # '大三'
p2._school # 'A大'
p2.set_grade('大一')
p2._grade # '大一'
动态绑定确实方便,但是如果我们需要限定自定义类型的对象只能绑定某些属性要怎么办呢?不用担心,这就可以通过我们这篇文章所讲的主角__slots__来限定了。
定义class的时候,定义一个特殊的__slots__
变量,来限制该class实例能添加的属性:
class Person(object):
# 我们限制只能对Person实例添加_name、_age、_gender属性
__slots__ = ('_name', '_age', '_gender')
def __init__(self, name, age):
self._name = name
self._age = age
实例就不能再添加不在限定范围内的属性了:
def fly(self):
print('fly with me. hahha...')
def set_grade(self, grade):
self._grade = grade
p = Person('陆七岁', 7)
# 给被'__slots__'魔法限制的实例添加在__slots__内的属性正常
p._gender = '男'
p._gender # '男'
# 给被'__slots__'魔法限制的实例添加不在__slots__内的属性均会报AttributeError错误
p._school = 'Q小学' # AttributeError: 'Person' object has no attribute '_school'
# 也不能给被'__slots__'魔法限制实例添加方法
p.fly = MethodType(fly, p) # AttributeError: 'Person' object has no attribute 'fly'
但要注意的是,限制只是针对实例,类本身并不会被限制。怎么理解能?就是我们仍然可以通过类去添加属性或方法:
# 通过类添加不在__slots__内的属性
Person._school = 'Q小学'
Person._school # 'Q小学'
p1._school # 'Q小学'
# 通过类添加方法
Person.fly = fly
p.fly() # fly with me. hahha...
# 或通过 MethodType 添加
Person.set_grade = MethodType(set_grade, Person)
p.set_grade('二年级')
p._grade # 二年级
总结:
1、__slots__是针对类实例的限制,要添加属性或方法仍可以通过类去添加;
2、同时需要注意,__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。