__Getattr__ ve __getattribute__ arasındaki farkı anlama


206

Arasındaki farkı anlamaya çalışıyorum __getattr__ve __getattribute__bununla birlikte başarısız oluyorum.

Cevap yığın taşması soru için aralarında Fark __getattr__VS__getattribute__ diyor:

__getattribute__nesnenin gerçek özelliklerine bakmadan önce çağrılır ve bu nedenle doğru bir şekilde uygulanması zor olabilir. Sonsuz özyinelemelere çok kolayca son verebilirsiniz.

Bunun ne anlama geldiğine dair hiçbir fikrim yok.

Sonra şöyle der:

Neredeyse kesinlikle istiyorsun __getattr__.

Neden?

__getattribute__Başarısız olursa __getattr__arandığını okudum . Peki neden aynı şeyi yapan iki farklı yöntem var? Kodum yeni stil sınıflarını uygularsa ne kullanmalıyım?

Bu soruyu temizlemek için bazı kod örnekleri arıyorum. Yeteneklerimin en iyisine gittim, ancak bulduğum cevaplar sorunu ayrıntılı olarak tartışmıyor.

Herhangi bir belge varsa, bunu okumaya hazırım.


2
"Bu yöntemde sonsuz özyinelemeden kaçınmak için, uygulamasının her zaman aynı ada sahip temel sınıf yöntemini çağırması gerekir, örneğin nesne .__ getattribute __ (self, name). " [ docs.python.org/2/reference/…
kmonsoor

Yanıtlar:


306

Önce bazı temel bilgiler.

Nesnelerle, öznitelikleriyle uğraşmanız gerekir. Normalde yapıyoruz instance.attribute. Bazen daha fazla kontrole ihtiyacımız var (özelliğin adını önceden bilmediğimizde).

Örneğin, instance.attributeolur getattr(instance, attribute_name). Bu modeli kullanarak, niteliği bir dize olarak sağlayarak niteliği alabiliriz .

Kullanımı __getattr__

Ayrıca, bir sınıfa açıkça yönetmediği niteliklerle nasıl başa çıkacağını söyleyebilir ve bunu __getattr__yöntemle yapabilirsiniz.

Python, daha önce tanımlanmamış bir özellik talep ettiğinizde bu yöntemi çağıracaktır, böylece onunla ne yapacağınızı tanımlayabilirsiniz.

Klasik bir kullanım örneği:

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

Uyarılar ve kullanımı __getattribute__

Her özellik yakalamak gerekiyorsa olursa olsun var olup olmadığını , kullanmak __getattribute__yerine. Aradaki fark, __getattr__sadece gerçekte mevcut olmayan özellikler için çağrılmasıdır. Bir özniteliği doğrudan ayarlarsanız, özniteliğe başvurmak çağrılmadan bu özniteliğe erişir __getattr__.

__getattribute__ her zaman çağrılır.


"Örneğin, instance.attribute olur getattr(instance, attribute_name)." Olmamalı mı __getattribute__(instance, attribute_name)?
Md. Abu Nafee Ibna Zahid

1
@ Md.AbuNafeeIbnaZahid getattryerleşik bir işlevdir. getattr(foo, 'bar')eşittir foo.bar.
wizzwizz4

değerinde belirterek __getattr__onu tanımlanan eğer miras değil sadece, çağrılanobject
joelb

94

__getattribute__ bir öznitelik erişimi gerçekleştiğinde çağrılır.

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

Bu sonsuz tekrarlamaya neden olur. Buradaki suçlu çizgi return self.__dict__[attr]. Tüm niteliklerin self.__dict__adlarına göre depolandığını ve mevcut olduklarını varsayalım (gerçeğe yeterince yakın) . Çizgi

f.a

aözelliğine erişmeye çalışır f. Bu çağırıyor f.__getattribute__('a'). __getattribute__sonra yüklemeye çalışır self.__dict__. __dict__bir özniteliktir self == fve bu nedenle f.__getattribute__('__dict__')yine özniteliğe erişmeye çalışan python çağrılarıdır '__dict__'. Bu sonsuz özyineleme.

Eğer __getattr__o zaman yerine kullanılmıştır vardı

  1. Asla koşmazdı çünkü fbir aniteliği var.
  2. Çalışmış olsaydı, (diyelim ki siz istediniz f.b), o zaman __dict__zaten orada olduğu ve __getattr__yalnızca özniteliği bulmanın diğer tüm yöntemleri başarısız olduğunda çağrıldığı için bulmak için çağrılmazdı .

Kullanarak yukarıdaki sınıfını yazmaya 'doğru' yolu __getattribute__olduğunu

class Foo(object):
    # Same __init__

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

super(Foo, self).__getattribute__(attr)__getattribute__'en yakın' üst sınıf yöntemini (resmi olarak, sınıfın Yöntem Çözüm Sırası veya MRO'daki bir sonraki sınıf) geçerli nesneye bağlar selfve sonra çağırır ve bunu yapmasına izin verir.

Tüm bu sorun, bir öznitelik bulunana kadar __getattr__Python'un normal bir şey yapmasına izin veren kullanarak önlenir . Bu noktada, Python __getattr__yönteminizi kontrol eder ve bir şey bulmasına izin verir.

Ayrıca sonsuz özyineleme ile karşılaşabileceğinizi belirtmek gerekir __getattr__.

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

Bunu egzersiz olarak bırakacağım.


60

Sanırım diğer cevaplar, __getattr__ve arasındaki farkı açıklamak için harika bir iş çıkardı __getattribute__, ancak net olmayan bir şey neden kullanmak isteyeceğinizdir __getattribute__. Bununla ilgili harika olan şey __getattribute__, bir sınıfa erişirken noktayı aşırı yüklemenize izin vermesidir. Bu, özelliklerin düşük düzeyde nasıl erişileceğini özelleştirmenizi sağlar. Örneğin, yalnızca kendi kendine argüman alan tüm yöntemlerin özellik olarak değerlendirildiği bir sınıf tanımlamak istediğimi varsayalım:

# 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

Ve interaktif tercümandan:

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

Tabii ki bu aptalca bir örnek ve muhtemelen bunu hiç yapmak istemezsiniz, ancak size geçersiz kılmadan alabileceğiniz gücü gösterir __getattribute__.


6

Başkalarının mükemmel açıklamasından geçtim. Ancak, bu blogdan basit bir cevap buldum Python Magic Methods ve__getattr__ . Aşağıdakilerin hepsi oradan.

Kullanmak __getattr__Sihirli yöntemi mevcut olmayan özellik aramasını kesebilir ve başarısız olmayacak bir şey yapabiliriz:

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'

Ancak özellik mevcutsa, __getattr__ çağrılmaz:

class Dummy(object):

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

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

__getattribute__benzer __getattr__önemli fark, __getattribute__müdahale edecektir her nitelik var olup olmadığını özellik araması, önemli değildir.

class Dummy(object):

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

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

Bu örnekte, dnesnenin zaten bir öznitelik değeri vardır. Ancak erişmeye çalıştığımızda, beklenen orijinal değeri (“Python”) alamıyoruz; biz sadece __getattribute__geri gelenleri alıyoruz . Bu, değer niteliğini neredeyse kaybettiğimiz anlamına gelir; “ulaşılamaz” hale geldi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.