Python Class and Instance Instantiation Behavior

Python Class and Instance Instantiation Behavior

__new__ and __init__ Function

  • __new__
    • Official document
    • 為Class function
      • 用了特殊方法,所以實現時不用特別寫上@classmethod裝飾器
    • 主要用途: 構建Instance
    • return:
      • 自身Class對應的Instance,並作為__init__的第一個參數,及為self
      • 其他Class對應的Instance,會呼叫對應的__init__
  • __init__
    • Official document
    • 為Object function
    • 主要用途: 初始化Object變量
    • return: 不允許返回任何值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Some:
def __new__(cls, *agrs, **kwargs):
print('>> __new__')
instance = object.__new__(cls)
return instance
def __init__(self, name):
print('>> __init__')
self.name = name
if __name__ == '__main__':
car = Some('car')
print('name: {}'.format(car.name))
print('type of Some: {}'.format(type(Some)))
print('type of car: {}'.format(type(car)))
""" output
>> __new__
>> __init__
name: Car
type of Some: <class 'type'>
type of car: <class '__main__.Some'>
""

Metaclass

  • 在Python中,Class也是一個Object,代表Class與其他Object一樣,都有建立與初始化的過程與相關函數
    • Class建立的時機是當所在的module被import的時候
  • Metaclass即是定義Class object建立與初始化過程的角色
  • Python預設使用type作為Metaclass的實作
    • 若在自身Object中宣告的Metaclass則使用指定的Metaclass,否則尋找父類是否有指定並使用之;若一路往上都沒有找到宣告Metaclass的語句,則只用type作為Metaclass的實作
    • 可以透過繼承type來實作Metaclass,達到改變Class的建立與初始化過程
    • 在初始化install時,會呼叫Metaclass的__call__
      • 若在自己實作的Metaclass中沒有實作__call__,則呼叫type的__call__
      • type中的__call__預設會呼叫Class的__new__ 與 __init__
  • type本身也是一個type Metaclass的instance,換句話說,type是本身的instance
  • Metaclass可以是任何具有__call__()的物件,Python會呼叫所指定物件的__call__()方法,並將物件本身、類別名稱、父類別資訊與特性作為參數傳入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class SomeMeta(type):
def __new__(cls, cls_name, bases, attrs):
print('>> SomeMeta.__new__')
return type.__new__(cls, cls_name, bases, attrs)
def __init__(self, cls_name, bases, attrs):
print('>> SomeMeta __init__')
def __call__(self, *args, **kwargs):
print('>> SomeMeta.__call__')
return super(SomeMeta, self).__call__(*args, **kwargs)
class Some(metaclass=SomeMeta):
def __new__(cls, *agrs, **kwargs):
print('>> __new__')
instance = object.__new__(cls)
return instance
def __init__(self, name):
print('>> __init__')
self.name = name
if __name__ == '__main__':
print('\n=== __main__ ===\n')
print('class of SomeMeta: {}'.format(SomeMeta.__class__))
car = Some("Car")
print("name: {}".format(car.name))
print('type of Some: {}'.format(type(Some)))
print('type of car: {}'.format(type(car)))
""" output
>> SomeMeta.__new__
>> SomeMeta __init__
=== __main__ ===
>> SomeMeta.__call__
>> __new__
>> __init__
name: Car
type of SomeMeta: <class 'type'>
type of Some: <class '__main__.SomeMeta'>
type of car: <class '__main__.Some'>
"""