一文轻松搞定Python装饰器@property

文章讨论了Python中装饰器的概念,特别是@property的使用。通过示例展示了如何利用@property来防止类的属性被随意修改,从而增强代码的安全性,以及如何将函数封装成属性进行访问。同时,提到了在Java中类似的概念——私有变量。应用@property可以避免直接修改关键属性导致的潜在错误。

背景

装饰器(Decorators),是一种可用于修改其它函数功能的函数,有助于使Python代码更加简短。

给出如下一个Python类的示例:

class CVHub(object):
    def __init__(self):
        self.age = 0
        self.member = 5


cvhub = CVHub()
print(f"cvhub.age={cvhub.age}")
print(f"cvhub.member={cvhub.member}")

通过实例化类,同时访问类中的两个成员变量,得到了以下输出:

cvhub.age=0

cvhub.member=5

乍看之下,貌似也没毛病。但是,当我们对__init__中定义的属性进行更改后,会发生什么情况呢?

cvhub.age = 1
cvhub.member = 500

print(f"cvhub.age={cvhub.age}")
print(f"cvhub.member={cvhub.member}")

此时,得到的输出会变成这个样子:

cvhub.age=1

cvhub.member=500

Terrible! 想象一下,如果系统中所涉及到一些关键的属性被完全的暴露出来,当所有开发人员都知道了相应属性名时,岂不是可以任意的修改?当然也不是每个程序员小哥哥都这么坏,但只要是人就难免会有出错的时候,比如不小心加多了一个小数点" . ",这对实际生产环境有时候是非常致命的。那么,我们有没有什么办法可以给这些重要的不想被开发人员修改的属性加一层”锁“呢(类似Java中设置成Private私有成员变量)?答案就在 @property .

功能

Python中的@property修饰符有两大功能:

  • 防止关键属性被任意修改
  • 将函数进一步封装,使函数(方法)像属性一样被访问
class CVHub(object):
    def __init__(self):
        self._age = 0
        self._member = 5

    @property
    def age(self):
        return self._age

    @property
    def member(self):
        return self._member


cvhub = CVHub()
print(cvhub.age)  # Output >> 0

同上,当我们将两个方法封装上一层装饰器@property时,可以以访问属性的方式来调用方法,同时还能够防止属性被任意修改。比如,此时如果我们尝试修改属性cvhub.age = 1,系统将会报错:

Traceback (most recent call last):
  File "E:/***/test.py", line *, in <module>
    cvhub.age = 1
AttributeError: can't set attribute
### Python装饰器的概念 Python装饰器是一种特殊类型的函数,用于修改其他函数的行为而不改变其源代码。这种设计模式允许开发者在不更改原始逻辑的情况下增强或扩展函数的功能[^1]。 装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数。通过这种方式,可以在目标函数执行前后添加额外的操作,从而实现诸如日志记录、性能监控或其他横切关注点的功能[^4]。 --- ### 装饰器的基本结构 以下是装饰器的一个基本例子: ```python def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper @my_decorator def say_hello(): print("Hello!") say_hello() ``` 上述代码展示了如何定义和使用一个简单的装饰器 `my_decorator` 来包裹 `say_hello()` 函数。运行此代码会输出如下内容: ``` Something is happening before the function is called. Hello! Something is happening after the function is called. ``` --- ### 带有参数的装饰器 如果被装饰的函数需要传递参数,则装饰器内部的嵌套函数也需要支持这些参数。下面的例子展示了一个带有参数的装饰器: ```python def do_twice(func): def wrapper_do_twice(*args, **kwargs): func(*args, **kwargs) func(*args, **kwargs) return wrapper_do_twice @do_twice def greet(name): print(f"Hello {name}") greet("Alice") ``` 这段代码将两次调用 `greet("Alice")` 方法,并打印两遍问候语[^2]。 --- ### 使用内置装饰器 Python 提供了一些常用的内置装饰器来简化特定场景下的开发工作。例如: - `@classmethod`: 将方法转换为类方法。 - `@staticmethod`: 定义静态方法。 - `@property`: 把类的方法当作属性访问。 - `@functools.wraps`: 保留原函数元数据(如名称和文档字符串)[^3]。 #### 示例:`@property` 的使用 ```python class Circle: def __init__(self, radius): self._radius = radius @property def area(self): return 3.14 * (self._radius ** 2) c = Circle(5) print(c.area) # 输出圆的面积 ``` 在这个例子中,我们利用 `@property` 将 `area` 方法伪装成属性,使得可以通过对象直接访问计算后的值。 --- ### 类装饰器 除了函数装饰器外,还可以创建类装饰器以更复杂的方式管理状态或者行为。例如,以下代码片段演示了如何使用类装饰器统计某个函数的调用次数: ```python import functools class CallCounter: def __init__(self, func): functools.update_wrapper(self, func) self.func = func self.calls = 0 def __call__(self, *args, **kwargs): self.calls += 1 result = self.func(*args, **kwargs) print(f"{self.func.__name__} has been called {self.calls} times.") return result @CallCounter def add(a, b): return a + b add(1, 2) add(3, 4) ``` 每次调用 `add` 函数时都会更新计数器并将当前调用次数打印出来。 --- ### 总结 装饰器Python编程中的一个重要工具,能够帮助程序员编写更加模块化、可重用以及易于维护的代码。无论是基础的日志记录还是复杂的跨领域需求处理,都可以借助于这一强大的特性得以解决。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CVHub

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值