Python 2.7 Python继承和getattr&__getattribute__
我整天都在与这个问题斗争,并且做了大量的谷歌搜索。我似乎有遗传问题 我有一个名为BaseClass的类,它为我做一些简单的事情,比如设置日志默认值、保存日志和管理只读属性。在过去,我对这个类没有任何问题,但我可以说我现在只使用python几个月了。此外,我认为有几个重要的注意事项:Python 2.7 Python继承和getattr&__getattribute__,python-2.7,inheritance,getattr,getattribute,Python 2.7,Inheritance,Getattr,Getattribute,我整天都在与这个问题斗争,并且做了大量的谷歌搜索。我似乎有遗传问题 我有一个名为BaseClass的类,它为我做一些简单的事情,比如设置日志默认值、保存日志和管理只读属性。在过去,我对这个类没有任何问题,但我可以说我现在只使用python几个月了。此外,我认为有几个重要的注意事项: 过去的所有继承都是单一继承。换句话说,我继承了基类,但是继承基类的类不会被另一个类继承。在今天的问题中,我将基类继承到BaseFormData中,然后将其继承到2013年7月的FormData中,然后将其继承到201
\uuuuu getattr\uuuuuuu
或\uuuuuu getattribute\uuuuuuu
。今天我是。基类有一个自己的\uuuu getattribute\uuu
方法来管理只读属性的获取。BaseFormData类有一个\uuu getattr\uuu
方法,因为我知道这是一种提供数据访问的正确方法,而不必显式声明所有属性。正在加载的表单数据中有十几条或更多的数据(取决于版本),因此我显式声明了一些重要的或有别名的属性,而剩下的由\uuuu getattr\uuuu
处理\uuuuu getattribute\uuuuu
:
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]
def __getattribute__(self, attr):
try:
# Default behaviour
return object.__getattribute__(self, attr)
except:
return self.__READ_ONLY[attr]
使用self.\u raw
的行之所以存在,完全是因为继承基类的类经常使用\u raw
。基类不需要\u raw
。理想情况下,对\u raw
的引用只会出现在继承类的\u getattr\u
或\u getattribute\u
中。但是,我需要在基类中使用\uuu getattribute\uu
,以便使只读功能正常工作
以及BaseFormData中的\uuuu getattr\uuuu
:
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中的\uuu getattr\uuu
从未被调用。其他时候,我得到这个递归错误。其他时候,我可以让它工作,但后来我添加了一些小东西,一切又打破了
关于继承和调用\uu getattribute\uuu
和\uu getattr\uu
的顺序,我显然缺少一些东西。我今天对代码做了很多调整,如果内存可用,我就不能在BaseFormData和BaseClass中使用\uu getattribute\uuuu
,但我记不起这个错误了
我猜递归问题源于\uu getattr\uu
中的这一行:
tmp = super(BaseFormData, self).__getattribute__(name)
显然,我要做的是首先查看当前类,然后转到基类\uuu getattribute\uuu
,以检查只读属性
非常感谢您的帮助
-----------一些调整的结果-----------
因此,我将BaseFormClass的\uuuuuuGetAttr\uuuuuuuu
更改为\uuuuuuuuGetAttribute\uuuuuuuuu
,并且它似乎在基类的\uuuuuuGetAttribute\uuuuuuuuuuuuuuuuuuuuuuuu
之前运行,这是有意义的
然而,它导致了无限递归,我认为这可能是由于BaseFormClass的\uuuu init\uuu
和BaseFormClass的子类中发生的某些事情的顺序造成的。然后,它似乎是由于uuu READ u创建得太晚了,我也解决了这个问题
最后,\u raw
在子类中,而不是在基类中,因此我删除了基类的\u getattribute\uu
中对\u raw
的任何引用。我接受了rchang关于将self更改为object的建议,这对BaseClass的\uuu getattribute\uuuu
有所帮助,但似乎在BaseFormData中引起了问题。我已经从解释器获得了“get”部分,代码如下:
基类:
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]
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
def __getattribute__(self, name):
# All the columns are saved in lowercase
lcName = s.strtolower(name)
try:
# Default behaviour
return object.__getattribute__(self, name)
except:
name = s.str_replace('_' + type(self).__name__, '', name)
lcName = s.strtolower(name)
try:
tmp = object.__getattribute__(self, '_raw')[lcName]
except KeyError:
#tmp = BaseClass.__getattribute__(self, name)
tmp = super(BaseFormData, self).__getattribute__(name)
if tmp == 'true':
return True
elif tmp == 'false':
return False
else:
return tmp
讽刺的是,这又产生了另一个问题。当我试图覆盖只读属性时,会触发日志警告,但在调用self.\uu instanceId
时失败。这个日志警告昨天运行得很好(当我可以让类无误地实例化时)。我可以这样实例化这个类:
a = Jan2014Lead(leadFile)
a.__instanceId
Out[7]: '8c08dee80ef56b1234fc4822627febfc'
并按如下方式获取实例ID:
a = Jan2014Lead(leadFile)
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.
-----------让它工作,但似乎黑客-----------
因此,上面的错误是在只读中查找BaseClass uuuuu instanceId,但是uuu instanceId在只读中。因此,我简单地修剪了传递的attr字符串,以便从一开始就删除_基类
这看起来像是一个黑客。有没有一种标准的方法可以做到这一点?我认为您遇到的是无限递归,因为
\uuuuu getattribute\uuuu
试图直接查找self的属性,因此导致\uuu getattribute\uuuuu
在那些块之外的块中调用自己。见本问题:
也许可以尝试以下操作(只需使用对象将您在try块中使用的相同技术扩展到except块即可)
我不能说我已经完全解决了这个问题。但是,基类\uuu getattirbute\uuu
方法需要更改调用对象的顺序:
def __getattribute__(self, attr):
if attr in self.__READ_ONLY:
return self.__READ_ONLY[attr]
else:
# Default behaviour
return object.__getattribute__(self, attr)
然后,我需要对BaseFormClass中的\uuuu getattribute\uuuu
进行另一个更改:
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
def __getattribute__(self, name):
# All the columns are saved in lowercase
lcName = s.strtolower(name)
try:
# Default behaviour
return object.__getattribute__(self, name)
except:
name = s.str_replace('_' + type(self).__name__, '', name)
lcName = s.strtolower(name)
try:
tmp = object.__getattribute__(self, '_raw')[lcName]
except KeyError:
#tmp = BaseClass.__getattribute__(self, name)
tmp = super(BaseFormData, self).__getattribute__(name)
if tmp == 'true':
return True
elif tmp == 'false':
return False
else:
return tmp
这里实际上只有两个变化。简单的一点是,首先,我删除了raise,让基类处理它。更难描述的更改是我使用s.str\u replace
去掉类名的更改。如果没有这一行,Python通常会寻找