1,类的私有属性
class Foo: def __init__(self, x): self.x = x
类的属性在实例化之后是可以更改的:
f = Foo(1) print(f.x) # 1 f.x = 2 print(f.x) # 2
如果想禁止访问属性,即让属性私有,可以用“双下划线” 或者“单下划线”:
class Foo: def __init__(self, x, y): self._x = x self.__y = y def __repr__(self): return 'f._x = {}, f.__y = {}'.format(self._x, self.__y)
区别是“双下划线”解释器会对属性就行“名称更改”,而“单下划线”不会有更改,只是约定成俗。
但是知道规则还是可以轻松访问:
f = Foo(1, 1) f._x = 2 f._Foo__y = 2 print(f) # f._x = 2, f.__y = 2
所以如果只是为了属性私有,用“单下划线”和“双下划线”没有什么区别。
但“双下划线”在继承时可以避免基类属性被子类的属性覆盖。
2,属性只读(私有 + property)
私有属性 + property可以让属性变的只读:
class Foo: def __init__(self, x): self._x = x @property def x(self): return self._x
此时对Foo进行实例化后,可以访问对象的属性x,但无法给x赋值:
f = Foo(1) print(f.x) # 1 f.x = 2 # AttributeError: can't set attribute
因为实例化时的x存在私有属性self._x中,当然可以用1中提到的访问私有属性的方法去修改,但这被认为是粗略的行为:
f = Foo(1) f._x= 2 print(f.x) # 2
3,属性管理(init)
4,属性管理(property)
对属性的操作有:get,set,del。
property只是完成了get操作,配套的get / del分配由setter / delettr完成,组合起来就可以实现对属性的管理:
class Foo: def __init__(self, x): self.x = x @property def x(self): return self._x @x.setter def x(self, val): if val < 0: raise ValueError('x must be >= 0') self._x = val @x.deleter def x(self): pass
再看看对x属性的访问情况:
f = Foo(1) print(f.x) # 1 f.x = 2 print(f.x) # 2 f = Foo(-1) # ValueError: x must be >= 0 f.x = -1 # ValueError: x must be >= 0
如果__init__中使用self._x = x会出现什么后果?
class Foo: def __init__(self, x): self._x = x ...... f = Foo(-1) print(c.x) # -1 f.x = -1 # ValueError: x must be >= 0
self.x = x在实例化时会触发set,而self._x = x在实例化时绕过了set,也就是不会对实例化时的参数做检查。
另外,del可以不定义,del f.x会触发AttributeError: can't delete attribute,这里pass演示,del f.x没什么效果。
5,属性管理(描述符)
6,动态存取属性
getattr,setattr,delattr,hasattr