Python中的元编程

Python中的元编程

文章目录

  • Python中的元编程
    • type类
    • 构建元类
    • 元类的应用
    • 元编程总结

  • 元编程概念来自LISP和smalltalk。
  • 如果自己写的代码,能生成我们需要的代码。这就是元编程。即用代码生成代码。或者说用代码生成特定的类。例如:常用的class类,是否能够用代码直接生成class类,而不是用关键字class来定义。
  • 用来生成代码的程序称为元编程metaprogram,编写这种程序就称为元编程metaprogramming
  • Python语言能够通过反射实现元编程。
    1. Python中
      • 所有非object类都继承自object类
      • 所有类的类型包括type类都是type
      • type类继承自object类,object类的类型也是type类

type类

  • type构建类

    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
    
  1. type(object) -> the object's type,返回对象的类型,例如type(10)
  2. type(name,bases,dict) -> a new type 返回一个新的类型
    • name 新类的类名
    • bases 新类的继承关系,一个元组,默认继承object
    • dict 新类的字典,可以为新类添加类属性
  • 简单示例:
XClass = type("myclass",(object,),{"a":100,"b":"string"}) # 字典是类属性
print(XClass)
print(XClass.__dict__)
print(XClass.__name__)
print(XClass.__bases__)
print(XClass.mro())

Python中的元编程_第1张图片

  • 使用type构建复查的类

def init(self):
    self.x = 1000

def show(self):
    print("我是实例方法",self.__dict__)

@classmethod
def show1(cls):
    print("类方法",cls)

XClass = type("myclass",(object,),{"a":100,"b":"string",
                                   "show1":show1,"show":show,"__init__":init})

print(XClass)
print(XClass.__name__)
print(XClass.__dict__)
print(XClass.mro())

print("- "*30)
# 使用类方法
XClass.show1()

# 使用实例方法
xclass = XClass()
xclass.show()
print(xclass.x)

Python中的元编程_第2张图片

  • 可以借助type构造任何类,用代码来生成代码,这就是元编程。

构建元类

  • 如果一个类继承了type类,那么这个类就是个元类。元类可以直接用来使用,元类可以用来创造类。
  • 在定义一个类的时候,会使用该类所指定的元类中的__new__方法类创建该类。
  • 默认类的元类是metaclass = type可以在类的继承体系括号中添加该参数为类指定该元类
  • 如果一个类的元类会从父类中继承下来。
class Mode(type):
    def __new__(cls,*args,**kwargs):
        print(cls)
        print(args)
        print(kwargs)
        print()
        return super().__new__(cls,*args,**kwargs) #调用父类方法构建实例

class A(metaclass=Mode): #改变A类的元类,默认元类是type
    id = 1000

    def __init__(self):
        print("A.init--------------")

# 第二种 B继承A后,元类依然是A中所指定的元类
class B(A):
    def __init__(self):
        print("B.init~~~~~~~~~~~")

# 第三种,元类可以使用下面的方式创建新的类
C = Mode("C",(),{})

# D、E是type的实例
class D:pass #等价于 D = type("D",(),{})
E = type("E",(),{})

class F(Mode):pass

print("= "*40)
print(type(A),A.__bases__)
print(type(B),B.__bases__)
print(type(C),C.__bases__)
print()

print(type(D),D.__bases__)
print(type(E),E.__bases__)
print()

print(type(F),F.__bases__)

Python中的元编程_第3张图片

  • 从运行结果还可以分析出__new__(cls,*args,**kwargs)的参数解构。中间是一个元组('A', (), {'__module__': '__main__', '__qualname__': 'A', 'id': 1000, '__init__': })对应(name,bases,dict)
  • 由此可以修改自定义元类代码为:
class Mode(type):
    def __new__(cls,name,bases,dt:dict):
        print(cls)
        print(name)
        print(bases)
        print(dt,"--------")
        return super().__new__(cls,name,bases,dt) #调用父类方法构建实例
  • 从运行结果可以看出,只要元类是Mode,创建类对象时,就会调用Mode的__new__方法。
  • 上例中,F也是元类,F–继承自–》Mode–继承自–》type。type(元类)返回type。但是type(被metaclass修改了的元类的类返回其元类。)

元类的应用

  • 本示例模拟sqlAlchemy中标定义时继承的Base,和字段类型Column的原理。(这里不做描述器的演示)
class Column:
    def __init__(self,fieldname=None,pk=False,nullable=False):
        self.fieldname = fieldname
        self.pk = pk
        self.nullable = nullable

    def __repr__(self):
        return "<{} {}>".format(__class__.__name__,self.fieldname)

class ModelMeta(type):
    def __new__(cls,name,bases,attrs:dict):
        print(name,bases,attrs)

        if "__tablename__" not in attrs:
            attrs["__tablename__"] = str.lower(name)

        primarykeys = []
        # 为类动态绑定属性
        for k,v in attrs.items():
            if isinstance(v,Column):
                if v.fieldname is None or v.fieldname.strip() == "":
                    v.fieldname = k #指段没有名字使用属性名
                if v.pk:
                    primarykeys.append(v)

        attrs["__primarykeys__"] = primarykeys
        return super().__new__(cls,name,bases,attrs)

class Base(metaclass=ModelMeta):
    """继承Base的类的元类都是ModelMety"""
    pass

class Student(Base):
    id = Column(pk=True,nullable=False)
    name = Column("username",nullable=False)
    ags = Column()

print("- "*30)
print(Student.__dict__)

Python中的元编程_第4张图片

元编程总结

  • 元类是制造类的工厂,是用来构造类的类。
  • 构造好元类,就可以在类定义时,使用关键字参数metaclass指定元类,可以使用最原始的metatype(name,bases,dict)的方式构造一类。
  • 元类的__new__()方法中,可以获取元类信息、当前类、基类、类属性字典。
  • 元编程一般用于框架开发中。
    1. 开发中除非你明确的知道自己在干什么,否则不要随便使用元编程
  • Django、SQLAlchemy使用了元类,让我们使用起来很方便。

你可能感兴趣的:(python基本知识)