程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

When__ getattr__ () when you meet @property, you fall down with the old Python driver

編輯:Python

Today, my colleagues reported that a basic library I wrote has a bug, It's probably that the class you wrote clearly has attributes foo, But it will throw an exception like the one below ,

AttributeError: 'A' object has no attribute 'foo'

This is very confusing , Because the function that throws the exception is of the base class __getattr__() Method , So he asked me to solve it .

I think the code is also confused , This foo Right there , This bug It gave me an illusion that seeing is not believing , I can't find the direction for a moment . Suddenly I found this foo There is one on top @property The hat of ( Decorator ), Why , Is it related to this ? So search for , I found this article Correct handling of AttributeError in __getattr__ when using property, The high praise answer above perfectly answers this question . Let me take this question and answer code as an example , In this way, you can only read my article .

First of all, there is such code , This code is purely for example , There is no logical meaning ,

class A:
@property
def F(self):
return self.moo # here should be an error
@property
def G(self):
return self.F
def __getattr__(self, name):
print('call of __getattr__ with name =', name)
if name == 'foo':
return 0
raise AttributeError("'{}' object has no attribute '{}'".format(type(self).__name__, name))
a = A()
print(a.G)

apparently , You will think that the exception thrown is AttributeError: 'A' object has no attribute 'moo', But the exception actually thrown is AttributeError: 'A' object has no attribute 'G' And the stack that spits out is like this :

Traceback (most recent call last):
line 18 in <module>
print(a.G)
line 15, in __getattr__
raise AttributeError("'{}' object has no attribute '{}'".format(type(self).__name__, name))
AttributeError: 'A' object has no attribute 'G'

As __getattr__() The author of , It's really annoying .

Abate one's breath , So why __getattr__() Will the front AtrributeError Abnormally eaten ? This is to review __getatrr__() When to call , The document says :

Called when the default attribute access fails with an AttributeError (either __getattribute__() raises an AttributeError because name is not an instance attribute or an attribute in the class tree for self; or __get__() of a name property raises AttributeError).

Simply speaking , When looking for attributes ,Python Will call first __getattribute__(), If you can't find it ( Throw out AtrributeError abnormal ), Will try to call __getattr__(). Another situation is if property Of __get__() Method throw AttributeError When abnormal , Will also try to call __getattr__().

So back to the above example , Use @property The decorated member function becomes a descriptor descriptor, When accessing it , What is actually called is the descriptor __get__() Method , obviously ,print(a.G) First called. a.G.__get__, Then it calls a.F.__get__, This method refers to self.moo, because moo Property does not exist , Just throw it out AtrributeError. According to the description of the above document , This will call a Of __getattr__() Method , According to the code above , This __getattr__() It will also be thrown out AtrributeError, therefore Python Just eat the previous exception , It only shows the abnormality that the cow's head is not right behind the horse's mouth .

In this case , That is to be in __get__() Throw out AtrributeError When catching abnormal , Rather than by Python To deal with . To achieve this , In this example and the code of our project , Are overloaded __getatrribute__() instead of __getattr__(). Modify the above code as follows :

class A:
@property
def F(self):
return self.moo # here should be an error
@property
def G(self):
return self.F
def __getattribute__(self, name):
print('call of __getattribute__ with name =', name)
if name == 'foo':
return 0
else:
return super().__getattribute__(name)

When it's executed again , You will find that the thrown exception meets your expectations :

Traceback (most recent call last):
...
AttributeError: 'A' object has no attribute 'moo'

And after our project made the same changes , It also solved the problem . This accident tells us , Don't overload easily __getattr__().


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved