1. 程式人生 > >看完必會超程式設計

看完必會超程式設計

超程式設計

超程式設計的概念來自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__()方法中,可以獲取元類資訊、當前類、基類、類屬性字典。

超程式設計一般用於框架開發中。