python __getattr__ 和 __setattr__方法、属性私有化

本文介绍了Python中如何使用setattr()函数设置对象属性值,并探讨了__getattr__和__setattr__方法的应用,包括属性私有化的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python setattr() 函数


描述
语法

setattr 函数对应函数 getatt(),用于设置属性值,该属性必须存在。

setattr 语法:

setattr(object, name, value)

参数

  • object -- 对象。
  • name -- 字符串,对象属性。
  • value -- 属性值。
返回值
实例

无。

以下实例展示了 setattr 的使用方法:

class A(object):
 bar = 1
a = A()
getattr(a, 'bar')          # 获取属性 bar 值
setattr(a, 'bar', 5)       # 设置属性 bar 值
a.bar
Out[2]: 5



__getattr__方法

拦截点号运算。当对未定义的属性名称和实例进行点号运算时,就会用属性名作为字符串调用这个方法。如果继承树可以找到该属性,则不调用此方法

[python]  view plain  copy
  1. class empty:  
  2.     def__getattr__(self, attrname):  
  3.         ifattrname =="age":  
  4.             return40  
  5.         else:  
  6.             raiseAttributeError, attrname  
  7.    
  8. x =empty()  
  9. print(x.age)       #40  
  10. print(x.name)      #error text omitted.....AttributeError, name  

这里empty类和实例x并没有属性age,所以执行x.age时,就会调用__getattr__方法,对于name也是同样。

__setattr__方法

会拦截所有属性的的赋值语句。如果定义了这个方法,self.arrt = value 就会变成self,__setattr__("attr", value).这个需要注意。当在__setattr__方法内对属性进行赋值是,不可使用self.attr = value,因为他会再次调用self,__setattr__("attr", value),则会形成无穷递归循环,最后导致堆栈溢出异常。应该通过对属性字典做索引运算来赋值任何实例属性,也就是使用self.__dict__['name'] = value.

实现属性的私有化

[python]  view plain  copy
  1. class PrivateExc(Exception):  
  2.     pass  
  3.    
  4. class Privacy:  
  5.     def__setattr__(self, attrname, value):  
  6.         ifattrname inself.privates:  
  7.             raisePrivateExc(attrname, self)  
  8.         else:  
  9.             self.__dict__[attrname]= value  
  10.    
  11. classTest1(Privacy):  
  12.     privates= ["age"]  
  13.    
  14. classTest2(Privacy):  
  15.     privates= ["name","age"]  
  16.     def__init__(self):  
  17.         self.__dict__["name"]= "sun"  
  18.    
  19. x =Test1()  
  20. y =Test2()  
  21. x.name = "Tom"         #执行成功  
  22. x.age =20              #执行失败,产生异常,该属性在privates列表内  
  23. y.name = "Mike"        #执行失败,产生异常,该属性在privates列表内  
  24. y.age =20              #执行成功  

上述方式是python实现属性私有化的首选方式。



Python Class 对象或类型通过内置成员 __dict__ 来存储成员信息。

  我们还可以通过重载 __getattr__ 和 __setattr__ 来拦截对成员的访问,需要注意的是 __getattr__ 只有在访问不存在的成员时才会被调用。

>>> class Class1:
  def __getattr__(self, name):
    print "__getattr__"
    return None
  def __setattr__(self, name, value):
    print "__setattr__"
    self.__dict__[name] = value
    
>>> a = Class1()
>>> a.x
__getattr__
>>> a.x = 123
__setattr__
>>> a.x
123

  如果类型继承自 object,我们可以使用 __getattribute__ 来拦截所有(包括不存在的成员)的获取操作。

  注意在 __getattribute__ 中不要使用 "return self.__dict__[name]" 来返回结果,因为在访问 "self.__dict__" 时同样会被 __getattribute__ 拦截,从而造成无限递归形成死循环。

>>> class Class1(object):
  def __getattribute__(self, name):
    print "__getattribute__"
    return object.__getattribute__(self, name)
  
>>> a = Class1()
>>> a.x
__getattribute__
Traceback (most recent call last):
 File "<pyshell#3>", line 1, in <module>
 a.x
 File "<pyshell#1>", line 4, in __getattribute__
 return object.__getattribute__(self, name)
AttributeError: 'Class1' object has no attribute 'x'
>>> a.x = 123
>>> a.x
__getattribute__
123




<think>我们被要求回答关于Python中快速生成私有属性的getset方法的问题。根据引用,我们知道在Python中,私有属性通常以双下划线开头(如`__name`),并且我们可以通过定义getset方法来访问修改这些属性。 然而,手动为每个私有属性编写getset方法可能会很繁琐。因此,我们可以利用一些工具或技巧来快速生成这些方法。 在Python中,有几种方式可以快速生成getset方法: 1. 使用属性(property)装饰器:这是一种Pythonic的方式,通过内置的`@property`装饰器来定义get方法,用`@属性名.setter`定义set方法。这样,我们可以像访问属性一样调用方法,同时可以在setter中加入验证逻辑。 2. 使用IDE的自动生成功能:许多集成开发环境(如PyCharm)提供了自动生成gettersetter的功能。通常,在定义好私有属性后,可以在代码编辑器中右键选择生成(Generate)然后选择gettersetter。 3. 使用元类或类装饰器:我们可以编写一个类装饰器或者元类,自动为类中的私有属性生成getset方法。这种方式需要一定的元编程知识,但可以实现一次编写,多次使用。 4. 使用第三方库:例如,`pyfields`库可以简化属性的定义,包括gettersetter。 由于问题要求“快速生成”,我们重点介绍前两种方法方法一:使用property装饰器 示例: ```python class Person: def __init__(self, name): self.__name = name # 私有属性 @property def name(self): """Getter for name""" return self.__name @name.setter def name(self, value): """Setter for name""" if not isinstance(value, str): raise TypeError("Name must be a string") self.__name = value ``` 这样,我们可以通过`p = Person('Alice')`创建对象,然后通过`p.name`来获取设置属性(例如`p.name = 'Bob'`),同时设置时会进行类型检查。 方法二:使用IDE自动生成(以PyCharm为例) 步骤: 1. 在类中定义私有属性,例如`__name`。 2. 在编辑器中右键点击,选择“Generate”(或使用快捷键Alt+Insert)。 3. 选择“Getter and Setter”。 4. 选择要生成gettersetter的属性。 这样,IDE会自动生成类似上面的property代码。 另外,如果我们有多个私有属性,并且希望快速为它们生成getset方法,我们可以考虑使用一个类装饰器来自动完成。下面是一个简单的示例: ```python def auto_props(*props): """类装饰器,为指定的私有属性生成property""" def decorator(cls): for prop in props: # 为每个属性创建gettersetter private_name = f"__{prop}" # 私有属性名 # 定义getter def getter(self, prop_name=prop): return getattr(self, f"__{prop_name}") # 定义setter def setter(self, value, prop_name=prop): setattr(self, f"__{prop_name}", value) # 创建property并设置到类中 setattr(cls, prop, property(getter, setter)) return cls return decorator # 使用类装饰器 @auto_props('name', 'age') class Person: def __init__(self, name, age): self.__name = name self.__age = age # 现在,我们可以直接使用属性名访问 p = Person('Alice', 30) print(p.name) # 输出: Alice p.name = 'Bob' print(p.name) # 输出: Bob ``` 注意:上面的装饰器示例是一个简化版本,它没有包含验证逻辑。如果需要验证,可以在setter函数中加入。 总结: 在Python中,快速生成私有属性的getset方法,推荐使用property装饰器或者IDE的自动生成功能。对于需要大量重复生成的情况,可以考虑使用类装饰器或元类来自动化。 注意:虽然我们可以使用自动生成的方式,但过度使用getset方法可能不符合Python的风格。在Python中,通常我们更倾向于直接访问属性,除非在需要额外处理(如验证)的时候才使用property。 §§相关问题§§ 1. 在Python中,使用property装饰器有哪些优势? 2. 除了property,还有哪些方式可以管理类的属性访问? 3. 如何为多个私有属性批量生成getset方法?</think>### Python中快速生成私有属性的getset方法Python中,私有属性通常以双下划线开头(如`__name`),通过以下方法可快速生成对应的getset方法: #### 方法1:使用`@property`装饰器(推荐) ```python class Student: def __init__(self, name): self.__name = name # 私有属性 @property def name(self): # getter方法 return self.__name @name.setter def name(self, value): # setter方法 if not isinstance(value, str): raise TypeError("姓名必须是字符串") self.__name = value # 使用示例 s = Student("张三") print(s.name) # 自动调用getter → 输出"张三" s.name = "李四" # 自动调用setter print(s.name) # 输出"李四" ``` #### 方法2:使用IDE自动生成(以PyCharm为例) 1. 定义私有属性:`self.__age = age` 2. 右键点击属性 → **Generate** → **Getter and Setter** 3. 选择需要生成方法属性 4. IDE自动生成模板代码: ```python @property def age(self): return self.__age @age.setter def age(self, value): self.__age = value ``` #### 方法3:自定义装饰器(批量生成) ```python def auto_property(*names): def decorator(cls): for name in names: private_name = f"__{name}" # 自动生成getter def getter(self, n=name): return getattr(self, f"__{n}") # 自动生成setter def setter(self, value, n=name): setattr(self, f"__{n}", value) # 绑定到类 setattr(cls, name, property(getter, setter)) return cls return decorator # 使用示例 @auto_property("score", "grade") class Exam: def __init__(self): self.__score = 0 self.__grade = "A" e = Exam() e.score = 90 # 自动调用setter print(e.grade) # 自动调用getter → 输出"A" ``` #### 关键优势 1. **数据验证**:可在setter中加入类型检查(如`if not isinstance(value, int)`)[^4][^5] 2. **封装性**:外部无法直接访问`__private`属性,防止意外修改[^1] 3. **灵活性**:可添加额外逻辑(如修改属性时触发事件) 4. **兼容性**:保持类接口简洁(`obj.name`而非`obj.get_name()`)[^3] > 提示:Python的私有属性本质是名称改写(name mangling),实际仍可通过`_ClassName__attr`访问,getter/setter主要提供规范的访问接口[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值