1.@property装饰器
在文章Python面向对象程序设计及Property装饰器中,通过@property装饰器可以代替Python类的getter/setter方法,实现对私有属性的访问,在这里对属性相关的其他内容进行总结归纳。
2.__slots__
使用
先定义简单的一个类:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
由于Python是可以动态绑定属性和方法的,因此,可以对一个类或者类实例绑定一个属性。如果对一个对象绑定一个属性,该属性只对当前对象起作用,类的其他对象是没有这个属性的,如:
if __name__ == "__main__":
stu1 = Student("ZhangSan",24)
# 对stu1对象绑定一个nickname属性
stu1.nickname = "little Zhang"
stu2 = Student("Lisi",24)
print(stu1.nickname) # little Zhang
# stu2没有nickname属性,因此出现异常
# print(stu2.nickname) # 'Student' object has no attribute 'nickname'
print(stu1.nickname) # little Zhang
print(stu2.nickname) # 'Student' object has no attribute 'nickname'
在创建类时(如果没有使用__slots__
属性),python会为每个实例创建一个__dict__
属性,以字典的形式存放每个实例的属性,我们分别打印stu1和stu2的__dict__
属性:
print(stu1.__dict__)
print(stu1.__dict__)
'''
输出结果:
#{'nickname': 'little Zhang', 'age': 24, 'name': 'ZhangSan'}
{'nickname': 'Lisi', 'age': 23}
'''
如果要对类的所有对象都绑定一个属性,那么就要绑定在类上:
Student.nickname = "litter Student"
这时stu1和stu2都具有nickname属性了。
如果禁止对类进行属性的添加和删除,就要在定义类时定义一个特殊的__slots__
属性即可,这样的类创建后将包含指定的元素,而没有__dict__
属性,如下面的NewStudent类:
class NewStudent:
__slots__ = ("name", "age")
def __init__(self, name, age):
self.name = name
self.age = age
if __name__ == "__main__":
stu1 = NewStudent("ZhangSan",24)
# 由于使用__slot__指定了属性,不能再进行绑定,出现AttributeError
stu1.nickname = "little Zhang" # AttributeError: 'NewStudent' object has no attribute 'nickname'
# 没有__dict__属性,出现AttributeError
print("dict:", stu1.__dict__) # AttributeError: 'NewStudent' object has no attribute '__dict__'
注意:使用
__slots__
要注意,__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
3.属性相关的特殊方法
通过@property装饰器可以快速简单的对属性进行控制,但是可读性差 ,因此,除这种方式外,可以使用python内置的一些特殊方法来控制属性的存取,这些方法见下表:
特殊方法 | 使用 | 描述 |
---|---|---|
__getattr__(self,item) |
v = obj.n | 返回obj对象的item属性 |
__setattr__(self, key, value) |
obj.key = value | 将obj对象的key属性设置为value |
__delattr__(self,item) |
v = obj.n | 删除obj对象的item属性 |
__dir__(self) |
dir(obj) | 返回obj对象的属性列表 |
__getattribute__(self,item) |
v = obj.n | 返回obj对象的item属性 |
例如通过上述方法对Student类中name属性进行控制:
def __setattr__(self, key, value):
if key == "name":
if not isinstance(value, str):
raise AttributeError("from setarrt:name must be s str obj")
self.__name = value
如果类中同时定义了__setattr__()
和@name.setter,执行哪一个呢?肯定是前者了.
注意:如果要实现这些方法来对属性存取进行控制,应该做好条件判断,在设置的属性或值不符合时抛出AttributeError或ValueError。
__getattribute__()
和__getattr__()
方法都用于获取属性,在寻找属性时,其中如果实现了,则__getattr__()
不会调用。并且__getattribute__()
通常会导致递归调用,因此一般不需要实现该方法。