标签归档:getattribute

了解__getattr__和__getattribute__之间的区别

问题:了解__getattr__和__getattribute__之间的区别

我试图理解上的差异之间__getattr____getattribute__,但是,我在它失败。

堆栈溢出问题的答案与vs 之间的区别是__getattr____getattribute__

__getattribute__在查看对象的实际属性之前调用,因此很难正确实现。您可以非常轻松地进行无限递归。

我完全不知道那是什么意思。

然后继续说:

您几乎可以肯定想要__getattr__

为什么?

我读到,如果__getattribute__失败,__getattr__则称为。那么,为什么有两种不同的方法做同样的事情呢?如果我的代码实现了新样式类,我应该使用什么?

我正在寻找一些代码示例来清除此问题。我已尽我所能搜索Google,但是我发现的答案并未彻底讨论该问题。

如果有任何文档,我准备阅读。

I am trying to understand the difference between __getattr__ and __getattribute__, however, I am failing at it.

The answer to the Stack Overflow question Difference between __getattr__ vs __getattribute__ says:

__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.

I have absolutely no idea what that means.

Then it goes on to say:

You almost certainly want __getattr__.

Why?

I read that if __getattribute__ fails, __getattr__ is called. So why are there two different methods doing the same thing? If my code implements the new style classes, what should I use?

I am looking for some code examples to clear this question. I have Googled to best of my ability, but the answers that I found don’t discuss the problem thoroughly.

If there is any documentation, I am ready to read that.


回答 0

首先了解一些基础知识。

对于对象,您需要处理其属性。通常我们会这么做instance.attribute。有时我们需要更多的控制权(当我们事先不知道属性名称时)。

例如,instance.attribute将变为getattr(instance, attribute_name)。使用此模型,我们可以通过提供attribute_name作为字符串来获取属性。

用于 __getattr__

您还可以告诉类如何处理它未显式管理的属性,并通过__getattr__方法进行操作。

每当您请求尚未定义的属性时,Python都会调用此方法,因此您可以定义该方法。

一个经典的用例:

class A(dict):
    def __getattr__(self, name):
       return self[name]
a = A()
# Now a.somekey will give a['somekey']

注意事项和使用 __getattribute__

如果您需要捕获每个属性(无论是否存在),请使用__getattribute__。不同之处在于,__getattr__仅调用实际上不存在的属性。如果您直接设置属性,则引用该属性将无需调用即可检索它__getattr__

__getattribute__ 一直被称为。

Some basics first.

With objects, you need to deal with its attributes. Ordinarily we do instance.attribute. Sometimes we need more control (when we do not know the name of the attribute in advance).

For example, instance.attribute would become getattr(instance, attribute_name). Using this model, we can get the attribute by supplying the attribute_name as a string.

Use of __getattr__

You can also tell a class how to deal with attributes which it doesn’t explicitly manage and do that via __getattr__ method.

Python will call this method whenever you request an attribute that hasn’t already been defined, so you can define what to do with it.

A classic use case:

class A(dict):
    def __getattr__(self, name):
       return self[name]
a = A()
# Now a.somekey will give a['somekey']

Caveats and use of __getattribute__

If you need to catch every attribute regardless whether it exists or not, use __getattribute__ instead. The difference is that __getattr__ only gets called for attributes that don’t actually exist. If you set an attribute directly, referencing that attribute will retrieve it without calling __getattr__.

__getattribute__ is called all the times.


回答 1

__getattribute__ 每当发生属性访问时都会调用。

class Foo(object):
    def __init__(self, a):
        self.a = 1

    def __getattribute__(self, attr):
        try:
            return self.__dict__[attr]
        except KeyError:
            return 'default'
f = Foo(1)
f.a

这将导致无限递归。罪魁祸首是排队return self.__dict__[attr]。让我们假装(这与事实很接近)所有属性都存储在self.__dict__名称中并可用。线

f.a

尝试访问的a属性f。这叫f.__getattribute__('a')__getattribute__然后尝试加载self.__dict____dict__是的属性,self == f因此python调用f.__getattribute__('__dict__')再次尝试访问属性'__dict__‘。这是无限递归。

如果__getattr__曾经使用过,那么

  1. 它永远不会运行,因为f具有a属性。
  2. 如果它已经运行((假设您要f.b)),则不会调用__dict__它,因为它已经存在,并且__getattr__仅当所有其他查找属性的方法均失败时才被调用。

编写上述类的“正确”方法__getattribute__

class Foo(object):
    # Same __init__

    def __getattribute__(self, attr):
        return super(Foo, self).__getattribute__(attr)

super(Foo, self).__getattribute__(attr)__getattribute__“最近”超类的方法(self通常是该类的“方法解析顺序”中的下一个类)绑定到当前对象,然后调用它并让其完成工作。

通过使用__getattr__python 可以在没有找到属性之前将其正常处理,从而避免了所有这些麻烦。到那时,Python将控制权交给您的__getattr__方法,并让它提出一些建议。

还值得注意的是,您可以使用进行无限递归__getattr__

class Foo(object):
    def __getattr__(self, attr):
        return self.attr

我将把它留作练习。

__getattribute__ is called whenever an attribute access occurs.

class Foo(object):
    def __init__(self, a):
        self.a = 1

    def __getattribute__(self, attr):
        try:
            return self.__dict__[attr]
        except KeyError:
            return 'default'
f = Foo(1)
f.a

This will cause infinite recursion. The culprit here is the line return self.__dict__[attr]. Let’s pretend (It’s close enough to the truth) that all attributes are stored in self.__dict__ and available by their name. The line

f.a

attempts to access the a attribute of f. This calls f.__getattribute__('a'). __getattribute__ then tries to load self.__dict__. __dict__ is an attribute of self == f and so python calls f.__getattribute__('__dict__') which again tries to access the attribute '__dict__‘. This is infinite recursion.

If __getattr__ had been used instead then

  1. It never would have run because f has an a attribute.
  2. If it had run, (let’s say that you asked for f.b) then it would not have been called to find __dict__ because it’s already there and __getattr__ is invoked only if all other methods of finding the attribute have failed.

The ‘correct’ way to write the above class using __getattribute__ is

class Foo(object):
    # Same __init__

    def __getattribute__(self, attr):
        return super(Foo, self).__getattribute__(attr)

super(Foo, self).__getattribute__(attr) binds the __getattribute__ method of the ‘nearest’ superclass (formally, the next class in the class’s Method Resolution Order, or MRO) to the current object self and then calls it and lets that do the work.

All of this trouble is avoided by using __getattr__ which lets Python do it’s normal thing until an attribute isn’t found. At that point, Python hands control over to your __getattr__ method and lets it come up with something.

It’s also worth noting that you can run into infinite recursion with __getattr__.

class Foo(object):
    def __getattr__(self, attr):
        return self.attr

I’ll leave that one as an exercise.


回答 2

我认为其他的答案做了解释之间的差异的一个伟大的工作__getattr____getattribute__,但有一点可能没有明确的是,为什么你会想使用__getattribute__。有趣的__getattribute__是,它本质上允许您在访问类时重载点。这使您可以自定义如何在较低级别访问属性。例如,假设我要定义一个类,其中所有仅带有自变量的方法都被视为属性:

# prop.py
import inspect

class PropClass(object):
    def __getattribute__(self, attr):
        val = super(PropClass, self).__getattribute__(attr)
        if callable(val):
            argcount = len(inspect.getargspec(val).args)
            # Account for self
            if argcount == 1:
                return val()
            else:
                return val
        else:
            return val

从交互式解释器中:

>>> import prop
>>> class A(prop.PropClass):
...     def f(self):
...             return 1
... 
>>> a = A()
>>> a.f
1

当然,这是一个愚蠢的示例,您可能永远也不想这样做,但是它向您展示了从覆盖获得的强大功能__getattribute__

I think the other answers have done a great job of explaining the difference between __getattr__ and __getattribute__, but one thing that might not be clear is why you would want to use __getattribute__. The cool thing about __getattribute__ is that it essentially allows you to overload the dot when accessing a class. This allows you to customize how attributes are accessed at a low level. For instance, suppose I want to define a class where all methods that only take a self argument are treated as properties:

# prop.py
import inspect

class PropClass(object):
    def __getattribute__(self, attr):
        val = super(PropClass, self).__getattribute__(attr)
        if callable(val):
            argcount = len(inspect.getargspec(val).args)
            # Account for self
            if argcount == 1:
                return val()
            else:
                return val
        else:
            return val

And from the interactive interpreter:

>>> import prop
>>> class A(prop.PropClass):
...     def f(self):
...             return 1
... 
>>> a = A()
>>> a.f
1

Of course this is a silly example and you probably wouldn’t ever want to do this, but it shows you the power you can get from overriding __getattribute__.


回答 3

我经历了别人的出色解释。但是,我从此博客Python Magic Methods和__getattr__找到了一个简单的答案。以下所有都是从那里开始的。

使用__getattr__magic方法,我们可以拦截不存在的属性查找并做一些事情,以确保它不会失败:

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.does_not_exist # 'DOES_NOT_EXIST'
d.what_about_this_one  # 'WHAT_ABOUT_THIS_ONE'

但是,如果该属性确实存在,__getattr__将不会被调用:

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.value = "Python"
print(d.value)  # "Python"

__getattribute__与相似__getattr__,但重要的区别是__getattribute__将拦截每个属性查找,而属性是否存在无关紧要。

class Dummy(object):

    def __getattribute__(self, attr):
        return 'YOU SEE ME?'

d = Dummy()
d.value = "Python"
print(d.value)  # "YOU SEE ME?"

在该示例中,d对象已经具有属性值。但是,当我们尝试访问它时,没有得到原始的期望值(“ Python”);我们只是得到任何__getattribute__回报。这意味着我们实际上失去了value属性;它已经变得“无法到达”。

I have gone through other’s excellent explanation. However, I found a simple answer from this blog Python Magic Methods and __getattr__. All the following are from there.

Using the __getattr__ magic method, we can intercept that inexistent attribute lookup and do something so it doesn’t fail:

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.does_not_exist # 'DOES_NOT_EXIST'
d.what_about_this_one  # 'WHAT_ABOUT_THIS_ONE'

But if the attribute does exist, __getattr__ won’t be invoked:

class Dummy(object):

    def __getattr__(self, attr):
        return attr.upper()

d = Dummy()
d.value = "Python"
print(d.value)  # "Python"

__getattribute__ is similar to __getattr__, with the important difference that __getattribute__ will intercept EVERY attribute lookup, doesn’t matter if the attribute exists or not.

class Dummy(object):

    def __getattribute__(self, attr):
        return 'YOU SEE ME?'

d = Dummy()
d.value = "Python"
print(d.value)  # "YOU SEE ME?"

In that example, the d object already has an attribute value. But when we try to access it, we don’t get the original expected value (“Python”); we’re just getting whatever __getattribute__ returned. It means that we’ve virtually lost the value attribute; it has become “unreachable”.


__getattr__和__getattribute__之间的区别

问题:__getattr__和__getattribute__之间的区别

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

I am trying to understand when to use __getattr__ or __getattribute__. The documentation mentions __getattribute__ applies to new-style classes. What are new-style classes?


回答 0

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

__getattribute__在查看对象的实际属性之前调用,因此正确实现可能会比较棘手。您可以非常轻松地进行无限递归。

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

您几乎可以肯定想要__getattr__

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.

__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.

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__.

You almost certainly want __getattr__.


回答 1

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

__getattr__

__getattr__每当您请求尚未定义的属性时,Python都会调用 method。在下面的示例中,我的Count类没有__getattr__方法。现在,当我尝试同时访问obj1.mymin和访问obj1.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'

现在,我的ClassCount具有__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__方法。如果您__getattribute__的类中有 方法,则python会为每个属性调用此方法,无论该属性是否存在。那么为什么我们需要__getattribute__方法呢?一个很好的理由是,您可以阻止访问属性并使它们更安全,如以下示例所示。

每当有人尝试访问以子字符串“ 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)

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

重要

如果您的类同时包含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)

Lets see some simple examples of both __getattr__ and __getattribute__ magic methods.

__getattr__

Python will call __getattr__ method whenever you request an attribute that hasn’t already been defined. In the following example my class Count has no __getattr__ method. Now in main when I try to access both obj1.mymin and obj1.mymax attributes everything works fine. But when I try to access obj1.mycurrent attribute — Python gives me 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 Count has __getattr__ method. Now when I try to access obj1.mycurrent attribute — 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.

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__

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.

Whenever someone try to access my attributes that starts with substring ‘cur’ python raises AttributeError exception. Otherwise it returns that attribute.

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]

IMPORTANT

If your class contain both getattr and getattribute magic methods then __getattribute__ is called first. But if __getattribute__ raises AttributeError exception then the exception will be ignored and __getattr__ method will be invoked. See the following example:

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)

回答 2

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

__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')

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

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

__getattr__ example:

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


回答 3

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

class SomeObject(object):
    pass

class SubObject(SomeObject):
    pass

旧式类不能:

class SomeObject:
    pass

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

请参见9.类(Python教程),NewClassVsClassicClass和Python中旧样式类和新样式类之间的区别是什么?有关详细信息。

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

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.

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


回答 4

新型类是子类“对象”的子类(直接或间接)。他们除了具有__new__类方法外__init__,还具有更合理的低级行为。

通常,您将需要覆盖__getattr__(如果要覆盖两者之一),否则您将很难在方法中支持“ self.foo”语法。

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

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.

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.

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


回答 5

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

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

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

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

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:

“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:

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.