让我们从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
在这里,我们可以说装饰器函数修改了我们的say_hello函数,并在其中添加了一些额外的代码行。
装饰器的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来确保数据封装的原理(被视为将数据与对这些数据进行操作的方法捆绑在一起)。
这些方法当然是用于获取数据的吸气剂和用于更改数据的设置器。
根据此原理,将一个类的属性设为私有,以隐藏它们并保护它们免受其他代码的侵害。
是的,@ property基本上是使用getter和setter的pythonic方法。
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,因为它们是不必要的,并污染类名称空间。
解决上述问题的pythonic方法是使用@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”修饰。
- 用作设置器的方法用“ @ temperature.setter”修饰,如果该函数被称为“ 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
很好,不是吗:您可以从可以想象到的最简单的实现开始,并且以后可以随意迁移到属性版本,而不必更改接口!因此,属性不仅仅是吸气剂和塞特剂的替代品!
您可以在此处检查此实现