探討 Python 的物件生成 - tsungjung411/python-study GitHub Wiki
主題:
- 動態生成 class
- Singleton 實作方式(non thread safe)
動態生成 class:
class A:
def show(msg):
print('A.msg: {}'.format(msg))
def showB(msg):
print('B.msg: {}'.format(msg))
def __init__():
print('__init__')
# dynamically define class B
class_name = 'B'
bases = (A,)
members = {
'__init__': __init__,
'showB': showB,
}
b = type(class_name, bases, members)
print('class B:', b)
print('base class of B:', b.__bases__)
print('b.mro():', b.mro())
b.show('hello')
b.showB('hello')
執行結果:
class B: <class '__main__.B'>
base class of B: (<class '__main__.A'>,)
b.mro(): [<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
A.msg: hello
B.msg: hello
Singleton 實作方式(non thread safe) - 範例一:
class A:
def __init__(self):
print('A.__init__()')
# end-of-def
def show(self):
print('A.show()')
# end-of-def
# end-of-class
class B(A):
__instance = None
def __init__(self):
print('B.__init__()')
# end-of-def
def __new__(cls, *args, **kwargs):
print('B.__new__({}, {}, {})'.format(cls, args, kwargs))
if not cls.__instance:
cls.__instance = super().__new__(cls, *args, **kwargs)
print('B.__new__(): first new')
return cls.__instance
# end-of-def
def show(self):
super().show()
# end-of-def
# end-of-class
print('flow: __new__() -> __init__()')
print('-' * 45)
b1 = B()
b1.show()
print('-' * 45)
b2 = B.__call__() # equivalent to B()
b2.show()
print('-' * 45)
print('b1:', b1)
print('b2:', b2)
print('id(b1):', hex(id(b1)))
print('id(b2):', hex(id(b2)))
執行結果:
flow: __new__() -> __init__()
---------------------------------------------
B.__new__(<class '__main__.B'>, (), {})
B.__new__(): first new
B.__init__()
A.show()
---------------------------------------------
B.__new__(<class '__main__.B'>, (), {})
B.__init__()
A.show()
---------------------------------------------
b1: <__main__.B object at 0x7ffaf09d14e0>
b2: <__main__.B object at 0x7ffaf09d14e0>
id(b1): 0x7ffaf09d14e0
id(b2): 0x7ffaf09d14e0
__init__()
會呼叫兩次
Singleton 實作方式(non thread safe) - 範例二:
class A:
def __init__(self):
print('A.__init__()')
# end-of-def
def show(self):
print('A.show()')
# end-of-def
# end-of-class
# if not inherited from type, an error will happen:
# TypeError: object() takes no parameters
class SingletonB(type):
__instance = None
def __call__(cls, *args, **kwargs):
print('>> B.__call__({}, {}, {})'.format(cls, args, kwargs))
if not cls.__instance:
cls.__instance = super().__call__(*args, **kwargs)
# end-of-if
print('<< B.__call__():', cls.__instance)
return cls.__instance
# end-of-def
# end-of-class
class B(A, metaclass=SingletonB):
def __init__(self):
print('B.__init__()')
# end-of-def
def __new__(cls, *args, **kwargs):
print('B.__new__({}, {}, {})'.format(cls, args, kwargs))
return super().__new__(cls, *args, **kwargs)
# end-of-def
def show(self):
super().show()
# end-of-def
# end-of-class
print('flow: __call__() -> __new__() -> __init__()')
print('-' * 45)
b1 = B()
b1.show()
print('-' * 45)
b2 = B.__call__() # equivalent to B()
b2.show()
print('-' * 45)
print('b1:', b1)
print('b2:', b2)
print('id(b1):', hex(id(b1)))
print('id(b2):', hex(id(b2)))
執行結果:
flow: __call__() -> __new__() -> __init__()
---------------------------------------------
>> B.__call__(<class '__main__.B'>, (), {})
B.__new__(<class '__main__.B'>, (), {})
B.__init__()
<< B.__call__(): <__main__.B object at 0x7ffaf091cba8>
A.show()
---------------------------------------------
>> B.__call__(<class '__main__.B'>, (), {})
<< B.__call__(): <__main__.B object at 0x7ffaf091cba8>
A.show()
---------------------------------------------
b1: <__main__.B object at 0x7ffaf091cba8>
b2: <__main__.B object at 0x7ffaf091cba8>
id(b1): 0x7ffaf091cba8
id(b2): 0x7ffaf091cba8
__init__()
只會呼叫一次