Ne zaman kullanılacağını anlamaya çalışıyorum __getattr__veya __getattribute__. Dokümantasyon bahseder __getattribute__yeni tarzı sınıfları için geçerlidir. Yeni stil sınıfları nelerdir?
Ne zaman kullanılacağını anlamaya çalışıyorum __getattr__veya __getattribute__. Dokümantasyon bahseder __getattribute__yeni tarzı sınıfları için geçerlidir. Yeni stil sınıfları nelerdir?
Yanıtlar:
Arasındaki temel farklılık __getattr__ve __getattribute__olmasıdır __getattr__nitelik zamanki yollar bulunamadığı takdirde sadece çağrılır. Eksik nitelikler için bir geri dönüş uygulamak için iyidir ve muhtemelen istediğiniz iki taneden biridir.
__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.
Yeni stil sınıflarından türetilir object, eski stil sınıfları Python 2.x'te açık taban sınıfı olmayan sınıflardır. Ancak, eski stil ile yeni stil sınıfları arasındaki fark __getattr__ve arasında seçim yaparken önemli değildir __getattribute__.
Neredeyse kesinlikle istiyorsun __getattr__.
__getattribute__her erişim __getattr__için çağrılacak ve __getattribute__yükseltilen zamanlar için çağrılacaktır AttributeError. Neden hepsini bir arada tutmuyorsun?
__getattribute__.
objec.__getattribute__çağırır myclass.__getattr__.
Her ikisinin __getattr__ve __getattribute__sihirli yöntemlerin bazı basit örneklerini görelim .
__getattr__Python, __getattr__daha önce tanımlanmamış bir özellik talep ettiğinizde yöntemi çağırır . Aşağıdaki örnekte sınıfımın Count__getattr__ yöntemi yoktur . Şimdi her ikisine de erişmeye çalıştığımda obj1.myminve obj1.mymaxniteliklerde her şey iyi çalışıyor. Ama obj1.mycurrentözniteliğe erişmeye çalıştığımda - Python banaAttributeError: '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'
Şimdi benim sınıf Kont sahiptir __getattr__yöntemi. Şimdi obj1.mycurrentözniteliğe erişmeye çalıştığımda - python __getattr__yöntemime uyguladığım her şeyi döndürüyor . Örneğimde, var olmayan bir özniteliği çağırmaya çalıştığımda, python bu özniteliği oluşturur ve 0 tamsayı değerine ayarlar.
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__Şimdi __getattribute__yöntemi görelim . __getattribute__Sınıfınızda bir yöntem varsa , python, var olup olmadığına bakılmaksızın her öznitelik için bu yöntemi çağırır. Peki neden __getattribute__yönteme ihtiyacımız var ? Bunun iyi bir nedeni, özniteliklere erişimi engelleyebilir ve aşağıdaki örnekte gösterildiği gibi daha güvenli hale getirebilirsiniz.
Birisi alt dize 'cur' ile başlayan özniteliklerime erişmeye çalıştığında python AttributeErroristisna oluşturur. Aksi takdirde bu niteliği döndürür.
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)
Önemli: __getattribute__Yöntemde sonsuz özyinelemeden kaçınmak için , uygulaması, gereken özelliklere erişmek için her zaman aynı ada sahip temel sınıf yöntemini çağırmalıdır. Örneğin: object.__getattribute__(self, name)ya da super().__getattribute__(item)değilself.__dict__[item]
Sınıf hem içeriyorsa getattr ve getAttribute sonra sihirli yöntemleri __getattribute__ilk olarak adlandırılır. Ancak istisna __getattribute__yükselirse
AttributeErroristisna dikkate alınmaz ve __getattr__yöntem çağrılır. Aşağıdaki örneğe bakın:
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)
__getattribute__ama kesinlikle bu değil. Senin başına Örneğin, sen yapıyorsun tüm Çünkü __getattribute__yükselterek olduğu AttributeErrornitelik de yoksa istisna __dict__nesnesinin; ancak buna gerçekten ihtiyacınız yok, çünkü bu varsayılan uygulama __getattribute__ve infact __getattr__tam olarak bir geri dönüş mekanizması olarak ihtiyacınız olan şey.
currentolaylarına tanımlanır Count(bkz __init__), bu yüzden sadece yükselterek AttributeErrorbu uygulamalara atıfta - nitelik oldukça ne oluyor orada değil değilse __getattr__için tüm dahil isimlerin 'cur' başlayan current, ama aynı zamanda curious, curly...
Bu sadece Ned Batchelder'in açıklamasına dayanan bir örnektir .
__getattr__ misal:
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')
Aynı örnek ile kullanılırsa, __getattribute__>>>RuntimeError: maximum recursion depth exceeded while calling a Python object
__getattr__()uygulamalar, yalnızca AttributeErrorgeçersiz özellik adları için yükselterek sınırlı bir geçerli özellik adı kümesini kabul eder , böylece ince ve hata ayıklaması zor sorunları önler . Bu örnek koşulsuz olarak tüm özellik adlarını geçerli olarak kabul eder - tuhaf (ve açıkçası hataya eğilimli) kötüye kullanım __getattr__(). Bu örnekte olduğu gibi öznitelik oluşturma üzerinde "tam kontrol" istiyorsanız, __getattribute__()bunun yerine istediğinizi belirtin.
defaultdict.
__getattr__ çağrılacak olmasıdır . Bu doğrudan bir alt sınıf için uygundur , çünkü gerçekten umursadığınız tek yöntem yine de örneği görmezden gelen sihirli yöntemler vardır, ancak daha karmaşık miras yapısı için, herhangi bir şeyi üst öğeden devralma yeteneğini tamamen kaldırırsınız. object
Yeni stil sınıfları objectbaşka bir yeni stil sınıfından miras alır veya başka bir yeni stil sınıfından miras alır :
class SomeObject(object):
pass
class SubObject(SomeObject):
pass
Eski tarz sınıflar şunları yapmaz:
class SomeObject:
pass
Bu sadece Python 2 için geçerlidir - Python 3'te yukarıdakilerin hepsi yeni stil sınıfları yaratacaktır.
Bkz. 9. Sınıflar (Python eğitimi), NewClassVsClassicClass ve Python'daki eski stil ile yeni stil sınıfları arasındaki fark nedir? detaylar için.
Yeni stil sınıfları, "doğrudan" veya dolaylı olarak "nesne" sınıfına giren sınıflardır. Bunlara __new__ek olarak bir sınıf yöntemi vardır __init__ve biraz daha rasyonel düşük seviyeli davranışa sahiptirler.
Genellikle, geçersiz kılmak istersiniz __getattr__(ikisini de geçersiz kılarsanız ), aksi takdirde yöntemlerinizde "self.foo" sözdizimini desteklemekte zorlanırsınız.
Ek bilgi: http://www.devx.com/opensource/Article/31482/0/page/4
Beazley & Jones PCB'yi okurken __getattr__, OP sorununun "ne zaman" kısmının yanıtlanmasına yardımcı olan açık ve pratik bir kullanım senaryosuna rastladım . Kitaptan:
" __getattr__()Yöntem, öznitelik araması için bir tümünü yakala gibi. Kod, var olmayan bir özniteliğe erişmeye çalışırsa çağrılan bir yöntemdir." Bunu yukarıdaki cevaplardan biliyoruz, ancak PCB tarifi 8.15'te, bu işlevsellik, delegasyon tasarım modelini uygulamak için kullanılır . A Nesnesi, A Nesnesinin temsil etmek istediği birçok yöntemi uygulayan bir Nesne B özniteliğine sahipse, yalnızca Nesne B'nin yalnızca Nesne B'nin yöntemlerini çağırmak için Nesne B'deki tüm yöntemlerini yeniden tanımlamak yerine __getattr__(), aşağıdaki gibi bir yöntem tanımlayın :
def __getattr__(self, name):
return getattr(self._b, name)
burada _b, Object B olan Object A özniteliğinin adıdır. Object B'de tanımlanan bir yöntem Object A'da __getattr__çağrıldığında , yöntem arama zincirinin sonunda çağrılır. Yalnızca başka bir nesneye yetki vermek için tanımlanmış yöntemlerin bir listesine sahip olmadığınız için, bu da kodu temizler.