开发者

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 的详细解析与实战案例:

      一、核心概念与基础语法

      1.property的本质

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

      2. 基础语法(两种方式编程客栈)

      # 方式1:使用 property() 函数
      class Person:
          def __init__(selpythonf, 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 android10
                
        class Child(Parent):
            @property
            def value(self):python
                return 20
        

      3. 性能考量

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

      五、与其他技术的对比

      技术用途实现方式
      property属性封装与控制装饰器或 property () 函数
      getter/settejsr传统的访问控制方法显式定义方法
      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 可以提高代码的安全性、可维护性和可读性,尤其在需要控制属性访问逻辑的场景中表现出色。

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜