2016-03-16 12 views
20

Python 3.4'ten itibaren DynamicClassAttribute adlı bir tanımlayıcı vardır. dokümantasyon devletler:Bir DynamicClassAttribute nedir ve nasıl kullanırım?

types.DynamicClassAttribute(fget=None, fset=None, fdel=None, doc=None)

Rota __getattr__ için bir sınıf üzerinde erişime bağlıyor.

Bu, bir örnek aracılığıyla ve bir sınıf aracılığıyla erişildiğinde farklı davranan öznitelikleri tanımlamak için kullanılan bir tanımlayıcıdır. Örnek erişimi normal kalır, ancak bir sınıftaki bir özelliğe erişim, sınıfın __getattr__ yöntemine yönlendirilir; Bu AttributeError yükseltilerek yapılır.

Bu, bir örnek üzerinde özelliklerin etkin olmasına ve aynı ada sahip sınıfta sanal özniteliklere sahip olmasına izin verir (örnek için bkz. Enum).

Yeni sürüm 3.4.

Görünüşe enum module kullanılır:

# DynamicClassAttribute is used to provide access to the `name` and 
# `value` properties of enum members while keeping some measure of 
# protection from modification, while still allowing for an enumeration 
# to have members named `name` and `value`. This works because enumeration 
# members are not set directly on the enum class -- __getattr__ is 
# used to look them up. 

@DynamicClassAttribute 
def name(self): 
    """The name of the Enum member.""" 
    return self._name_ 

@DynamicClassAttribute 
def value(self): 
    """The value of the Enum member.""" 
    return self._value_ 

Ben enums are a little special ama bu DynamicClassAttribute ilgilidir anlamıyorum biliyoruz. Bu özniteliklerin dinamik olduğu, bunun normal bir özellikten farkı nedir ve DynamicClassAttribute avantajımı nasıl kullanırım?

cevap

12

Yeni Versiyon: çok görünüyor,

İlk the source code of DynamicClassAttribute de bakabilirsiniz ve muhtemelen fark edeceksiniz: birazcık yeniden oluşturmaya karar verdi bu yüzden önceki cevap biraz hayal kırıklığına uğradım

Normal property gibi. __get__ kullanılan yöntem dışında: erişmek istiyorsanız

bir DynamicClassAttribute (yani soyut değildir) sınıfına yerine self dönen bir AttributeError yükseltir
def __get__(self, instance, ownerclass=None): 
    if instance is None: 
     # Here is the difference, the normal property just does: return self 
     if self.__isabstractmethod__: 
      return self 
     raise AttributeError() 
    elif self.fget is None: 
     raise AttributeError("unreadable attribute") 
    return self.fget(instance) 

Peki bunun anlamı olduğunu. Örnekler için if instance:, True için değerlendirir ve __get__, property.__get__ ile aynıdır. sadece giderir, normal sınıflar için

bir görünürAttributeError niteliğini çağrılırken:

from types import DynamicClassAttribute 
class Fun(): 
    @DynamicClassAttribute 
    def has_fun(self): 
     return False 
Fun.has_fun 

AttributeError - kendisi için olmadığını traceback (son En son çağrı)

metaclass es'i kullanarak "Class attribute lookup" yordamına numaralı yordamı izleyene kadar çok yararlıdır Bu güzel bir resim this blog bulundu. Bir özniteliğin AttributeError'u yükseltmesi ve bu sınıfın metaclass python'un metaclass.__getattr__ yöntemine sahip olması ve bu özniteliği çözüp çözemeyeceğini görmesi durumunda.

from types import DynamicClassAttribute 

# Metaclass 
class Funny(type): 

    def __getattr__(self, value): 
     print('search in meta') 
     # Normally you would implement here some ifs/elifs or a lookup in a dictionary 
     # but I'll just return the attribute 
     return Funny.dynprop 

    # Metaclasses dynprop: 
    dynprop = 'Meta' 

class Fun(metaclass=Funny): 
    def __init__(self, value): 
     self._dynprop = value 

    @DynamicClassAttribute 
    def dynprop(self): 
     return self._dynprop 

Ve burada "dinamik" bölümünü gelir: minimal bir örnekle bu göstermek için. Eğer sınıfına dynprop ararsanız o meta arama ve dönecektir meta en dynprop:

Fun.dynprop 

yazdırır:

search in meta 
'Meta' 

yüzden metaclass.__getattr__ çağrılan ve özgün niteliğini döndü (oldu yeni özellik ile aynı adla tanımlanır).

örnekleri için Fun -instance ait dynprop döndürülür iken:

Fun('Not-Meta').dynprop 

biz overriden niteliğini olsun:

'Not-Meta' 

bundan Benim sonuç DynamicClassAttribute isterseniz önemli olduğunu, olup Alt sınıfların, meta sınıfta kullanılanla aynı ada sahip bir özniteliğe sahip olmasını sağlamak. Örneklere gölge uygularsınız, ancak sınıfta çağırırsanız hala erişilebilir. DynamicClassAttribute (Ben bu noktada gerçekten emin değilim) eğer sadece yararlıdır Sürüm

Eski:

ben eski sürümde Enum davranışlarıyla gitti bu yüzden buraya bıraktı alt sınıfta belirlenen bir özellik ile temel sınıftaki bir özellik arasındaki çakışmaların adlandırma olabileceğinden şüpheleniyorsunuz.

nitelik arama biraz farklıolduğu için bu metaclasses (this blog post bulunabilir sınıf nitelikleri denir nasıl güzel bir açıklama) kullanmadan çalışmaz, çünkü metaclasses hakkında en azından bazı temellerini bilmek gerekir metaclasses ile.

sen olduğunu varsayalım: o zaman

class Funny(type): 
    dynprop = 'Very important meta attribute, do not override' 

class Fun(metaclass=Funny): 
    def __init__(self, value): 
     self._stub = value 

    @property 
    def dynprop(self): 
     return 'Haha, overridden it with {}'.format(self._stub) 

ve çağrı:

Fun.dynprop 

mülkiyet 0x1b3d9fd19a8

de ve örneğinde elde ederiz:

Fun(2).dynprop 

kaybolması ...

kötü 'Haha, 2 ile geçersiz kılınmış'. Ama bekle metaclass özel aramasını kullanabiliriz: __getattr__ (geri dönüş) uygulayalım ve dynprop'u DynamicClassAttribute olarak uygulayalım.ona göre documentation Çünkü o amacı var - __getattr__ çare için o sınıfın çağırdı eğer:

Fun.dynprop 

yazdırır:

search in meta 
'Meta' 

from types import DynamicClassAttribute 

class Funny(type): 
    def __getattr__(self, value): 
     print('search in meta') 
     return Funny.dynprop 

    dynprop = 'Meta' 

class Fun(metaclass=Funny): 
    def __init__(self, value): 
     self._dynprop = value 

    @DynamicClassAttribute 
    def dynprop(self): 
     return self._dynprop 

şimdi sınıf niteliğini erişmek

Bu nedenle metaclass.__getattr__ numaralı telefonu çağırdık ve orijinal niteliğini (yeni özellikle aynı adla tanımlanmış) döndürdük.

Ve örnekleri için

:

'Not-Meta' 

Eh biz bir örneğini oluşturmadan önce tanımlanan fakat overriden özelliklerine metaclasses kullanarak yeniden yönlendirmek dikkate çok kötü değil:

Fun('Not-Meta').dynprop 

biz overriden niteliği olsun.

from enum import Enum 

class Fun(Enum): 
    name = 'me' 
    age = 28 
    hair = 'brown' 

ve varsayılan olarak bu sonradan tanımlanan özellikleri erişmek istiyorum: Bu örnek, alt sınıf üzerindeki özelliklerini tanımlamak Enum, ile yapılır tersidir.

Fun.name 
# <Fun.name: 'me'> 

ama aynı zamanda DynamicClassAttribute olarak tanımlanmıştır name niteliğini (değişken aslında sahip olduğu adı döndüren) erişilmesine izin istiyorum:

Fun('me').name 
# 'name' 

çünkü aksi takdirde 28 adını erişebilir nasıl ?

Fun.hair.age 
# <Fun.age: 28> 
# BUT: 
Fun.hair.name 
# returns 'hair' 

Farkı görüyor musunuz? İkincisi neden <Fun.name: 'me'>'u iade etmiyor? Bu, DynamicClassAttribute'un bu kullanımı nedeniyle. Böylece orijinal mülkiyeti gölgeleyebilir, ancak daha sonra tekrar "bırakabilirsiniz". Bu davranış benim örneğimde gösterilenin tersidir ve en az __new__ ve __prepare__ kullanımını gerektirir. Ancak bunun tam olarak nasıl çalıştığını ve bir çok blogda ve stackoverflow-yanıtlarında nasıl açıklanacağını bilmeniz gerekiyor ki bunu çok daha iyi açıklayabiliyorum, böylece o kadar derinliğe inmeyi başaracağım (ve Kısa sürede çözebilirim).

Fiili kullanımın söz bir Propably bazı düşünebiliriz seyrek ama verilen bir zaman olabilir ...

Çok güzel tartışma DynamicClassAttribute dökümanlarına: "we added it because we needed it"

İlgili konular