做网站和优化公司的宣传语,穆棱seo,装修加盟好项目,qq网页空间前言:
写代码嘛#xff0c;关键是得让它既好用又好看#xff0c;这不#xff0c;Python装饰器就摆在那儿。咱们程序员有时也得有那么点艺术家的腔调#xff1a;讲求效率#xff0c;追求代码的简洁优雅#xff0c;偶尔还得装装X#xff0c;不是吗#xff1f;
翻开人家…前言:
写代码嘛关键是得让它既好用又好看这不Python装饰器就摆在那儿。咱们程序员有时也得有那么点艺术家的腔调讲求效率追求代码的简洁优雅偶尔还得装装X不是吗
翻开人家的工程代码哎呦有时候我都忍不住想吐槽怎么就这么啰嗦这不咱就得拿出刀子削削刻刻把装饰器这玩意儿的妙用给咱整明白了。得让代码那叫一个流畅看着清清楚楚懂得一看就会会了还想看。 正文:
1. staticmethod
作用
staticmethod 装饰器允许我们定义一个方法使其不依赖于对象的状态即不与特定的实例self绑定也不与类cls绑定。这主要用在你想将某个功能置于类的命名空间namespace下以表明它逻辑上属于类但实际上又独立于类的任何特定实例。 用法
当你需要直接通过类调用方法而不需要实例时将该方法定义为静态方法是非常合适的。
class MathOperations:staticmethoddef add(x, y):返回两个参数的和。return x y# 调用静态方法注意如何使用类名直接调用静态方法而不是类的实例
result MathOperations.add(5, 10)
print(result) # 输出: 15代码讲解
在上述代码中add 方法被 staticmethod 装饰意味着它不接受常规方法第一个参数self。这使得它可以像普通函数一样通过类名直接调用而不需要创建类的实例。 对比
不使用 staticmethod 的普通方法会要求传递一个实例作为第一个参数。下面是未使用 staticmethod 的对比
class MathOperations:def add(self, x, y):返回两个参数的和。需要通过实例调用。return x y# 创建类的实例
math_ops MathOperations()
result math_ops.add(5, 10)
print(result) # 输出: 15在这个例子中我们必须先创建一个 MathOperations 类的实例并通过这个实例调用 add 方法。 2.classmethod
作用
classmethod 装饰器使方法变成类方法它接收类本身作为第一个参数通常命名为 cls。这使得这个方法可以访问类属性或调用其他类方法而不依赖于具体的实例。 用法
类方法通常用作替代构造函数。
class MyClass:_my_list []classmethoddef add_to_list(cls, item):将项目添加到类属性列表中。cls._my_list.append(item)MyClass.add_to_list(item 1)
print(MyClass._my_list) # 输出: [item 1]代码讲解
在上述代码中add_to_list 方法是一个类方法可以直接通过类来调用并且它修改了类属性 _my_list。 对比
常规的实例方法需要创建实例才能调用并且只能访问实例属性
class MyClass:def __init__(self):self._my_list []def add_to_list(self, item):将项目添加到实例属性列表中。self._my_list.append(item)# 创建类的实例
my_instance MyClass()
my_instance.add_to_list(item 1)
print(my_instance._my_list) # 输出: [item 1]# 尝试使用类名直接调用将会失败
# MyClass.add_to_list(item 1) # 这将抛出 TypeError3. property
作用
property 装饰器用于将类中的方法当作一个属性来访问通常用于计算或返回内部状态的值同时不让调用者直接访问内部状态。 用法
它经常被用于创建只读属性。
class MyClass:def __init__(self, value):self._internal_state valuepropertydef internal_state(self):访问内部状态的一个只读属性return self._internal_state# 创建类实例
instance MyClass(5)
print(instance.internal_state) # 输出: 5代码讲解
在上面的代码中internal_state 成为一个只读属性我们不能直接对它赋值除非也定义了 setter。 对比
没有 property 装饰器我们通常会直接公开属性或通过一个明确的 getter 方法来访问
class MyClass:def __init__(self, value):self.internal_state value# 创建类实例
instance MyClass(5)
print(instance.internal_state) # 输出: 5在这个例子中internal_state 可以被外部直接访问和修改没有了 property 提供的保护层。 4. property.setter
作用
property.setter 装饰器是与之前的 property 配套使用的它允许我们定义一个赋值方法可以通过这个属性对相关数据进行设置。 用法
我们可以用它来定义一个属性的设置逻辑例如实施类型检查或值验证。
class MyClass:def __init__(self, value):self._internal_state valuepropertydef internal_state(self):return self._internal_stateinternal_state.setterdef internal_state(self, value):if not isinstance(value, int):raise ValueError(internal_state must be an integer)self._internal_state value# 创建类实例
instance MyClass(5)
instance.internal_state 10 # 有效
print(instance.internal_state) # 输出: 10
代码讲解
在这个例子中尝试为 internal_state 赋非整数值会引发 ValueError因为我们的 setter 方法中添加了类型检查。 对比
如果没有 property.setter我们不能定义一个属性的赋值行为属性将是完全公开的
class MyClass:def __init__(self, value):self.internal_state value# 创建类实例
instance MyClass(5)
instance.internal_state a string # 没有问题但可能不是我们想要的行为在没有 setter 装饰器的情况下internal_state 属性可以接受任何类型的赋值没有额外的验证逻辑来保护类的内部表示。
5. functools.wraps
作用
装饰器在Python中用于增加函数额外的功能但装饰器会改变函数的__name__和__doc__属性。functools.wraps是一个特殊的装饰器用于在定义装饰器时保持原函数的元数据不变。 用法
这通常用于自定义装饰器的编写中以确保被装饰函数的元数据不会丢失。
import functoolsdef my_decorator(func):functools.wraps(func)def wrapper(*args, **kwargs):print(函数发生前...)result func(*args, **kwargs)print(函数发生后)return resultreturn wrappermy_decorator
def say_hello():Greet the user.print(Hello!)# 由于使用了 functools.wrapssay_hello 保留了其原始的元数据
print(say_hello.__name__)
print(say_hello.__doc__) 代码讲解
在这个例子中functools.wraps用在内部函数wrapper上保护了原始函数say_hello的__name__和__doc__属性。如果不使用functools.wrapssay_hello.__name__将会返回wrapper。 对比
没有functools.wraps函数say_hello的属性会被丢失
def my_decorator(func):def wrapper(*args, **kwargs):Wrapper function for func.print(函数get前发生的...)result func(*args, **kwargs)print(函数get后发生的...)return resultreturn wrappermy_decorator
def say_hello():print(Hello!)# 没有使用 functools.wraps元数据被覆盖了
print(say_hello.__name__)
print(say_hello.__doc__) 在没有使用functools.wraps的这个版本中装饰函数wrapper的__name__和__doc__覆盖了say_hello的元数据这会在某些情况下导致混淆特别是在需要函数签名保持原样时。 6. functools.lru_cache
作用
functools.lru_cache 提供了一个简单的缓存机制让函数能缓存最近使用过的输入及其结果。如果一个函数被频繁调用并且伴随相同的参数LRULeast Recently Used缓存可以提升性能。 用法
它特别用于那些计算开销大但又有高重复调用概率的函数。
import functoolsfunctools.lru_cache(maxsize32)
def fibonacci(num):返回斐波那契数列的第 num 个数if num 2:return numreturn fibonacci(num - 1) fibonacci(num - 2)# 第一次调用将会缓存结果
print(fibonacci(10)) # 输出: 55
# 后续调用将会使用缓存
print(fibonacci(10)) # 输出: 55代码讲解
在这个例子中fibonacci 函数的每个结果会在首次计算后缓存起来。当你再次用同样的参数调用该函数时它会返回缓存的结果而不是重新计算。 对比
不使用 functools.lru_cache 运行上面的 fibonacci 函数会导致很多重复的计算特别是参数较大时会非常耗时。 7. functools.singledispatch
作用
functools.singledispatch 装饰器可以将普通函数转化为单分派泛函数。这表示函数将会根据第一个参数的类型调用另外专门定义的函数实现类似于其他语言中的函数重载。 用法
它特别适用于需要根据不同类型执行不同操作的场景。
import functoolsfunctools.singledispatch
def format_data(arg):默认的实现被调用时参数类型没有匹配的特定注册函数return str(arg)format_data.register
def _(arg: int):专门用于处理整数的实现return f{arg} is an integerformat_data.register
def _(arg: list):专门用于处理列表的实现return fList length is {len(arg)} and items are {, .join(map(str, arg))}# 根据参数类型调用不同的实现
print(format_data(Hello!))
print(format_data(42))
print(format_data([1, 2, 3])) 代码讲解
在这个例子中对于任意未注册类型format_data 将使用默认实现即直接转换为字符串。对于被注册类型例如 int 和 list将调用专为它们定义的函数。 对比
若没有 functools.singledispatch你通常需要编写显式的类型检查语句如使用 if-elif-else 结构这样的代码通常会更加冗长和不易维护。 总结:
好了我的粉儿们咱们今天的装饰器课就上到这儿。
记住装饰器不光让你的代码行数变短颜值变高更重要的是它能让你的工作流、逻辑变得更清晰。
staticmethod和classmethod能帮你搞定静态和类相关的调用property 让访问方法像是读取属性一样优雅functools.wraps让你自定义装饰器的时候还能保持原函数的尊严和名声。然后是咱们的性能加速器functools.lru_cache让你对那些费劲儿的计算结果记个小本本下次用的时候直接从记忆里找不再重新煮沸冷饭节约不少脑力。至于functools.singledispatch简直就是动态语言Python的类型挂钩利器让同一个名字的函数根据传参的不同表演不同的戏法。 啰嗦了这么多希望你们明白代码写得好不好跟会不会用装饰器那可是直接挂钩的。用好了你的代码就像是精品咖啡不用或者用糟了那就是旅馆速溶。行了回家练去吧。
保持好奇保持饥渴这样才能写出更香的代码。加油