2015-09-17 21 views
7

Python'da bir sınıf özeti oluşturmak için bir dekorasyon (merakın hatırı için) kodluyordum. Şimdiye kadar işe yarayacakmış gibi görünüyordu, ama beklenmedik bir davranışım var.Python soyut dekorasyon çalışmıyor

dekorasyon için fikri şuna benzer: Bu dekorasyon kullanırken

Sonra
from abc import ABCMeta, abstractmethod 

def abstract(cls): 
    cls.__metaclass__ = ABCMeta 
    return cls 

, sadece ben test ederken

@abstract 
class Dog(object): 
    @abstractmethod 
    def bark(self): 
     pass 

Ama başardı bir soyut yöntemini tanımlamak için ihtiyaç duyulan __metaclass__ atama test ederken

d = Dog() 
d.bark() //no errors 
Dog.__metaclass__ //returned "<class 'abc.ABCMeta'>" 

: bir köpek nesne oluşturmak doğrudan, o kadar beklenen davranır:

class Dog(object): 
    __metaclass__ = ABCMeta 
    @abstractmethod 
    def bark(self): 
     pass 

Test:

d = Dog() 

"Traceback (most recent call last): 
    File "<pyshell#98>", line 1, in <module> 
    d = Dog() 
TypeError: Can't instantiate abstract class Dog with abstract methods bark" 

neden oluyor?

+0

Cevabımı kontrol edin, sorununuzu çözer. Bu soru için teşekkürler. –

cevap

2

Sorununuzu yeniden üretebildim.

ABCMeta .__ new__, dekoratörünüzü kullanarak hiçbir zaman olarak adlandırılmaz. Onu Dog'ın meta sınıfı olarak tanımladığınızda, çağrılır. Bunun nedeni, Köpek sınıfının zaten tanımlanmış olmasıdır, bu yüzden ABCMeta'nın eklenmesi, aslında herhangi bir fark yaratmayacaktır, çünkü yeni tanım zamanında çağrılmadığı için, Köpek sınıfını bir özet olarak kaydettirmez ve keşfetmez. soyut yöntemleri. Seni ABCMeta'yı okumaya davet ediyorum. yeni kodu ve ne yaptığını göreceksiniz. beklendiği gibi

def abstract(cls): 
    return ABCMeta(cls.__name__, cls.__bases__, dict(cls.__dict__)) 

Bu şimdi çalışır:

Ancak, ben yine de dekoratör çalışması için, bu çözüm bulduk. 'un anlamı bark'u arayabilmeniz içinDog alt sınıfını belirlemeniz gerekir.

+0

Bu işe yaradı, düzgün! – Hydren

4

piton referans states: __metaclass__ sonra tanımlanmış olması durumunda kendisine atanmış çağrılabilir yerine Çeşidi çağrılır

sınıf tanımı okunur

,(). Bu sınıflar veya işlevler yazılı olan monitör veya

sınıf tanımı okumak olduğunda önemli parçası , sen sonradan metaclass değiştiremeyeceğiniz anlamına gelir sınıf oluşturma işlemini değiştirmek izin verir, ve işte Sadece bir dekoratörün yaptığı, sadece sözdizimsel şeker olduğu gibi. dekoratör çağrıldığında

class SomeClass(object): pass SomeClass = some_decorator(SomeClass) 

Yani, sınıf tanımı zaten okundu:

@some_decorator 
class SomeClass(object): 
    pass 

aynıdır.

+0

Çok kısa cevap. Apero'nun bana bir çözüm verdiğini söylese de, eğer istersen seninkini "kabul" olarak işaretlerim. – Hydren