Python内置函数之property函数用法详解

 更新时间:2025年07月02日 11:03:55   作者:alden_ygq  
这篇文章主要介绍了Python内置函数之property函数用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

在 Python 中,property 是一个内置的装饰器,用于将类方法转换为类属性,实现对属性的高级控制(如类型检查、只读限制、计算属性等)。

以下是对 property 的详细解析与实战案例:

一、核心概念与基础语法

1.property的本质

  • 属性封装:将方法伪装成属性,通过点号(.)直接访问
  • 访问控制:自定义属性的 getter、setter 和 deleter 方法
  • 计算属性:动态计算属性值,无需显式存储

2. 基础语法(两种方式)

# 方式1:使用 property() 函数
class Person:
    def __init__(self, age):
        self._age = age  # 私有属性
        
    def get_age(self):
        return self._age
        
    def set_age(self, value):
        if value < 0:
            raise ValueError("年龄不能为负数")
        self._age = value
        
    age = property(get_age, set_age)  # 创建 property 对象

# 方式2:使用装饰器(推荐)
class Person:
    def __init__(self, age):
        self._age = age
        
    @property  # 相当于 age = property(age)
    def age(self):
        return self._age
        
    @age.setter  # 相当于 age = age.setter(setter)
    def age(self, value):
        if value < 0:
            raise ValueError("年龄不能为负数")
        self._age = value

3. 使用示例

p = Person(25)
print(p.age)  # 调用 getter 方法,输出: 25
p.age = 30    # 调用 setter 方法
p.age = -5    # 抛出 ValueError: 年龄不能为负数

二、进阶用法

1. 只读属性(仅实现 getter)

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)  # 输出: 78.5
c.area = 100   # 报错: AttributeError: can't set attribute

2. 计算属性(动态计算)

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        
    @property
    def area(self):
        return self.width * self.height
        
    @property
    def perimeter(self):
        return 2 * (self.width + self.height)

r = Rectangle(3, 4)
print(r.area)     # 输出: 12
print(r.perimeter)  # 输出: 14

3. 删除属性(实现 deleter)

class Person:
    def __init__(self, name):
        self._name = name
        
    @property
    def name(self):
        return self._name
        
    @name.deleter
    def name(self):
        print("删除名字...")
        del self._name

p = Person("Alice")
print(p.name)  # 输出: Alice
del p.name     # 输出: 删除名字...
print(p.name)  # 报错: AttributeError

4. 类型检查与验证

class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius
        
    @property
    def celsius(self):
        return self._celsius
        
    @celsius.setter
    def celsius(self, value):
        if not isinstance(value, (int, float)):
            raise TypeError("温度必须是数字")
        self._celsius = value
        
    @property
    def fahrenheit(self):
        return self._celsius * 1.8 + 32

t = Temperature(25)
print(t.fahrenheit)  # 输出: 77.0
t.celsius = "30"     # 报错: TypeError

三、实战案例

1. 数据库字段映射

class User:
    def __init__(self, db_row):
        self._db_row = db_row
        
    @property
    def id(self):
        return self._db_row["id"]
        
    @property
    def username(self):
        return self._db_row["username"]
        
    @property
    def email(self):
        return self._db_row["email"]

# 使用示例
db_data = {"id": 1, "username": "john", "email": "john@example.com"}
user = User(db_data)
print(user.username)  # 输出: john

2. 缓存计算结果

import math

class Factorial:
    def __init__(self, number):
        self.number = number
        self._result = None
        
    @property
    def result(self):
        if self._result is None:
            print("计算阶乘...")
            self._result = math.factorial(self.number)
        return self._result

f = Factorial(5)
print(f.result)  # 输出: 计算阶乘... 120
print(f.result)  # 直接返回缓存结果: 120

3. 权限控制

class Account:
    def __init__(self, balance, owner):
        self._balance = balance
        self._owner = owner
        
    @property
    def balance(self):
        return self._balance
        
    @balance.setter
    def balance(self, value):
        if self._owner != "admin":
            raise PermissionError("只有管理员可以修改余额")
        self._balance = value

acc = Account(1000, "user")
print(acc.balance)  # 输出: 1000
acc.balance = 2000  # 报错: PermissionError

四、深入理解与注意事项

1.property的底层实现

property 是一个描述符(descriptor)类,其简化实现如下:

class Property:
    def __init__(self, fget=None, fset=None, fdel=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        
    def __get__(self, instance, owner):
        if instance is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(instance)
        
    def __set__(self, instance, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(instance, value)
        
    def __delete__(self, instance):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(instance)
        
    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel)
        
    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel)
        
    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel)

2. 继承与property

  • 子类可重写父类的 property
    class Parent:
        @property
        def value(self):
            return 10
            
    class Child(Parent):
        @property
        def value(self):
            return 20
    

3. 性能考量

  • 少量调用property 的性能开销极小(约 100ns / 次)
  • 大量调用:若性能敏感(如循环百万次),建议直接访问属性

五、与其他技术的对比

技术用途实现方式
property属性封装与控制装饰器或 property () 函数
getter/setter传统的访问控制方法显式定义方法
getattr动态属性获取魔法方法(所有属性都经过它)
setattr动态属性设置魔法方法(所有属性都经过它)

六、常见误区与最佳实践

1. 避免过度使用property

  • 推荐场景:需要验证、计算或访问控制的属性
  • 不推荐场景:简单的数据封装(直接使用公有属性)

2. 私有属性命名约定

  • 使用单下划线 _attr 表示受保护属性(非强制私有)
  • 使用双下划线 __attr 进行名称修饰(Name Mangling)

3. 初始化时调用 setter

class Person:
    def __init__(self, age):
        self.age = age  # 调用 setter 进行验证
        
    @property
    def age(self):
        return self._age
        
    @age.setter
    def age(self, value):
        if value < 0:
            raise ValueError("年龄不能为负数")
        self._age = value

七、总结

场景推荐实现方式
简单属性直接使用公有属性
需要类型检查 / 验证使用 property 装饰器
只读属性只实现 getter 方法
计算属性使用 property 装饰器
复杂的属性访问控制自定义描述符类

合理使用 property 可以提高代码的安全性、可维护性和可读性,尤其在需要控制属性访问逻辑的场景中表现出色。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • python 弹窗提示警告框MessageBox的实例

    python 弹窗提示警告框MessageBox的实例

    今天小编就为大家分享一篇python 弹窗提示警告框MessageBox的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-06-06
  • 九个Python列表生成式高频面试题汇总

    九个Python列表生成式高频面试题汇总

    本文为大家整理了九个Python列表生成式的面试题(从简单到困难排序),可以帮助大家提高列表生成式的理解水平,感兴趣的小伙伴可以学习一下
    2022-05-05
  • 详细讲解用Python发送SMTP邮件的教程

    详细讲解用Python发送SMTP邮件的教程

    这篇文章主要详细讲解了用Python发送SMTP邮件的教程,包括在邮件中添加图片等文件,强烈推荐!需要的朋友可以参考下
    2015-04-04
  • python-opencv中的cv2.inRange函数用法说明

    python-opencv中的cv2.inRange函数用法说明

    这篇文章主要介绍了python-opencv中的cv2.inRange函数用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • python自定义函数实现最大值的输出方法

    python自定义函数实现最大值的输出方法

    今天小编就为大家分享一篇python自定义函数实现最大值的输出方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • 盘点十个超级好用的高级Python脚本

    盘点十个超级好用的高级Python脚本

    这篇文章主要介绍了盘点十个超级好用的高级Python脚本,我们经常会遇到一些大小问题,其中有很多的问题,都是可以使用一些简单的Python代码就能解决,需要的朋友可以参考下
    2023-04-04
  • Python时间序列数据的预处理方法总结

    Python时间序列数据的预处理方法总结

    这篇文章主要介绍了Python时间序列数据的预处理方法总结,时间序列数据随处可见,要进行时间序列分析,我们必须先对数据进行预处理。时间序列预处理技术对数据建模的准确性有重大影响
    2022-07-07
  • python函数的两种嵌套方法使用

    python函数的两种嵌套方法使用

    本文主要介绍了python函数的两种嵌套方法使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • python中get和post有什么区别

    python中get和post有什么区别

    在本篇内容里小编给大家分享的是关于python中get和post有什么区别的相关内容,需要的朋友们参考下吧。
    2020-06-06
  • 使用Python批量压缩tif文件操作步骤

    使用Python批量压缩tif文件操作步骤

    Tif文件是栅格数据最常用的一种格式。图像数据区以位图的方式进行数据的表示。因此Tif文件可以进行压缩,常用的压缩方式有LZW、RAW、RLE、CCITT等
    2021-09-09

最新评论