class property(fget=None, fset=None, fdel=None, doc=None)
它返回的是一个属性。
比如:
class C:
@property
def x(self):
return None
print(type(x))
可以看见打印的结果是:
<class 'property'>
也就是说返回的x
其实是一个类对象,记住,不是类的实例,它本身就是一个类,叫property
。这个类有setter和deleter
两个方法,下面会用到。
也就是说property
其实是一个类,在初始化的时候,可以给定上面的4个参数,前面三个参数,都是接收函数类型的参数,分别用于获取属性的值,设置属性的值,和删除属性,最后一个doc
用于设定属性的docstring。
看一下它和类属性的区别:
class C:
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
y = 1
c = C()
print(C.x)
print(C.y)
print(c.x)
print(c.y)
打印的结果是:
<property object at 0x000002789820F458>
1
None
1
也就是说其实x
也是一个类属性,只不过,如果通过了C
的实例c
去访问,就会访问到对应的getx setx delx
等方法上。
我们看一个实例:
class C:
def __init__(self):
self._x = None
def getx(self):
print('getter')
return self._x
def setx(self, value):
print('setter')
self._x = value
def delx(self):
print('deleter')
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
c = C()
print(c.x)
c.x = 1
print(c.x)
del c.x
# print(c.x) #由于上面使用del,所以这里会报错
最后的打印结果是:
getter
None
setter
getter
1
deleter
其实很类似下面的MyProperty
(如果你熟悉描述器的概念,下面的很好理解):
class MyProperty:
def __init__(self, getter, setter, deleter, docstr):
self.getter = getter
self.setter = setter
self.deleter = deleter
self.docstr = docstr
def __get__(self, instance, owner):
return self.getter(instance)
def __set__(self, instance, value):
self.setter(instance, value)
class C:
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = MyProperty(getx, setx, delx, "I'm the 'x' property.")
c = C()
print(c.x)
c.x = 1
print(c.x)
如果我们想让某个属性只能可读,不能被修改,那么可以使用下面的方式:
class C:
def __init__(self):
self._x = 1
@property
def x(self):
return self._x
c = C()
print(c.x)
# c.x = 1 # 因为设置为了只读属性,这里修改会报错
最后的结果是:
1
类似,我们也可以编写一个替换(当然,本文的很多替换,由于是举例,并没有考虑所有情况,只会对当前用到的情况进行代码的编写):
class MyProperty:
def __init__(self, getter=None, setter=None, deleter=None, docstr=None):
self.getter = getter
self.setter = setter
self.deleter = deleter
self.docstr = docstr
def __get__(self, instance, owner):
return self.getter(instance)
def __set__(self, instance, value):
if not self.setter:
raise AttributeError("can't set attribute")
class C:
def __init__(self):
self._x = 1
@MyProperty
def x(self):
return self._x
c = C()
print(c.x)
c.x = 1
结果:
1
最后抛出AttributeError: can't set attribute
异常。
按照上面的使用@property
的方式后,属性变成只读的了,如果要变成可写可删除,那么可以使用下面的方式:
class C:
def __init__(self):
self._x = 1
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
c = C()
print(c.x)
c.x = 2
print(c.x)
del c.x
# print(c.x) # 这里抛出异常
结果:
1
2