看完必會超程式設計
阿新 • • 發佈:2018-11-23
超程式設計
超程式設計的概念來自LISP和smalltalk。
用來生成程式碼的程式稱為元程式metaprogram,編寫這種程式就稱為超程式設計metaprogramming。
python主要通過反射來實現超程式設計。
Python中
所有非object類都繼承自Object類
所有類的型別包括type類都是type
type類繼承自object類,object類的型別也是type類
type類
type構建類
class type(object):
def __init__(cls, what, bases=None, dict= None): # known special case of type.__init__
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
# (copied from class doc)
"""
pass
構建
def __init__(self):
self.x = 1000
def show(self):
return self.__dict__
XClass = type('myclass', (object,), {'a':100, 'b': 'string', 'show':show, '__init__':__init__}) # 字典是類屬性 print(XClass)
print(XClass)
print(XClass.__name__)
print(XClass.__dict__)
print(XClass.mro())
XClass().show()
可以藉助type構造任何類,用程式碼生成程式碼,這就是超程式設計。
構建元類
一個類可以繼承自type類
class ModelMeta(type):
def __new__(cls, *args):
print(cls)
print(*args)
return super().__new__(cls, *args)
繼承自type,ModelMeta就是元類,它可以創建出其他類。
class ModelMeta(type): # 繼承自type
def __new__(cls, name, bases, attrs: dict):
print(cls)
print(name)
print(bases)
print(attrs)
print("--------")
return super().__new__(cls, name, bases, attrs)
# 第一種 使用metaclass關鍵字引數指定元類
class A(metaclass=ModelMeta):
id = 100
def __init__(self):
self.x = 2000
# 第二種 B繼承自A後,依然是從ModelMeta的型別
class B(A): # 繼承
pass
# 第三種 元類就可以使用下面的方式建立新的類
C = ModelMeta('Class', (), {'y': 200})
print(type(A))
print(type(B))
print(type(C))
從執行結果還可以分析出__new__(cls, *args)
的引數結構
中間是一個元組 ('A', (), {'__init__': <function A.__init__ at 0x0000000000B6E598>, '__module__':'__main__', '__qualname__': 'A', 'id': 100})
對應 (name, bases, dict)
從執行結果可以看出,只要元類是ModelMeta,建立類物件時,就會呼叫ModelMeta的__new__
方法
元類的應用
class Field:
def __init__(self, fieldname=None, pk=False, nullable=False):
self.fieldname = fieldname
self.pk = pk
self.nullable = nullable
def __repr__(self):
return "<Field {}>".format(self.fieldname)
class ModelMeta(type): # 繼承自type
def __new__(cls, name, bases, attrs: dict):
print(cls)
print(name)
print(bases)
print(attrs, '-------------')
# 使用元類動態注入表名
tblname = '__tablename__'
if tblname not in attrs.keys():
attrs[tblname] = name
primarykeys = []
for k, v in attrs.items():
if isinstance(v, Field):
print(k)
print(v)
print(v.fieldname)
if v.fieldname is None:
v.fieldname = k # 沒有名字則使用屬性名
if v.pk:
primarykeys.append(v)
attrs['__primarykeys__'] = primarykeys
return super().__new__(cls, name, bases, attrs)
class ModelBase(metaclass=ModelMeta):
pass
class Student(ModelBase):
id = Field(pk=True, nullable=False)
name = Field('username', nullable=False)
age = Field()
print('----------------')
print(Student.__dict__)
超程式設計的總結
元類是製造類的工廠,是生成類的類。
構造好元類,就可以在類定義時,使用關鍵字引數metaclass指定元類,可以使用最原始的metatype(name,
bases, dict)的方式構造一個類。
元類的 __new__()
方法中,可以獲取元類資訊、當前類、基類、類屬性字典。
超程式設計一般用於框架開發中。