[Python] 面向对象程序设计进阶(一):控制属性的三种方式

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__()通常会导致递归调用,因此一般不需要实现该方法。

猜你喜欢

转载自blog.csdn.net/fightfightfight/article/details/79932873
今日推荐