让我们从Python装饰器开始。
Python装饰器是一个函数,它帮助向已经定义的函数添加一些额外的功能。
在Python中,所有东西都是对象。Python中的函数是一类对象,这意味着它们可以被变量引用、添加到列表中、作为参数传递给另一个函数等。
考虑下面的代码片段。
def decorator_func(fun):
def wrapper_func():
print("Wrapper function started")
fun()
print("Given function decorated")
# Wrapper function add something to the passed function and decorator
# returns the wrapper function
return wrapper_func
def say_bye():
print("bye!!")
say_bye = decorator_func(say_bye)
say_bye()
# Output:
# Wrapper function started
# bye!!
# Given function decorated
这里,我们可以说decorator函数修改了say_bye函数,并向其添加了一些额外的代码行。
用于装饰器的Python语法
def decorator_func(fun):
def wrapper_func():
print("Wrapper function started")
fun()
print("Given function decorated")
# Wrapper function add something to the passed function and decorator
# returns the wrapper function
return wrapper_func
@decorator_func
def say_bye():
print("bye!!")
say_bye()
让我们用一个案例来分析一下。但在此之前,让我们讨论一些面向对象的原则。
在许多面向对象的编程语言中使用getter和setter来确保数据封装的原则(这被视为数据与操作这些数据的方法的捆绑)。
当然,这些方法是用于检索数据的getter和用于更改数据的setter。
根据这一原则,类的属性被设置为私有,以隐藏和保护它们不受其他代码的影响。
是的,@property基本上是一种使用getter和setter的python方式。
Python有一个很好的概念,叫做属性,它使面向对象程序员的工作变得更加简单。
让我们假设您决定创建一个可以以摄氏度为单位存储温度的类。
class Celsius:
def __init__(self, temperature = 0):
self.set_temperature(temperature)
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
def get_temperature(self):
return self._temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
这里是我们如何用“属性”实现它。
在Python中,property()是一个内置函数,用于创建并返回属性对象。
属性对象有三个方法:getter()、setter()和delete()。
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
def get_temperature(self):
print("Getting value")
return self.temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.temperature = value
temperature = property(get_temperature,set_temperature)
在这里,
temperature = property(get_temperature,set_temperature)
可以分解为,
# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)
注意事项:
Get_temperature仍然是一个属性而不是一个方法。
现在你可以通过写入来获取温度值。
C = Celsius()
C.temperature
# instead of writing C.get_temperature()
我们可以更进一步,不定义名称get_temperature和set_temperature,因为它们是不必要的,而且会污染类名称空间。
python处理上述问题的方法是使用@property。
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value")
return self.temperature
@temperature.setter
def temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.temperature = value
〇注意事项
用于获取值的方法用“@property”修饰。
必须作为setter的方法使用“@temperature”来修饰。如果函数被称为“x”,我们就必须用“@x.setter”来修饰它。
我们写了“两个”方法,名称相同,参数数量不同,“def temperature(self)”和“def temperature(self,x)”。
如您所见,代码显然不那么优雅。
现在,让我们来讨论一个现实生活中的实际场景。
假设你设计了一个类,如下所示:
class OurClass:
def __init__(self, a):
self.x = a
y = OurClass(10)
print(y.x)
现在,让我们进一步假设我们的类在客户中很受欢迎,他们开始在他们的程序中使用它,他们对对象做各种各样的赋值。
在决定命运的一天,一位值得信赖的客户找到我们,建议“x”必须是0到1000之间的值;这真是一个可怕的场景!
由于属性,这很简单:我们创建“x”的属性版本。
class OurClass:
def __init__(self,x):
self.x = x
@property
def x(self):
return self.__x
@x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 1000:
self.__x = 1000
else:
self.__x = x
这很棒,不是吗:您可以从最简单的实现开始,并且以后可以自由地迁移到属性版本,而不必更改接口!所以属性不仅仅是getter和setter的替代品!
你可以在这里检查这个实现