เนื่องจากคลาสเป็นอินสแตนซ์ของ metaclass ดังนั้นจึงไม่เป็นที่คาดหวังว่า "เมธอดอินสแตนซ์" บนเมตาคลาสจะทำงานเหมือนคลาสเมธอด
อย่างไรก็ตามใช่มีความแตกต่าง - และบางส่วนมีความหมายมากกว่า:
- ความแตกต่างที่สำคัญที่สุดคือวิธีการใน metaclass ไม่ได้เป็น "มองเห็น" จากชั้นเรียนเช่น สิ่งนี้เกิดขึ้นเนื่องจากการค้นหาแอททริบิวต์ใน Python (ในทางที่เรียบง่าย - ผู้บรรยายอาจจะมีความสำคัญกว่า) ค้นหาแอททริบิวในอินสแตนซ์ - หากไม่มีอยู่ในอินสแตนซ์ Python จะค้นหาในคลาสของอินสแตนซ์นั้น ซูเปอร์คลาสของคลาสแต่ไม่ได้อยู่ในคลาสของคลาส Python stdlib ใช้ประโยชน์จากคุณสมบัตินี้ใน
abc.ABCMeta.register
วิธีการ คุณลักษณะนั้นสามารถใช้งานได้ดีเนื่องจากวิธีการที่เกี่ยวข้องกับคลาสนั้นสามารถนำกลับมาใช้ใหม่เป็นแอตทริบิวต์ของอินสแตนซ์ได้โดยไม่มีข้อขัดแย้งใด ๆ (แต่วิธีการจะยังคงขัดแย้งกัน)
- ความแตกต่างอื่น ๆ ที่เห็นได้ชัดคือวิธีการที่ประกาศใน metaclass สามารถใช้ได้ในหลาย ๆ คลาสไม่เกี่ยวข้องกัน - ถ้าคุณมีลำดับชั้นของคลาสที่แตกต่างกันไม่เกี่ยวข้องเลยในสิ่งที่พวกเขาจัดการ แต่ต้องการฟังก์ชั่นทั่วไปบางอย่างสำหรับชั้นเรียนทั้งหมด คุณต้องมีคลาส mixin ซึ่งจะต้องรวมเป็นฐานในลำดับชั้นทั้งสอง (พูดเพื่อรวมคลาสทั้งหมดในแอปพลิเคชันรีจิสตรี) (NB. the mixin บางครั้งอาจเป็นการเรียกที่ดีกว่า metaclass)
- classmethod เป็นวัตถุ "classmethod" แบบพิเศษในขณะที่เมธอดใน metaclass เป็นฟังก์ชันปกติ
ดังนั้นจึงเกิดขึ้นว่ากลไกที่ classmethods ใช้คือ " descriptor protocol " ในขณะที่ฟังก์ชั่นปกติมี__get__
วิธีการที่จะแทรกself
อาร์กิวเมนต์เมื่อพวกเขาถูกดึงออกมาจากอินสแตนซ์และปล่อยให้อาร์กิวเมนต์นั้นว่างเปล่าเมื่อดึงมาจากชั้นเรียน classmethod
วัตถุมีความแตกต่าง__get__
ที่จะแทรกชั้นเรียนเอง ("เจ้าของ") เป็น พารามิเตอร์แรกในทั้งสองสถานการณ์
สิ่งนี้ทำให้ไม่มีความแตกต่างในทางปฏิบัติส่วนใหญ่ แต่ถ้าคุณต้องการเข้าถึงวิธีการเป็นฟังก์ชั่นสำหรับวัตถุประสงค์ในการเพิ่มการเพิ่มมัณฑนากรแบบไดนามิกหรืออื่น ๆ สำหรับวิธีการใน metaclass meta.method
ดึงฟังก์ชั่นพร้อมที่จะใช้ ในขณะที่คุณต้องใช้cls.my_classmethod.__func__
เพื่อดึงมันออกมาจาก classmethod (แล้วคุณจะต้องสร้างclassmethod
วัตถุอื่นและกำหนดกลับถ้าคุณทำห่อบาง)
โดยทั่วไปเหล่านี้เป็น 2 ตัวอย่าง:
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)
ในคำอื่น ๆ :นอกเหนือจากความแตกต่างที่สำคัญที่วิธีการที่กำหนดใน metaclass สามารถมองเห็นได้จากอินสแตนซ์และclassmethod
วัตถุไม่ได้ความแตกต่างอื่น ๆ ที่รันไทม์จะดูเหมือนชัดเจนและไร้ความหมาย - แต่ที่เกิดขึ้นเพราะภาษาไม่จำเป็นต้องไป ด้วยกฎพิเศษสำหรับ classmethods: ทั้งสองวิธีในการประกาศ class class เป็นไปได้ซึ่งเป็นผลมาจากการออกแบบภาษา - หนึ่งเนื่องจากข้อเท็จจริงที่ว่าคลาสนั้นเป็นวัตถุตัวเองและอีกวิธีหนึ่งเป็นไปได้ในหมู่คนจำนวนมากของ การใช้โพรโทคอล descriptor ซึ่งอนุญาตให้หนึ่งเข้าถึงการเข้าถึงคุณลักษณะเฉพาะในอินสแตนซ์และในคลาส:
classmethod
builtin ถูกกำหนดไว้ในรหัสพื้นเมือง แต่มันอาจจะเป็นเพียงแค่จะเขียนในหลามบริสุทธิ์และจะทำงานในลักษณะเดียวกันแน่นอน ร้องระดับ 5 บรรทัดสามารถใช้เป็นclassmethod
มัณฑนากรที่ไม่มีความแตกต่างแบบรันไทม์สำหรับการแก้ไข@classmethod" at all (though distinguishable through introspection such as calls to
isinstance ในตัว, and even
`):
class myclassmethod:
def __init__(self, func):
self.__func__ = func
def __get__(self, instance, owner):
return lambda *args, **kw: self.__func__(owner, *args, **kw)
และนอกเหนือจากวิธีการเป็นที่น่าสนใจที่จะทราบว่าคุณลักษณะพิเศษเช่น@property
บน metaclass จะทำงานเป็นคุณลักษณะคลาสเฉพาะเช่นเดียวกันโดยไม่มีพฤติกรรมที่น่าแปลกใจเลย