__getattr__ 和 __getattribute__ 之间的区别

2025-01-03 08:40:00
admin
原创
102
摘要:问题描述:我想了解何时定义__getattr__或__getattribute__。python文档中提到的__getattribute__适用于新式类。什么是新式类?解决方案 1:__getattr__和之间的主要区别__getattribute__在于,__getattr__只有当属性无法以常规方式找到时...

问题描述:

我想了解何时定义__getattr____getattribute__。python文档中提到的__getattribute__适用于新式类。什么是新式类?


解决方案 1:

__getattr__和之间的主要区别__getattribute__在于,__getattr__只有当属性无法以常规方式找到时才会调用。它非常适合实现缺失属性的后备,并且可能是您想要的两个之一。

__getattribute__在查看对象的实际属性之前被调用,因此很难正确实现。你很容易陷入无限递归。

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

您几乎肯定想要__getattr__

解决方案 2:

让我们看一些有关魔术方法的简单__getattr__例子__getattribute__

__getattr__

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

现在我的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__方法。如果你的类中有 __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)

解决方案 3:

这只是基于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

解决方案 4:

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

class SomeObject(object):
    pass

class SubObject(SomeObject):
    pass

旧式课程没有:

class SomeObject:
    pass

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

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

解决方案 5:

新式类是直接或间接地将“对象”子类化的类。它们__new__除了类方法之外__init__,还具有更合理的低级行为。

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

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

解决方案 6:

我发现没有人提到这个区别:

__getattribute__有默认实现,但是__getattr__没有。

class A:
    pass
a = A()
a.__getattr__ # error
a.__getattribute__ # return a method-wrapper

这含义很明确:因为__getattribute__有默认实现,而__getattr__没有,所以显然python鼓励用户去实现__getattr__

解决方案 7:

  • getattribute:用于从实例中检索属性。它捕获使用点符号或 getattr() 内置函数访问实例属性的每次尝试。

  • getattr:当对象中未找到属性时,作为最后一个资源执行。您可以选择返回默认值或引发 AttributeError。

回到getattribute函数;如果默认实现没有被覆盖;执行该方法时将进行以下检查:

  • 检查MRO链中任意一个类中是否有定义同名(属性名)的描述符(方法对象解析)

  • 然后查看实例的命名空间

  • 然后查看类命名空间

  • 然后进入每个基地的命名空间等等。

  • 最后,如果未找到,默认实现将调用实例的后备getattr () 方法,并引发 AttributeError 异常作为默认实现。

这是object.__getattribute__ 方法的实际实现:

.. c:function:: PyObject PyObject_GenericGetAttr(PyObject o, PyObject *name) 通用属性获取函数,用于放入类型对象的 tp_getattro 槽中。它在对象的 MRO 中的类字典中查找描述符,并在对象的 :attr:~object. dict中查找属性(如果存在)。如 :ref:descriptors 中所述,数据描述符优先于实例属性,而非数据描述符则不然。否则,将引发 :exc:AttributeError。

解决方案 8:

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

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

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

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

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用