Sınıflar bir metasınıfın örnekleri olduğu için, metasınıftaki bir "örnek yönteminin" bir sınıf yöntemi gibi davranması beklenmez.
Ancak, evet, farklılıklar var - ve bazıları semantikten daha fazlası:
- En önemli fark, metasınıftaki bir yöntemin bir sınıf örneğinden "görünür" olmamasıdır . Bunun nedeni, Python'daki öznitelik aramasının (basitleştirilmiş bir şekilde - tanımlayıcıların önceliği olabilir) örnekteki bir özniteliği aramasıdır - örnekte yoksa, Python daha sonra bu örneğin sınıfına bakar ve arama devam eder sınıfın üst sınıfları, ama değil sınıfları, sınıfın sınıfları üzerinde . Python stdlib
abc.ABCMeta.register
yöntemde bu özelliği kullanır . Sınıfla ilgili yöntemlerin herhangi bir çakışma olmadan örnek öznitelikleri olarak yeniden kullanılabilmeleri için bu özellik iyi olarak kullanılabilir (ancak bir yöntem yine de çakışma olur).
- Başka bir fark, açık olsa da, metasınıfta bildirilen bir yöntemin başka sınıflarla ilgili olmayan birkaç sınıfta mevcut olması - farklı sınıf hiyerarşilerine sahipseniz, uğraştıkları şeyle hiç ilgili değilse , ancak tüm sınıflar için bazı ortak işlevsellik istiyorsanız , her iki hiyerarşiye de temel olarak dahil edilmesi gereken bir mixin sınıfı bulmanız gerekir (örneğin, bir uygulama kayıt defterine tüm sınıfları dahil etmek için). (Not: mixin bazen bir metasınıftan daha iyi bir çağrı olabilir)
- Sınıf metodu özel bir "sınıf metodu" nesnesidir, oysa metasınıftaki bir yöntem sıradan bir fonksiyondur.
Böylece, sınıf yöntemlerinin kullandığı mekanizma " tanımlayıcı protokolü " olur. Normal işlevler , bir örnekten alındığında bağımsız değişkeni __get__
ekleyecek ve self
bir sınıftan alındığında bu bağımsız değişkeni boş bırakacak bir yöntem içerirken, bir classmethod
nesnenin farklı__get__
sınıfın kendisini ("sahip") her iki durumda da ilk parametre.
Bu çoğu zaman pratik bir fark yaratmaz, ancak metoda bir işlev olarak erişmek istiyorsanız, ona dinamik olarak dekoratör eklemek amacıyla veya metasınıftaki bir yöntem için meta.method
kullanıma hazır olan bir işlevi alır. , cls.my_classmethod.__func__
bir sınıf yönteminden almak için kullanmanız gerekirken (ve sonra başka birclassmethod
nesne ve biraz kaydırma yaparsanız geri atamanız gerekir).
Temel olarak, bunlar 2 örnektir:
class M1(type):
def clsmethod1(cls):
pass
class CLS1(metaclass=M1):
pass
def runtime_wrap(cls, method_name, wrapper):
mcls = type(cls)
setattr(mcls, method_name, wrapper(getatttr(mcls, method_name)))
def wrapper(classmethod):
def new_method(cls):
print("wrapper called")
return classmethod(cls)
return new_method
runtime_wrap(cls1, "clsmethod1", wrapper)
class CLS2:
@classmethod
def classmethod2(cls):
pass
def runtime_wrap2(cls, method_name, wrapper):
setattr(cls, method_name, classmethod(
wrapper(getatttr(cls, method_name).__func__)
)
)
runtime_wrap2(cls1, "clsmethod1", wrapper)
Başka bir deyişle: metasınıfta tanımlanan bir yöntemin örnekten görülebildiği ve bir classmethod
nesnenin görmediği önemli farkın yanı sıra, çalışma zamanında diğer farklılıklar belirsiz ve anlamsız görünecektir - ancak bu, dilin gitmesi gerekmediği için olur sınıf metodları için özel kurallarla kendi yolundan: Sınıf tasarımını ilan etmenin her iki yolu da dil tasarımından kaynaklanabilir - birincisi, bir sınıfın kendisinin bir nesne olması ve bir diğerinin de birçokları arasında bir olasılık olarak kişinin bir örnekte ve bir sınıfta öznitelik erişimini özelleştirmesine izin veren tanımlayıcı protokolünün kullanımı:
classmethod
Builtin yerli kodlarında tanımlanan, ama sadece saf python kodlanmış olabilir ve aynı şekilde çalışmaya devam eder. 5 satır sınıfı körük classmethod
, dahili @classmethod" at all (though distinguishable through introspection such as calls to
isinstance , and even
repr'ında çalışma zamanı farkı olmayan bir dekoratör olarak kullanılabilir ):
class myclassmethod:
def __init__(self, func):
self.__func__ = func
def __get__(self, instance, owner):
return lambda *args, **kw: self.__func__(owner, *args, **kw)
Ve yöntemlerin ötesinde @property
, metasınıfta gibi özel niteliklerin, şaşırtıcı bir davranış olmadan, aynı şekilde, özel sınıf nitelikleri olarak çalışacağını akılda tutmak ilginçtir .