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

作者:

文章目录
  • 技术 用途 实现方式 property 属性封装与控制 装饰器或 property () 函数 getter/setter 传统的访问控制方法 显式定义方法 getattr 动态属性获取 魔法方法(所有属性都经过它) setattr 动态属性设置 魔法方法(所有属性都经过它)
  • 场景 推荐实现方式 简单属性 直接使用公有属性 需要类型检查 / 验证 使用 property 装饰器 只读属性 只实现 getter 方法 计算属性 使用 property 装饰器 复杂的属性访问控制 自定义描述符类 合理使用 property 可以提高代码的安全性、可维护性和可读性,尤其在需要控制属性访问逻辑的场景中表现出色。 以上为个人经验,希望能给大家一个参考,也希望大家多多支持风君子博客。 您可能感兴趣的文章: Python内置函数property()如何使用 Python中lazy property的两种方法小结 python使用property完成数据隐藏封装与校验 Python property函数的具体使用 掌握Python property装饰器巧妙管理类的属性 python装饰器中@property属性的使用解析 Python中通过property设置类属性的访问
  • 目录
    • 一、核心概念与基础语法
      • 1.property的本质
      • 2. 基础语法(两种方式)
      • 3. 使用示例
    • 二、进阶用法
      • 1. 只读属性(仅实现 getter)
      • 2. 计算属性(动态计算)
      • 3. 删除属性(实现 deleter)
      • 4. 类型检查与验证
    • 三、实战案例
      • 1. 数据库字段映射
      • 2. 缓存计算结果
      • 3. 权限控制
    • 四、深入理解与注意事项
      • 1.property的底层实现
      • 2. 继承与property
      • 3. 性能考量
    • 五、与其他技术的对比
      • 六、常见误区与最佳实践
        • 1. 避免过度使用property
        • 2. 私有属性命名约定
        • 3. 初始化时调用 setter
      • 七、总结

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

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

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

        # 方式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
        

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

        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
        

        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
        

        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
        

        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
        

        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
        

        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
        

        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
        

        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)
        

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

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

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

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

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

        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内置函数property()如何使用
        • Python中lazy property的两种方法小结
        • python使用property完成数据隐藏封装与校验
        • Python property函数的具体使用
        • 掌握Python property装饰器巧妙管理类的属性
        • python装饰器中@property属性的使用解析
        • Python中通过property设置类属性的访问

        站内搜索