Python中的@property和decorator

初次认识decorator和@property

Welcome. 在本文中,将详细学习如何使用Python中的decorator和@property。

将会学习的内容:

  • 使用decorator的优势。
  • 使用@property的优势。
  • 装饰器函数的基础知识:它们是什么以及如何与@property关联起来。
  • 如何使用@property定义getter、setter和deleter。

Python中decorator的优势

  • 在不确定其他代码块对现有函数的调用,不改变现有函数,保证代码可靠稳定,避免修改现有函数所引发的潜在问题。
  • 拓展原来函数功能。

Python中@property的优势

property可以视为使用属性的“Pythonic”方式,因为:

  • 用于定义property的语法简洁易读。
  • 可以完全地访问实例属性,就像是公共属性一样。
  • 通过使用@property,可以重复使用property的名字,以避免为getter、setter和deleter创建新名字。

装饰器简介

装饰器函数(decorator function)是一个函数,它能给现有的函数(此“现有的函数”作为参数传递)添加新功能。使用装饰器函数就像是给冰淇淋(代指另一个函数)添加少量的巧克力(代指新功能)。即给现有的函数添加新功能,并且不对现有的函数进行任何更新修改。

 1 def decorator(func):
 2     print("在装饰器函数内部,修饰:", func.__name__)
 3     def new_function():
 4         print("新增功能,随后执行的函数为:", func.__name__)
 5         func()
 6     return new_function
 7
 8 @decorator
 9 def initial_function():
10     print("现有函数功能")
11
12 initial_function()

输出结果为:

在装饰器函数内部,修饰: initial_function
新增功能,随后执行的函数为: initial_function
现有函数功能

在不使用装饰器函数时,实现以上功能的代码如下所示:

 1 def decorator(func):
 2     print("在装饰器函数内部,修饰:", func.__name__)
 3     def new_function():
 4         print("新增功能,随后执行的函数为:", func.__name__)
 5         func()
 6     return new_function
 7
 8
 9 def initial_function():
10     print("现有函数功能")
11
12 initial_function = decorator(initial_function)
13 initial_function()

这两段代码,实现功能是相同的。装饰器是替代上述代码initial_function = decorator(initial_function)的语法糖,只增加一行代码就可以将现有函数包装到装饰器函数内。

对比两种实现方案,装饰器@decorator就可以理解为替换initial_function = decorator(initial_function)这条语句的实现。

装饰器更加简洁,有两部分组成:先定义用于包装或“装饰”其他函数的装饰器函数;然后立即在被包装函数的定义前面,加上“@”和装饰器函数名。这里的装饰器函数应该以一个函数为形参,返回值也是一个函数。

@property的实际应用

定义一个House类(该类仅定义了实例属性price)。通过House类创建一个house实例

1  class House:
2      def __init__(self, price):
3          self.price = price
4
5  house = House()

这个实例属性price是公有的,因此可以使用点标记法直接访问和修改属性值。

1 # Access value
2 house.price
3
4 # Modify value
5 house.price = 40000

然而,通常我们并不希望用户能直接访问和修改属性值,因此将实例属性设置为私有的,并采用getter和setter方法间接访问和修改私有的实例属性,更新后的代码如下:

class House:
    def __init__(self, price):
        self.__price = price

    def get_price(self):
        return self.__price

    def set_price(self, new_price):
        self.__price = new_price

之前访问该实例属性的代码均需要修改,对应的客户端也需要进行代码修改:

1 # Changed from house.price
2 house.get_price()
3
4 # Changed from house.price = 40000
5 house.set_price(40000)

为了应对以上的情况,@property应运而生,解决了当时直接使用实例属性的代码重构问题。

 1 class House:
 2     def __init__(self, price):
 3         self.__price = price
 4
 5     @property
 6     def price(self):
 7         return self.__price
 8
 9     @price.setter
10     def price(self, new_price):
11         if new_price > 0 and isinstance(new_price, float):
12             self.__price = new_price
13         else:
14             print("Please enter a valid price")
15
16     @price.deleter
17     def price(self):
18         del self.__price

此时,就可以像之前一样访问实例属性。即初始开发时可以采用传统的实例属性,以后可以根据需要随时随地无缝切换为属性,客户端代码则无须改动。

getter

1 house = House(50000.0) # Create instance
2 print(house.price)     # Access value

输出结果为:

50000.0

setter

1 house = House(50000.0)    # Create instance
2 house.price = 88888.0     # Update value
3 print(house.price)

输出结果为:

88888.0

deleter

1 # Delete the instance attribute
2 del house.price
3
4 # The instance sttribute doesn‘t exist
5 print(house.price)

输出结果为:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-13-dd54e9ad0090> in <module>
      1 # The instance sttribute doesn‘t exist
----> 2 print(house.price)

<ipython-input-8-5e2f43c64399> in price(self)
      5     @property
      6     def price(self):
----> 7         return self.__price
      8
      9     @price.setter

AttributeError: ‘House‘ object has no attribute ‘_House__price‘

总结

  • 使用decorator和@property可以使得Python代码简洁易读。
  • @property可以被视为定义getter、setter和deleter的"pythonic"方式。
  • 在不影响程序的前提下修改类的内部实现,从而避免直接对数据的访问和修改。

参考文献

  1. https://www.freecodecamp.org/news/python-property-decorator/
  2. 《Python快速入门》(第三版)

原文地址:https://www.cnblogs.com/qiuhuachuan/p/12118940.html

时间: 2024-08-29 07:26:47

Python中的@property和decorator的相关文章

python 中的@property

如果在Java中定义类,我们经常使用类来封装一些属性,比如说,Student类中,有firstname 和 lastname,同时的,为了能访问和修改这个属性,我们还会设置set和get方法,但是,在Python中,我们可以使用@property的方法来将一个方法变成一个类属性,并且,利用同样的方式,来生成set和get方法,如下代码: ######################################################################## class P

python中的property属性

目录 1. 什么是property属性 2. 简单的实例 3. property属性的有两种方式 3.1 装饰器方式 3.2 类属性方式,创建值为property对象的类属性 4. property属性-应用 4.1. 私有属性添加getter和setter方法 4.2. 使用property升级getter和setter方法 4.3. 使用property取代getter和setter方法 1. 什么是property属性 一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方法 # #

python中的property注解

装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用.Python内置的 @property 装饰器就是负责把一个方法变成属性调用的: class Student(object): @property def score(self): return self._score @score.setter def score(self, value): if not isinstance(value, int): raise ValueError('score must

Python中的@property装饰器

要了解@property的用途,首先要了解如何创建一个属性. 一般而言,属性都通过__init__方法创建,比如: 1 class Student(object): 2 def __init__(self,name,score): 3 self.name=name 4 self.score=score 创建实例,运行结果: 1 tim=Student('Tim',97) 2 tim.score=100 3 tim.score 4 100 5 mary=Student('Mary',90) 6 m

python中的property

property(fget=None, fset=None, fdel=None, doc=None) -> property attribute fget is a function to be used for getting an attribute value, and likewise fset is a function for setting, and fdel a function for del'ing, an attribute. Typical use is to defi

python中编写带参数decorator

考察上一节的 @log 装饰器: def log(f): def fn(x): print 'call ' + f.__name__ + '()...' return f(x) return fn 发现对于被装饰的函数,log打印的语句是不能变的(除了函数名). 如果有的函数非常重要,希望打印出'[INFO] call xxx()...',有的函数不太重要,希望打印出'[DEBUG] call xxx()...',这时,log函数本身就需要传入'INFO'或'DEBUG'这样的参数,类似这样:

python中的property及实现lazy property

@property有什么用呢?表面看来,就是将一个方法用属性的方式来访问. 上代码,代码最清晰了. class Circle(object): def __init__(self, radius): self.radius = radius @property def area(self): return 3.14 * self.radius ** 2 c = Circle(4) print c.radius print c.area 可以看到,area虽然是定义成一个方法的形式,但是加上@pr

python中的@property

@property 可以将python定义的函数“当做”属性访问,从而提供更加友好访问方式,但是有时候setter/getter也是需要的 class People: def __init__(self,name,weight,height): self.__name=name self.weight=weight self.height=height @property def bmi(self): return self.weight / (self.height**2) @bmi.dele

Python中的property()函数

property() 函数的作用是在新式类中返回属性值 1.语法: class property([fget[, fset[, fdel[, doc]]]]) 2.参数: fget -- 获取属性值的函数 fset -- 设置属性值的函数 fdel -- 删除属性值函数 doc -- 属性描述信息 3.返回值:返回新式类属性 4.实例:银行卡案例,假设钱是私有属性. class Card: def __init__(self, card_no): '''初始化方法''' self.card_no