gpt4 book ai didi

python-2.7 - Python继承和__getattr__和__getattribute__

转载 作者:行者123 更新时间:2023-12-01 01:20:03 25 4
gpt4 key购买 nike

我整天都为此奋斗,并做了很多Google搜索。我遇到的似乎是继承问题。

我有一个名为BaseClass的类,该类为我做一些简单的事情,例如设置日志记录默认值,保存日志和管理只读属性。过去,此类没有问题,但是我可以说我只使用python几个月了。此外,我认为有几个警告很重要:


过去的所有继承都是单一继承。换句话说,我已经继承了BaseClass,但是继承了BaseClass的类则没有被另一个类继承。在今天的问题中,我将BaseClass继承到BaseFormData中,然后将其继承到July2013FormData中,再将其继承到Jan2014FormData中。因此,显然现在有更多层。
我没有尝试在过去继承了BaseClass的任何类中覆盖__getattr____getattribute__。今天是。 BaseClass拥有自己的__getattribute__方法,以管理只读属性的获取。 BaseFormData类具有__getattr__方法,因为我读过这是提供对数据的访问的正确方法,而不必显式声明所有属性。正在加载的表单数据中包含十几个或更多数据(取决于版本),因此我明确声明了一些重要或别名的属性,而其余属性则由__getattr__处理。


这是BaseClass中的__getattribute__

def __getattribute__(self, attr):
try:
# Default behaviour
return object.__getattribute__(self, attr)
except:
try:
return self.__READ_ONLY[attr]
except KeyError:
lcAttr = php_basic_str.strtolower(attr)
return self._raw[lcAttr]


使用 self._raw的行仅是因为继承BaseClass的类经常使用 _raw。没有BaseClass要求的 _raw。理想情况下,对 _raw的引用只能出现在继承类的 __getattr____getattribute__中。但是,我需要在BaseClass中使用 __getattribute__才能使只读功能正常工作。

和来自BaseFormData的 __getattr__

def __getattr__(self, name):
"""
Return a particular piece of data from the _raw dict
"""

# All the columns are saved in lowercase
lcName = s.strtolower(name)

try:
tmp = self._raw[lcName]
except KeyError:
try:
tmp = super(BaseFormData, self).__getattribute__(name)
except KeyError:
msg = "'{0}' object has no attribute '{1}'. Note that attribute search is case insensitive."
raise AttributeError(msg.format(type(self).__name__, name))

if tmp == 'true':
return True
elif tmp == 'false':
return False
else:
return tmp


这是我收到的错误:

File "D:\python\lib\mybasics\mybasics\cBaseClass.py", line 195, in __getattribute__
return self.__READ_ONLY[attr]

RuntimeError: maximum recursion depth exceeded while calling a Python object


简短的版本是我整天都为此奋斗,因为在这里或那里进行了调整,我得到了不同的响应。大多数时候,从未调用BaseFormData中的 __getattr__。其他时间我收到此递归错误。其他时间我可以使它工作,但是随后我添加了一些小东西,一切都再次中断了。

关于继承以及 __getattribute____getattr__的调用顺序,我显然缺少一些东西。今天,我已经做了很多代码调整,如果有内存可用的话,我在BaseFormData和BaseClass中都不会有 __getattribute__,但是我不记得这个错误。

我猜想递归问题源于 __getattr__中的这一行:

tmp = super(BaseFormData, self).__getattribute__(name)


显然,我要执行的操作是先查看当前类,然后转到BaseClass __getattribute__以检查“只读”属性。

任何帮助是极大的赞赏。

-----------一些调整的结果.... -----------

所以我将BaseFormClass __getattr__更改为 __getattribute__,它似乎在BaseClass的 __getattribute__之前运行,这很有意义。

但是,它导致了无限递归,我认为这可能是由于某些事情在BaseFormClass的 __init__和BaseFormClass的子类中发生的顺序所致。然后似乎是由于创建__READ_ONLY太晚了,我也修复了该问题。

最终, _raw在子类中不在BaseClass中,因此我在BaseClass的 _raw中删除​​了对 _getattribute__的任何引用。我接受了rchang关于将自我更改为对象的建议,这对BaseClass的 __getattribute__有所帮助,但似乎在BaseFormData的问题中引起了问题。我已经使用以下代码从解释器中获取了“ get”部分:

BaseClass:

def __getattribute__(self, attr):
try:
# Default behaviour
return object.__getattribute__(self, attr)
except:
return self.__READ_ONLY[attr]


BaseFormClass:

def __getattribute__(self, name):
# All the columns are saved in lowercase
lcName = s.strtolower(name)

try:
# Default behaviour
return object.__getattribute__(self, name)
except:
try:
tmp = object.__getattribute__(self, '_raw')[lcName]
except KeyError:
try:
tmp = BaseClass.__getattribute__(self, name)
except KeyError:
msg = "'{0}' object has no attribute '{1}'. Note that attribute search is case insensitive."
raise AttributeError(msg.format(type(self).__name__, name))

if tmp == 'true':
return True
elif tmp == 'false':
return False
else:
return tmp


具有讽刺意味的是,这却造成了另一个 __getattribute__问题。当我尝试覆盖只读属性时,将触发日志警告,但随后在调用 self.__instanceId时失败。昨天该日志警告正常运行(当我可以使类实例化而没有错误时)。我可以像这样实例化该类:

a = Jan2014Lead(leadFile)


并获得实例ID,如下所示:

a.__instanceId
Out[7]: '8c08dee80ef56b1234fc4822627febfc'


这是实际的错误:

File "D:\python\lib\mybasics\mybasics\cBaseClass.py", line 255, in write2log
logStr = "[" + self.__instanceId + "]::[" + str(msgCode) + "]::" + msgMsg

File "cBaseFormData.py", line 226, in __getattribute__
raise AttributeError(msg.format(type(self).__name__, name))

AttributeError: 'Jan2014Lead' object has no attribute '_BaseClass__instanceId'. Note that attribute search is case insensitive.


-----------可以正常使用,但看起来有点笨拙。...-----------

因此,以上错误是由于在_READ_ONLY中查找_BaseClass__instanceId而在_READ_ONLY中查找了__instanceId。因此,我只是简单地修剪了传递的attr字符串,以从一开始就删除_BaseClass。

不过,这似乎是一个hack。有标准的方法吗?

最佳答案

我认为您遇到了无限递归,因为__getattribute__试图直接查找self的属性,因此导致__getattribute__在除块之外的那些地方调用自身。看到这样的问题:
How is the __getattribute__ method used?

也许尝试以下方法(将与您在try块中使用的object.__getattribute__相同的技术也扩展到except块)?

def __getattribute__(self, attr):
try:
# Default behaviour
return object.__getattribute__(self, attr)
except:
try:
# return self.__READ_ONLY[attr]
return object.__getattribute__(self, __READ_ONLY)[attr]
except KeyError:
lcAttr = php_basic_str.strtolower(attr)
# return self._raw[lcAttr]
return object.__getattribute__(self, _raw)[lcAttr]

关于python-2.7 - Python继承和__getattr__和__getattribute__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27265009/

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