- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我是 a simple database layer 的作者——目前几乎肯定是唯一的用户,如果在多个项目中的话—— (灵感来自 minimongo )用于名为 kale
的 MongoDB。我目前在模型的基类中使用 __getattr__
导致了一些难以跟踪的错误。
我遇到的问题was articulated去年 6 月,David Halter 在本网站上简明扼要地说明了这一点。讨论很有趣,但是没有提供解决方案。
简而言之:
>>> class A(object):
... @property
... def a(self):
... print "We're here -> attribute lookup found 'a' in one of the usual places!"
... raise AttributeError
... return "a"
...
... def __getattr__(self, name):
... print "We're here -> attribute lookup has not found the attribute in the usual places!"
... print('attr: ', name)
... return "not a"
...
>>> print(A().a)
We're here -> attribute lookup found 'a' in one of the usual places!
We're here -> attribute lookup has not found the attribute in the usual places!
('attr: ', 'a')
not a
>>>
请注意,这种矛盾的行为不是我阅读 the official python documentation 时所期望的。 :
object.__getattr__(self, name)
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name.
(如果他们提到 AttributeError
是“属性查找”知道是否在“通常位置”找到属性的方法,那就太好了。澄清括号似乎我充其量是不完整的。)
在实践中,无论何时在 @property
描述符事物中引发 AttributeError,这都会导致跟踪由编程错误引起的错误的问题。
>>> class MessedAttrMesser(object):
... things = {
... 'one': 0,
... 'two': 1,
... }
...
... def __getattr__(self, attr):
... try:
... return self.things[attr]
... except KeyError as e:
... raise AttributeError(e)
...
... @property
... def get_thing_three(self):
... return self.three
...
>>>
>>> blah = MessedAttrMesser()
>>> print(blah.one)
0
>>> print(blah.two)
1
>>> print(blah.get_thing_three)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in __getattr__
AttributeError: 'get_thing_three'
>>>
在这种情况下,通过检查整个类很明显发生了什么。但是,如果您依赖于来自堆栈跟踪的消息,AttributeError: 'get_thing_three'
,它就没有意义,因为很明显,get_thing_three
看起来是一个有效的属性当他们来的时候。
kale
的目的是为构建模型提供一个基类。因此,基本模型代码对最终程序员是隐藏的,并且像这样掩盖错误的原因并不理想。
最终程序员(咳咳我)可能会选择在他们的模型上使用@property
描述符,并且他们的代码应该可以并且失败他们期望的方式。
问题
如何允许 AttributeError
传播到定义了 __getattr__
的基类?
最佳答案
基本上,您不能 --- 或者至少不能以简单且万无一失的方式。如您所述,AttributeError
是 Python 用来确定属性是否“在通常位置找到”的机制。尽管 __getattr__
文档没有提到这一点,但在 __getattribute__
的文档中已经说得更清楚了,如 this answer 中所述。到您已经链接到的问题。
您可以覆盖 __getattribute__
并在那里捕获 AttributeError
,但是如果您捕获了一个错误,您将没有明显的方法来判断它是否是一个“真正的”错误(意味着确实没有找到该属性),或者在查找过程中用户代码引发的错误。理论上,您可以检查回溯以寻找特定的东西,或者进行各种其他黑客攻击来尝试验证属性的存在,但这些方法将比现有行为更加脆弱和危险。
另一种可能性是编写您自己的基于 property
的描述符,但会捕获 AttributeErrors 并将它们重新引发为其他内容。但是,这将要求您使用此属性替换而不是内置 property
。此外,这意味着从描述符方法内部引发的 AttributeErrors 不会作为 AttributeErrors 传播,而是作为其他东西传播(无论你用什么替换它们)。这是一个例子:
class MyProp(property):
def __get__(self, obj, cls):
try:
return super(MyProp, self).__get__(obj, cls)
except AttributeError:
raise ValueError, "Property raised AttributeError"
class A(object):
@MyProp
def a(self):
print "We're here -> attribute lookup found 'a' in one of the usual places!"
raise AttributeError
return "a"
def __getattr__(self, name):
print "We're here -> attribute lookup has not found the attribute in the usual places!"
print('attr: ', name)
return "not a"
>>> A().a
We're here -> attribute lookup found 'a' in one of the usual places!
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
A().a
File "<pyshell#6>", line 6, in __get__
raise ValueError, "Property raised AttributeError"
ValueError: Property raised AttributeError
这里 AttributeErrors 被 ValueErrors 代替。如果您只想确保异常“突破”属性访问机制并且可以传播到下一个级别,那么这可能没问题。但是,如果您有复杂的异常捕获代码并希望看到 AttributeError,它将错过此错误,因为异常类型已更改。
(此外,这个例子显然只处理属性 getter,不处理 setter,但应该清楚如何扩展这个想法。)
我想作为此解决方案的扩展,您可以将此 MyProp
想法与自定义 __getattribute__
结合起来。基本上,您可以定义一个自定义异常类,例如 PropertyAttributeError
,并将属性替换重新引发 AttributeError 作为 PropertyAttributeError。然后,在您的自定义 __getattribute__
中,您可以捕获 PropertyAttributeError 并将其重新引发为 AttributeError。基本上 MyProp
和 __getattribute__
可以充当“分流器”,通过将错误从 AttributeError 转换为其他内容,然后再次将其转换回 AttributeError 来绕过 Python 的正常处理一旦这样做是“安全的”。但是,我觉得这样做不值得,因为 __getattribute__
会对性能产生重大影响。
一个小附录:a bug已经在 Python 错误跟踪器上提出了这个问题,并且最近有关于可能解决方案的事件,所以它可能会在未来的版本中得到修复。
关于python - 使用 __getattr__ 并满足子类的预期行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15401180/
我对java有点陌生,所以如果我犯了一个简单的错误,请原谅我,但我不确定我哪里出错了,我收到的错误是“预期的.class,预期的标识符,而不是声明, ';'预期的。”我尝试了不同的方法,并从这些方法中
This question already has answers here: chai test array equality doesn't work as expected (3个答案) 3年前
我正在学习 Java(对不起,我的英语很差,这不是我的母语),当我在 Eclipse (JavaSE-1.7) 中在我输入的每个“try”中执行“try-finally” block 时,会出现以下消
我收到两个错误,指出 token 上的语法错误,ConstructorHeaderName expected instead & token “(”上的语法错误,< expected 在线: mTM.
我找不到错误。 Eclipse 给我这个错误。每个 { } 都是匹配的。请帮忙。 Multiple markers at this line - Syntax error on token “)”,
代码: import java.awt.*; import javax.swing.*; import java.awt.event.*; public class DoubleIt extends
我正在用 python(Vs 代码)编写代码,但出现此错误: Expected ")" Pylance 错误发生在:def main() 我试着运行我的 main 并将它打印到我的屏幕上。我用谷歌搜
我正在尝试按照 documentation 中的建议使用异步函数。但我收到此错误 意外的 token ,预期 ( async function getMoviesFromApi() { try
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想改善这个问题吗?更新问题,以便将其作为on-topic
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想改善这个问题吗?更新问题,以便将其作为on-topic
第一行包含一个表示数组长度的整数p。第二行包含用空格分隔的整数,这些整数描述数组中的每个元素。第三行打印一个整数,指示负数组的数量。 package asgn3; import java.util.*
好的,我是初学者,我必须修复此 java 表达式语言代码才能在我的系统 (Windchill) 中工作,但看起来我在语法中遗漏了一些内容: LWCNormalizedObject lwc =
我无法编译我的程序! 我想我缺少一个花括号,但我怎么也看不出在哪里! import javax.swing.*; import java.awt.*;
我的 jQuery 代码有问题,我的 Firebug 向我发出警告:需要选择器。 这是代码: $("img[id$='_tick']").each(function() { $(this).c
我的新类(class) Fountainofyouth 遇到了问题。尝试构建整个项目后,调试器显示 warning: extended initializer lists only available
我已经从 Java 转向 CPP,并且正在努力围绕构造构造函数链进行思考,我认为这是我的问题的根源。 我的头文件如下: public: GuidedTour(); GuidedTour(string
鉴于以下 for(var i=0; i< data.cats.length; i++) list += buildCategories(data.cats[i]); jsLint 告诉我 Expect
我有这个 json,但 Visual Studio Code 在标题中给了我警告。 [ { "title": "Book A", "imageUrl": "https:
我正在尝试编写一个有条件地禁用四个特殊成员函数(复制构造、移动构造、复制赋值和移动赋值)的包装类,下面是我用于测试目的的快速草稿: enum class special_member : uint8_
所以我用 F# 编写了一个非常简单的程序,它应该对 1000 以下的所有 3 和 5 的倍数求和: [1..999] |> List.filter (fun x -> x % 3 = 0 || x %
我是一名优秀的程序员,十分优秀!