最近看Robotframe中SeleniumLibrary 源码,发现源代码中存在许多@property,因此看下python中内置的装饰器。
简言之,python 内置的装饰器常见为3个 ,分别为@property 、@classmethod和@staticmethod。
property 源码分析
查看property定义 class property(fget=None, fset=None, fdel=None, doc=None) ,说明property是一个类,包含3个可调用参数,和一个str的参数。返回为一个 property 属性。
class property(object):
def __init__(self, fget: Optional[Callable[[Any], Any]] = ...,
fset: Optional[Callable[[Any, Any], None]] = ...,
fdel: Optional[Callable[[Any], None]] = ...,
doc: Optional[str] = ...) -> None: ...
def getter(self, fget: Callable[[Any], Any]) -> property: ...
def setter(self, fset: Callable[[Any, Any], None]) -> property: ...
def deleter(self, fdel: Callable[[Any], None]) -> property: ...
def __get__(self, obj: Any, type: Optional[type] = ...) -> Any: ...
def __set__(self, obj: Any, value: Any) -> None: ...
def __delete__(self, obj: Any) -> None: ...
def fget(self) -> Any: ...
def fset(self, value: Any) -> None: ...
def fdel(self) -> None: ...
采用测试代码 python 版本为3.5.2
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
test = C()
x = property(test.getx,test.setx,test.delx,"I'm the 'x' property.")
test.x = 5
print(test.x)
del test.x
通过x = property(test.getx,test.setx,test.delx,"I'm the 'x' property.") 将x变更为类对象test的属性,可以对其进行 赋值 删除等操作。
property 作为装饰器应用
先看下面代码
class number(object):
def __init__(self):
self._x = 1000
# @property
def get_x(self):
return self._x
test = number()
print(test.get_x())
在方法未添加装饰器前,get_x是一个可以修改的类的方法。而添加 @property装饰器后,get_x 从类的方法变更为类属性,从而调用方式也发生变化。
在之前的源代码分析中,property可以传入三个参数,前面的装饰器只装饰了一个函数,可以采用以下方式进行装饰三个函数
class C:
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
test = C()
test.x = 5
print(test.x)
可以看出这与源码中的结果是一样的,实际上 源码中的代码 属于 装饰器的另一种调用方法。
小结
property 本身上就是采用类方式实现的装饰器,若在类内部使用,则将类中定义的方法转换为类的属性,且将对类属性的赋值、删除操作变得和变量操作一样,
可以说实现了多态。建议采用@property 装饰器的调用方法。应用方式
- 单一装饰 直接采用@property 此装饰器 相当于调用fget, 将类中的方法装换为类属性
- 进一步装饰 @x.setter 、 @x.deleter 将类方法变更为属性,且对属性进行 赋值和删除操作。