我试图理解什么时候定义__getattr__或__getattribute__。python文档提到__getattribute__适用于新样式的类。什么是新型类?


当前回答

new -style类继承自object或另一个new -style类:

class SomeObject(object):
    pass

class SubObject(SomeObject):
    pass

老式的类没有:

class SomeObject:
    pass

这只适用于python2 -在python3中,上述所有将创建新样式的类。

看到9。类(Python教程),NewClassVsClassicClass和Python中新旧风格类之间的区别是什么?获取详细信息。

其他回答

getattribute:用于从实例中检索属性。它通过使用点表示法或getattr()内置函数捕获访问实例属性的每次尝试。 getattr:当在对象中找不到属性时,作为最后一个资源执行。您可以选择返回一个默认值或引发AttributeError。

返回__getattribute__函数;如果没有覆盖默认实现;执行该方法时执行以下检查:

检查MRO链中的任何类中是否定义了同名(属性名)的描述符(方法对象解析) 然后查看实例的名称空间 然后查看类名称空间 然后进入每个基的名称空间,等等。 最后,如果未找到,默认实现将调用实例的回退getattr()方法,并作为默认实现引发AttributeError异常。

这是对象的实际实现。__getattribute__方法:

.. c:function:: PyObject* PyObject_GenericGetAttr(PyObject *o, PyObject *name) Generic attribute getter function that is meant to be put into a type object's tp_getattro slot. It looks for a descriptor in the dictionary of classes in the object's MRO as well as an attribute in the object's :attr:~object.dict (if present). As outlined in :ref:descriptors, data descriptors take preference over instance attributes, while non-data descriptors don't. Otherwise, an :exc:AttributeError is raised.

这只是一个基于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:调用Python对象时超过最大递归深度

新型类是直接或间接继承“object”的类。除了__init__之外,它们还有一个__new__类方法,并且有一些更合理的低级行为。

通常,你会想要重写__getattr__(如果你重写了其中任何一个),否则你将很难支持“self”。方法中的Foo语法。

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

new -style类继承自object或另一个new -style类:

class SomeObject(object):
    pass

class SubObject(SomeObject):
    pass

老式的类没有:

class SomeObject:
    pass

这只适用于python2 -在python3中,上述所有将创建新样式的类。

看到9。类(Python教程),NewClassVsClassicClass和Python中新旧风格类之间的区别是什么?获取详细信息。

让我们看一些__getattr__和__getattribute__神奇方法的简单例子。

__getattr__

每当你请求一个尚未定义的属性时,Python将调用__getattr__方法。在下面的例子中,我的类Count没有__getattr__方法。在main中,当我访问两个obj1时。Mymin和obj1。Mymax属性一切正常。但当我访问obj1时。` Count `对象没有属性` 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]

重要的

如果你的类同时包含getattr和getattribute魔法方法,那么__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)