property是用来实现属性可管理性的built-in数据类型。它实际上是一种实现了__get__(), __set__()方法的类,用户也可以根据自己的需要定义个性化的property,其实质是一种特殊的数据描述符(数据描述符:如果一个对象同时定义了__get__()和__set__()方法,则称为数据描述符,如果仅定义了__get__()方法,则称为非数据描述符)。它和普通描述符的区别在于:普通描述符提供的是一种较为低级的控制属性访问的机制,而property是它的高级应用,它以标注库的形式提供描述符的实现,其签名形式为:
property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
Property常见的使用形式有以下几种
1)
class Some_Class(object): def __init__(self): self._somevalue = 0 def get_value(self): print("calling get method to get value") return self._somevalue def set_value(self, value): print("calling set method to set value") self._somevalue = value def del_attr(self): print("calling delete method to delete value") del self._somevalue x = property(get_value, set_value, del_attr, "I‘m the ‘x‘ property.") obj = Some_Class() obj.x = 10 print(obj.x) print(obj.x + 2) del obj.x print(obj.x)
2)
class Some_class(object): _x = None def __init__(self): self._x = None @property def x(self): print("calling get method to return value") return self._x @x.setter def x(self, value): print("calling set method to set value") self._x = value @x.deleter def x(self): print("calling delete method to delete value") del self._x obj = Some_class() obj.x = 10 print(obj.x) del obj.x print(obj.x)
property的优势可言简单概括为以下几点:
1)代码简洁,可读性更强。这条优势是显而易见的,显然obj.x += 1比 obj.set_value(ojb.get_value()+1)要更简洁易读,而且对于编程人员来说还少敲了几次键盘。
2)更好的管理属性的访问。property将对属性的访问直接转换为对对应的get / set等相关函数的调用,属性能够更好的被控制和管理。
创建一个property实际上就是将其属性的访问与特定的函数关联起来,相对于标准属性的访问,其工作原理如图。property的作用相当于一个分发器,对某个属性的访问并不直接操作具体对象,而对标准属性的访问没有中间这一层,直接访问存储属性的对象。
3)代码可维护性更好;
4)控制属性访问权限;提高数据安全性,如果用户想设置某个属性为只读:
class PropertyTest(object): def __init__(self): self.__varl = 20 @property def x(self): return self.__varl pt = PropertyTest() print(pt.x) pt.x = 12
其实:使用property并不能真正完全达到属性只读的目的,正如以双下划线命令的变量并不是真正的私有变量一样,这些方法只是在直接修改属性这条道路上增加了一些障碍。如果用户想访问私有属性,同样能够实现,使用 pt._PropertyTest__varl = 30 来修改属性。
property本质并不是函数,而是特殊类,既然是类的话,那么就可以被继承,因此用户便可以根据自己的需要定义property:
def update_meta(self, other): self.__name__ = other.__name__ self.__doc__ = other.__doc__ self.__dict__.update(other.__dict__) return self class UserProperty(property): def __new__(cls, fget=None, fset=None, fdel=None, doc=None): if fget is not None: def __get__(obj, objtype=None, name=fget.__name__): fget = getattr(obj, name) print("fget name:" + fget.__name__) return fget() fget = update_meta(__get__, fget) if fset is not None: def __set__(obj, value, name=fset.__name__): fset = getattr(obj, name) print("fset name:" + fset.__name__) print("setting value:" + str(value)) return fset(value) fset = update_meta(__set__, fset) if fdel is not None: def __delete__(obj, name=fdel.__name__): fdel = getattr(obj, name) print("warning: you are deleting attribute using fdel.__name__") return fdel() fdel = update_meta(__delete__, fdel) return property(fget, fset, fdel, doc) class C(object): def get(self): print("calling C.getx to get value") return self._x def set(self, x): print("calling C.setx to set value") self._x = x def delete(self): print("calling C.delx to delete value") del self._x x = UserProperty(get, set, delete) c = C() c.x = 1 print(c.x)
回到前面的问题:使用property并不能真正完全达到属性只读的目的,用户仍然可以绕过阻碍来修改变量,那么要真正实现只读属性怎么做呢:
def ro_property(obj, name, value): setattr(obj.__class__, name, property(lambda obj: obj.__dict__["__" + name])) setattr(obj, "__" + name, value) class ROClass(object): def __init__(self, name, available): ro_property(self, "name", name) self.available = available a = ROClass("read only", True) print(a.name) a._ROClass__name = "modify" print(a.__dict__) print(ROClass.__dict__) print(a.name)
a._ROClass__name = "modify" 创建了新的属性,这样就能很好的保护可读属性不被修改。
编写高质量代码 改善Python程序的91个建议——笔记(三)
原文:https://www.cnblogs.com/xiangxiaolin/p/12881982.html