Sự khác biệt tinh tế trở nên rõ hơn một chút khi bạn quan sát cẩn thận thứ tự thực hiện của các phương pháp này.
class Meta_1(type):
def __call__(cls, *a, **kw):
print "entering Meta_1.__call__()"
rv = super(Meta_1, cls).__call__(*a, **kw)
print "exiting Meta_1.__call__()"
return rv
class Class_1(object):
__metaclass__ = Meta_1
def __new__(cls, *a, **kw):
print "entering Class_1.__new__()"
rv = super(Class_1, cls).__new__(cls, *a, **kw)
print "exiting Class_1.__new__()"
return rv
def __init__(self, *a, **kw):
print "executing Class_1.__init__()"
super(Class_1,self).__init__(*a, **kw)
Lưu ý rằng đoạn mã trên không thực sự làm bất cứ điều gì khác hơn là đăng những gì chúng ta đang làm. Mỗi phương thức đều ngăn cản việc triển khai cha mẹ của nó, tức là phương thức mặc định của nó. Vì vậy, bên cạnh khai thác gỗ đó là một cách hiệu quả, nếu như bạn đã chỉ đơn giản tuyên bố điều như sau:
class Meta_1(type): pass
class Class_1(object):
__metaclass__ = Meta_1
Và bây giờ chúng ta hãy tạo một thể hiện của Class_1
c = Class_1()
# entering Meta_1.__call__()
# entering Class_1.__new__()
# exiting Class_1.__new__()
# executing Class_1.__init__()
# exiting Meta_1.__call__()
Vì vậy nếu type
là phụ huynh của Meta_1
chúng ta có thể tưởng tượng một pseudo triển khai type.__call__()
như vậy:
class type:
def __call__(cls, *args, **kwarg):
# ... a few things could possibly be done to cls here... maybe... or maybe not...
# then we call cls.__new__() to get a new object
obj = cls.__new__(cls, *args, **kwargs)
# ... a few things done to obj here... maybe... or not...
# then we call obj.__init__()
obj.__init__(*args, **kwargs)
# ... maybe a few more things done to obj here
# then we return obj
return obj
Thông báo từ cuộc gọi orde r ở trên số Meta_1.__call__()
(hoặc trong trường hợp này là type.__call__()
) có cơ hội ảnh hưởng đến việc có hay không gọi đến số Class_1.__new__()
và Class_1.__init__()
sau cùng được thực hiện. Trong quá trình thực hiện, Meta_1.__call__()
có thể trả lại một đối tượng mà thậm chí không bị chạm vào. Lấy ví dụ phương pháp này để mô hình singleton:
class Meta_2(type):
__Class_2_singleton__ = None
def __call__(cls, *a, **kw):
# if the singleton isn't present, create and register it
if not Meta_2.__Class_2_singleton__:
print "entering Meta_2.__call__()"
Meta_2.__Class_2_singleton__ = super(Meta_2, cls).__call__(*a, **kw)
print "exiting Meta_2.__call__()"
else:
print ("Class_2 singleton returning from Meta_2.__call__(), "
"super(Meta_2, cls).__call__() skipped")
# return singleton instance
return Meta_2.__Class_2_singleton__
class Class_2(object):
__metaclass__ = Meta_2
def __new__(cls, *a, **kw):
print "entering Class_2.__new__()"
rv = super(Class_2, cls).__new__(cls, *a, **kw)
print "exiting Class_2.__new__()"
return rv
def __init__(self, *a, **kw):
print "executing Class_2.__init__()"
super(Class_2, self).__init__(*a, **kw)
Hãy quan sát những gì xảy ra khi liên tục cố gắng để tạo ra một đối tượng kiểu Class_2
a = Class_2()
# entering Meta_2.__call__()
# entering Class_2.__new__()
# exiting Class_2.__new__()
# executing Class_2.__init__()
# exiting Meta_2.__call__()
b = Class_2()
# Class_2 singleton returning from Meta_2.__call__(), super(Meta_2, cls).__call__() skipped
c = Class_2()
# Class_2 singleton returning from Meta_2.__call__(), super(Meta_2, cls).__call__() skipped
print a is b is c
True
Bây giờ quan sát thực hiện này sử dụng một lớp __new__()
phương pháp thử để thực hiện điều tương tự.
import random
class Class_3(object):
__Class_3_singleton__ = None
def __new__(cls, *a, **kw):
# if singleton not present create and save it
if not Class_3.__Class_3_singleton__:
print "entering Class_3.__new__()"
Class_3.__Class_3_singleton__ = rv = super(Class_3, cls).__new__(cls, *a, **kw)
rv.random1 = random.random()
rv.random2 = random.random()
print "exiting Class_3.__new__()"
else:
print ("Class_3 singleton returning from Class_3.__new__(), "
"super(Class_3, cls).__new__() skipped")
return Class_3.__Class_3_singleton__
def __init__(self, *a, **kw):
print "executing Class_3.__init__()"
print "random1 is still {random1}".format(random1=self.random1)
# unfortunately if self.__init__() has some property altering actions
# they will affect our singleton each time we try to create an instance
self.random2 = random.random()
print "random2 is now {random2}".format(random2=self.random2)
super(Class_3, self).__init__(*a, **kw)
Chú ý rằng việc thực hiện ở trên mặc dù đăng ký thành công một singleton trên lớp, không ngăn cản __init__()
khỏi bị gọi là, điều này xảy ra ngầm trong type.__call__()
(type
là metaclass mặc định nếu không chỉ định). Điều này có thể dẫn đến một số hiệu ứng không mong muốn:
a = Class_3()
# entering Class_3.__new__()
# exiting Class_3.__new__()
# executing Class_3.__init__()
# random1 is still 0.282724600824
# random2 is now 0.739298365475
b = Class_3()
# Class_3 singleton returning from Class_3.__new__(), super(Class_3, cls).__new__() skipped
# executing Class_3.__init__()
# random1 is still 0.282724600824
# random2 is now 0.247361634396
c = Class_3()
# Class_3 singleton returning from Class_3.__new__(), super(Class_3, cls).__new__() skipped
# executing Class_3.__init__()
# random1 is still 0.282724600824
# random2 is now 0.436144427555
d = Class_3()
# Class_3 singleton returning from Class_3.__new__(), super(Class_3, cls).__new__() skipped
# executing Class_3.__init__()
# random1 is still 0.282724600824
# random2 is now 0.167298405242
print a is b is c is d
# True
Không! '__new__' trên metaclass xảy ra khi _class_ được tạo, không phải là _instance_.'__call__' xảy ra khi' __new__' xảy ra mà không có metaclass. – agf
Tôi nói rằng '__new__' liên quan đến việc tạo ví dụ ở đâu? – pyroscope
Tôi đã thực sự hỏi về '__new__' của lớp, không phải là' __new__' của metaclass. –