Ta klasa nie ma zestawu atrybutów __metaclass__
... ponieważ nigdy go nie ustawiłeś!
Która metaklasa używana jest zwykle określana jako przez nazwa __metaclass__
ustawiona w bloku klasy. Atrybut __metaclass__
nie jest ustawiony przez metaclass. Więc jeśli wywołasz metaclass bezpośrednio, zamiast ustawiać __metaclass__
i pozwalając Pythonowi go rozgryźć, wtedy nie zostanie ustawiony atrybut __metaclass__
.
W rzeczywistości, normalne zajęcia są wszystkie przypadki metaklasą type
, więc jeśli metaklasa zawsze ustawić atrybut __metaclass__
na jego wystąpień następnie każdy klasa będzie mieć atrybut __metaclass__
(większość z nich ustawiony type
).
Nie użyłbym twojego podejścia do dekoratora. Pomija fakt, że metaclass jest zaangażowany (i który z nich), jest nadal jedną linią standardowego zestawu, a po prostu jest bałagan stworzyć klasę z 3 cech definiujących (name, bases, attributes)
tylko po to, aby usunąć te 3 bity z wynikowej klasy, wyrzuć klasę i utwórz nową klasę z tych samych 3 bitów!
Kiedy to zrobić w Pythonie 2.x:
class A(object):
__metaclass__ = MyMeta
def __init__(self):
pass
Można by się z grubsza taki sam rezultat gdybyś napisał to:
attrs = {}
attrs['__metaclass__'] = MyMeta
def __init__(self):
pass
attrs['__init__'] = __init__
A = attrs.get('__metaclass__', type)('A', (object,), attrs)
W rzeczywistości obliczania metaklasą więcej Jest to skomplikowane, ponieważ w rzeczywistości trzeba przeszukać wszystkie bazy, aby ustalić, czy istnieje konflikt metaclasu, a jeśli jedna z baz nie ma type
jako metaklasy, a attrs
nie zawiera __metaclass__
, wówczas domyślną metaklasą jest metaklasa przodka, a nie type
. Jest to jedna z sytuacji, w której oczekuję, że twoje "rozwiązanie" dla dekoratora będzie się różnić od bezpośredniego stosowania __metaclass__
. Nie jestem do końca pewien, co by się stało, gdybyś użył swojego dekoratora w sytuacji, w której użycie __metaclass__
dałoby błąd konfliktu metaklasowego, ale nie spodziewałbym się, że będzie to przyjemne.
Ponadto, jeśli są zaangażowane jakiekolwiek inne metaclasy, twoja metoda spowoduje, że zostaną uruchomione jako pierwsze (ewentualnie modyfikując nazwę, bazy i atrybuty!), A następnie wyciągając je z klasy i używając jej do utworzenia nowa klasa. Może to potencjalnie różnić się od tego, co uzyskasz używając __metaclass__
.
Jeśli chodzi o __dict__
nie dając prawdziwego słownika, to tylko szczegół wdrożenia; Zgaduję, ze względu na wydajność. Wątpię, aby istniała jakaś specyfikacja, która mówi, że __dict__
instancji (bez klasy) musi być tego samego typu co klasa __dict__
klasy (która jest również instancją btw, po prostu instancją metaclass). Atrybut __dict__
klasy jest "dictproxy", który pozwala na wyszukiwanie kluczy atrybutów tak, jakby były one dict
, ale nadal nie jest to dict
. type
jest wybredny o typie trzeciego argumentu; chce prawdziwego dyktatu, a nie tylko obiektu typu "dyktującego" (wstyd za to, że psuje pisanie z kaczką). To nie jest rzecz 2.x vs 3.x; Python 3 zachowuje się w ten sam sposób, chociaż zapewnia ładniejszą reprezentację ciągów znaków dictproxy
. Python 2.4 (który jest najstarszym 2.x, który mam łatwo dostępny) ma również obiekty dictproxy
dla obiektów klasy .
Po prostu zastanawiałem się, czy istnieje dekorator równoważny ustawieniu atrybutu '__metaclass__' w definicji klasy. Sądzę, że inną częścią mojego pytania jest to, że mój "dekorator" * działał *, ale zauważyłem, że dekorowana klasa nie ma atrybutu "__metaclass__", więc wyraźnie widać różnicę między tymi dwiema metodami; dlaczego to? – Chris