gpt4 book ai didi

python 嵌套属性封装

转载 作者:太空宇宙 更新时间:2023-11-03 17:32:46 24 4
gpt4 key购买 nike

我对 python 中的封装嵌套属性有一些疑问。让我们假设几个类:这里我们有一个主类(DataWrapper),其中还包括两个类:InnerWrapper1 和 InnerWrapper2。两个内部包装器都包含两个属性。

class DataWrapper(object):     
@property
def inner_wrapper1(self):
return self.__inner_wrapper1
@inner_wrapper1.setter
def inner_wrapper1(self, value):
self.__inner_wrapper1 = value

@property
def inner_wrapper2(self):
return self.__inner_wrapper2
@inner_wrapper2.setter
def inner_wrapper2(self, value):
self.__inner_wrapper2 = value

class InnerWrapper1(object):
@property
def property1(self):
return self.__property1
@property1.setter
def property1(self, value):
self.__property1 = value

@property
def property2(self):
return self.__property2
@property2.setter
def property2(self, value):
self.__property2 = value

class InnerWrapper2(object):
@property
def property3(self):
return self.__property3
@property3.setter
def property3(self, value):
self.__property3 = value

@property
def property4(self):
return self.__property4
@property4.setter
def property4(self, value):
self.__property4 = value

是否可以以某种方式重写 getattrsetattr 方法以实现以下封装?我想要实现的是从顶级类 DataWrapper 访问这些嵌套属性。

data_wrapper = DataWrapper()
data_wrapper.property1 = "abc"
...
var = data_wrapper.property2
...

我想到的第一件事是在 getattr 中执行 hasattr,但这给出了最大递归深度......

这是完整的代码:

class DataWrapper(object):

def __init__(self):
self.inner_wrapper1 = InnerWrapper1()
self.inner_wrapper2 = InnerWrapper2()

@property
def inner_wrapper1(self):
return self.__inner_wrapper1
@inner_wrapper1.setter
def inner_wrapper1(self, value):
self.__inner_wrapper1 = value

@property
def inner_wrapper2(self):
return self.__inner_wrapper2
@inner_wrapper2.setter
def inner_wrapper2(self, value):
self.__inner_wrapper2 = value

def __setattr__(self, attribute, value):
#if attribute in {'innerwrapper1', 'innerwrapper2'}:
if attribute in ['inner_wrapper1', 'inner_wrapper2']:
return super(DataWrapper, self).__setattr__(attribute, value)
if hasattr(self.inner_wrapper1, attribute):
return setattr(self.inner_wrapper1, attribute, value)
elif hasattr(self.inner_wrapper2, attribute):
return setattr(self.inner_wrapper2, attribute, value)



def __getattr__(self, attribute):
try:
return getattr(self.inner_wrapper1, attribute)
except AttributeError: pass

try:
return getattr(self.inner_wrapper2, attribute)
except AttributeError: pass

class InnerWrapper1(object):
@property
def property1(self):
return self.__property1
@property1.setter
def property1(self, value):
self.__property1 = value

@property
def property2(self):
return self.__property2
@property2.setter
def property2(self, value):
self.__property2 = value

class InnerWrapper2(object):
@property
def property3(self):
return self.__property3
@property3.setter
def property3(self, value):
self.__property3 = value

@property
def property4(self):
return self.__property4
@property4.setter
def property4(self, value):
self.__property4 = value

def main():
data_wrapper = DataWrapper()
data_wrapper.property1 = "abc"

if __name__ == "__main__":
main()

最佳答案

您收到无限递归错误,因为您忘记考虑在 __init__ 方法中设置 inner_wrapper1inner_wrapper2 属性。

当你这样做时:

self.inner_wrapper1 = InnerWrapper()

Python也会使用您的__setattr__方法。然后尝试使用尚不存在的 self.inner_wrapper1 ,因此调用 __getattr__ ,它尝试使用不存在的 self.inner_wrapper1 t 尚未存在,并且您进入无限递归循环。

__setattr__中将属性设置委托(delegate)给父类(super class):

def __setattr__(self, attribute, value):
if attribute in {'innerwrapper1', 'innerwrapper2'}:
return super(DataWrapper, self).__setattr__(attribute, value)
if hasattr(self.inner_wrapper1, attribute):
return setattr(self.inner_wrapper1, attribute, value)
elif hasattr(self.inner_wrapper2, attribute):
return setattr(self.inner_wrapper2, attribute, value)

如果您对“私有(private)”属性使用了一个前导下划线(例如 _innerwrapper1_innerwrapper2),您只需测试一下即可:

def __setattr__(self, attribute, value):
if attribute[0] == '_': # private attribute
return super(DataWrapper, self).__setattr__(attribute, value)

因此您不必对一整套名称进行硬编码。

由于您更新的完整脚本使用 __inner_wrapper1__inner_wrapper2 作为实际属性名称,并且您正在使用属性,因此您必须调整您的 __setattr__ 测试来查找那些名称。因为您使用的是双下划线名称,所以需要调整 name mangling of such attributes :

def __setattr__(self, attribute, value):
if attribute in {
'inner_wrapper1', 'inner_wrapper2',
'_DataWrapper__inner_wrapper1', '_DataWrapper__inner_wrapper2'}:
return super(DataWrapper, self).__setattr__(attribute, value)

除非您要子类化 DataWrapper 并且必须保护您的属性免遭意外覆盖,否则我会完全避免使用双下划线名称。在Pythonic代码中,您不必担心其他代码访问属性,不存在真正私有(private)属性的概念。

在这里使用属性也有点过分了;属性并不能为您带来封装,在 Python 中您只能使用它们来简化 API(用属性访问替换方法调用)。

请注意,hasattr()InnerWrapper* property* 属性的测试将失败,因为您不这样做没有默认值:

>>> inner = InnerWrapper1()
>>> hasattr(inner, 'property1')
False

hasattr() 不测试属性,它只是尝试访问属性,如果引发任何异常,则返回False :

>>> inner = InnerWrapper1()
>>> hasattr(inner, 'property1')
False
>>> inner.property1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 43, in property1
AttributeError: 'InnerWrapper1' object has no attribute '_InnerWrapper1__property1'
>>> inner.property1 = 'foo'
>>> inner.property1
'foo'
>>> hasattr(inner, 'property1')
True

通过删除所有 @property 对象,您可以大大简化此操作:

class DataWrapper(object):
def __init__(self):
self._inner_wrapper1 = InnerWrapper1()
self._inner_wrapper2 = InnerWrapper2()

def __setattr__(self, attribute, value):
if attribute[0] == '_':
return super(DataWrapper, self).__setattr__(attribute, value)
if hasattr(self._inner_wrapper1, attribute):
return setattr(self._inner_wrapper1, attribute, value)
elif hasattr(self._inner_wrapper2, attribute):
return setattr(self._inner_wrapper2, attribute, value)

def __getattr__(self, attribute):
try:
return getattr(self._inner_wrapper1, attribute)
except AttributeError: pass
return getattr(self._inner_wrapper2, attribute)

class InnerWrapper1(object):
property1 = None
property2 = None

class InnerWrapper2(object):
property3 = None
property4 = None

关于python 嵌套属性封装,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31649871/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com