Python __getattr__ 与 __getattribute__ 之间的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3278077/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 09:23:25  来源:igfitidea点击:

Difference between __getattr__ vs __getattribute__

pythongetattrgetattribute

提问by Yarin

I am trying to understand when to use __getattr__or __getattribute__. The documentationmentions __getattribute__applies to new-style classes. What are new-style classes?

我试图了解何时使用__getattr____getattribute__。该文件提到了__getattribute__适用于新样式类。什么是新式班级?

采纳答案by Ned Batchelder

A key difference between __getattr__and __getattribute__is that __getattr__is only invoked if the attribute wasn't found the usual ways. It's good for implementing a fallback for missing attributes, and is probably the one of two you want.

之间的主要差异__getattr__,并__getattribute__是,__getattr__如果属性没有被发现通常的途径,只调用。这对于为缺少的属性实施回退很有用,并且可能是您想要的两个之一。

__getattribute__is invoked before looking at the actual attributes on the object, and so can be tricky to implement correctly. You can end up in infinite recursions very easily.

__getattribute__在查看对象的实际属性之前调用,因此正确实现可能会很棘手。您可以很容易地以无限递归结束。

New-style classes derive from object, old-style classes are those in Python 2.x with no explicit base class. But the distinction between old-style and new-style classes is not the important one when choosing between __getattr__and __getattribute__.

新式类派生自object,旧式类是 Python 2.x 中没有显式基类的类。但旧式和新式的类之间的区别并不之间进行选择时的重要的__getattr____getattribute__

You almost certainly want __getattr__.

你几乎肯定想要__getattr__

回答by Mr Fooz

New-style classes are ones that subclass "object" (directly or indirectly). They have a __new__class method in addition to __init__and have somewhat more rational low-level behavior.

新式类是将“对象”(直接或间接)子类化的类。它们还有一个__new__类方法,__init__并且具有更合理的低级行为。

Usually, you'll want to override __getattr__(if you're overriding either), otherwise you'll have a hard time supporting "self.foo" syntax within your methods.

通常,您会想要覆盖__getattr__(如果您要覆盖任何一个),否则您将很难在您的方法中支持“self.foo”语法。

Extra info: http://www.devx.com/opensource/Article/31482/0/page/4

额外信息:http: //www.devx.com/opensource/Article/31482/0/page/4

回答by Sam Dolan

New-style classes inherit from object, or from another new style class:

新样式类继承自object,或从另一个新样式类继承:

class SomeObject(object):
    pass

class SubObject(SomeObject):
    pass

Old-style classes don't:

旧式类不会:

class SomeObject:
    pass

This only applies to Python 2 - in Python 3 all the above will create new-style classes.

这仅适用于 Python 2 - 在 Python 3 中,以上所有内容都将创建新样式的类。

See 9. Classes(Python tutorial), NewClassVsClassicClassand What is the difference between old style and new style classes in Python?for details.

请参阅9. 类(Python 教程)、NewClassVsClassicClass和Python 中的旧样式和新样式类有什么区别?详情。

回答by Simon K Bhatta4ya

This is just an example based on Ned Batchelder's explanation.

这只是基于Ned Batchelder 解释的示例

__getattr__example:

__getattr__例子:

class Foo(object):
    def __getattr__(self, attr):
        print "looking up", attr
        value = 42
        self.__dict__[attr] = value
        return value

f = Foo()
print f.x 
#output >>> looking up x 42

f.x = 3
print f.x 
#output >>> 3

print ('__getattr__ sets a default value if undefeined OR __getattr__ to define how to handle attributes that are not found')

And if same example is used with __getattribute__You would get >>> RuntimeError: maximum recursion depth exceeded while calling a Python object

如果将相同的示例与__getattribute__您一起使用,您将获得 >>>RuntimeError: maximum recursion depth exceeded while calling a Python object

回答by N Randhawa

Lets see some simple examples of both __getattr__and __getattribute__magic methods.

让我们来看看两者的一些简单的例子__getattr____getattribute__魔术方法。

__getattr__

__getattr__

Python will call __getattr__method whenever you request an attribute that hasn't already been defined. In the following example my class Counthas no __getattr__method. Now in main when I try to access both obj1.myminand obj1.mymaxattributes everything works fine. But when I try to access obj1.mycurrentattribute -- Python gives me AttributeError: 'Count' object has no attribute 'mycurrent'

__getattr__每当您请求尚未定义的属性时,Python 都会调用 方法。在下面的例子中,我的类Count没有__getattr__方法。现在在 main 中,当我尝试访问两者obj1.myminobj1.mymax属性时,一切正常。但是当我尝试访问obj1.mycurrent属性时——Python 给了我AttributeError: 'Count' object has no attribute 'mycurrent'

class Count():
    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax

obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent)  --> AttributeError: 'Count' object has no attribute 'mycurrent'

Now my class Counthas __getattr__method. Now when I try to access obj1.mycurrentattribute -- python returns me whatever I have implemented in my __getattr__method. In my example whenever I try to call an attribute which doesn't exist, python creates that attribute and set it to integer value 0.

现在我的类Count__getattr__方法。现在,当我尝试访问 obj1.mycurrent属性时,python 会返回我在__getattr__方法中实现的任何内容。在我的示例中,每当我尝试调用一个不存在的属性时,python 都会创建该属性并将其设置为整数值 0。

class Count:
    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax    

    def __getattr__(self, item):
        self.__dict__[item]=0
        return 0

obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.mycurrent1)

__getattribute__

__getattribute__

Now lets see the __getattribute__method. If you have __getattribute__method in your class, python invokes this method for every attribute regardless whether it exists or not. So why we need __getattribute__method? One good reason is that you can prevent access to attributes and make them more secure as shown in the following example.

现在让我们看看__getattribute__方法。如果你__getattribute__的类中有 方法,python 会为每个属性调用这个方法,不管它是否存在。那么为什么我们需要__getattribute__方法呢?一个很好的理由是您可以阻止对属性的访问并使它们更安全,如以下示例所示。

Whenever someone try to access my attributes that starts with substring 'cur'python raises AttributeErrorexception. Otherwise it returns that attribute.

每当有人尝试访问我的以子字符串'cur'开头的属性时,python 都会引发AttributeError异常。否则它返回该属性。

class Count:

    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax
        self.current=None

    def __getattribute__(self, item):
        if item.startswith('cur'):
            raise AttributeError
        return object.__getattribute__(self,item) 
        # or you can use ---return super().__getattribute__(item)

obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)

Important: In order to avoid infinite recursion in __getattribute__method, its implementation should always call the base class method with the same name to access any attributes it needs. For example: object.__getattribute__(self, name)or super().__getattribute__(item)and not self.__dict__[item]

重要提示:为了避免__getattribute__方法中的无限递归,其实现应始终调用具有相同名称的基类方法来访问它需要的任何属性。例如:object.__getattribute__(self, name)or super().__getattribute__(item)and notself.__dict__[item]

IMPORTANT

重要的

If your class contain both getattrand getattributemagic methods then __getattribute__is called first. But if __getattribute__raises AttributeErrorexception then the exception will be ignored and __getattr__method will be invoked. See the following example:

如果您的类同时包含getattrgetattribute魔术方法,则 __getattribute__首先调用。但是如果 __getattribute__引发 AttributeError异常,则异常将被忽略并__getattr__调用方法。请参阅以下示例:

class Count(object):

    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax
        self.current=None

    def __getattr__(self, item):
            self.__dict__[item]=0
            return 0

    def __getattribute__(self, item):
        if item.startswith('cur'):
            raise AttributeError
        return object.__getattribute__(self,item)
        # or you can use ---return super().__getattribute__(item)
        # note this class subclass object

obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)

回答by soporific312

In reading through Beazley & Jones PCB, I have stumbled on an explicit and practical use-case for __getattr__that helps answer the "when" part of the OP's question. From the book:

在阅读 Beazley & Jones PCB 时,我偶然发现了一个明确且实用的用例,__getattr__它有助于回答 OP 问题的“何时”部分。从书中:

"The __getattr__()method is kind of like a catch-all for attribute lookup. It's a method that gets called if code tries to access an attribute that doesn't exist." We know this from the above answers, but in PCB recipe 8.15, this functionality is used to implement the delegation design pattern. If Object A has an attribute Object B that implements many methods that Object A wants to delegate to, rather than redefining all of Object B's methods in Object A just to call Object B's methods, define a __getattr__()method as follows:

“该__getattr__()方法有点像属性查找的万能方法。如果代码尝试访问不存在的属性,则会调用该方法。” 我们从上面的答案中知道这一点,但在 PCB 配方 8.15 中,此功能用于实现委托设计模式。如果对象 A 有一个属性对象 B,该属性实现了对象 A 想要委托给的许多方法,而不是重新定义对象 A 中的所有对象 B 的方法只是为了调用对象 B 的方法,定义一个__getattr__()方法如下:

def __getattr__(self, name):
    return getattr(self._b, name)

where _b is the name of Object A's attribute that is an Object B. When a method defined on Object B is called on Object A, the __getattr__method will be invoked at the end of the lookup chain. This would make code cleaner as well, since you do not have a list of methods defined just for delegating to another object.

其中 _b 是对象 A 的属性名称,即对象 B。当对象 B 上定义的方法在对象 A__getattr__上调用时,该方法将在查找链的末尾调用。这也会使代码更清晰,因为您没有定义仅用于委托给另一个对象的方法列表。