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.mymin
ve obj1.mymax
niteliklerde 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 AttributeError
istisna 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
AttributeError
istisna 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 AttributeError
nitelik 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.
current
olaylarına tanımlanır Count
(bkz __init__
), bu yüzden sadece yükselterek AttributeError
bu 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 AttributeError
geç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ı object
baş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.