python学习--元编程

元编程概念来自LISP和smalltalk
用来生成代码的程序称为元程序metaprogram,编写这种程序就称为元编程metaprogramming
Python语言能够通过反射实现元编程

Python中
所有非object类都继承自object类
所有类的类型包括type类都是type
type类继承自object类,object类的类型也是type类

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

type(object) -> the object's type ,返回对象的类型,例如type(10)返回int类型
type(name, bases, dict) -> a new type 返回一个新的类型
what是构建类的名字
bases是构建类的基类, 默认是None(基类是object类)
dict是构建类的类字典

def __init__(self):
    self.x = 1000

def show(self):
    print(self.x)

XClass = type("x", (object,), {'a':100, 'b':'abc',
                               '__init__':__init__,
                               'show':show})
print(XClass)
print(XClass.__name__)
print(XClass.__bases__)
print(XClass.mro())
print(XClass().a)
print(XClass.__dict__)
print(XClass().x)
print(XClass().show())

#运行结果:
<class '__main__.x'>
x
(<class 'object'>,)
[<class '__main__.x'>, <class 'object'>]
100
{'a': 100, 'b': 'abc', '__init__': <function __init__ at 0x0000024344784A60>, 'show': <function show at 0x0000024344784AE8>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'x' objects>, '__weakref__': <attribute '__weakref__' of 'x' objects>, '__doc__': None}
1000
1000
None

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

构建元类

一个类可以继承自type类

class MetaClass(type):
	def __new__(cls, *args, **kwargs):
		print(cls)
		print(args)
		print(kwargs)
		return super().__new__(cls, *args,**kwargs)

继承自type类, MetaClass就是元类, 它可以创建出其他类

class MetaClass(type): # 继承自type
    def __new__(cls, *args, **kwargs):
        print(cls)
        print(args)
        print(kwargs)
        print()
        return super().__new__(cls, *args, **kwargs)

class A(metaclass=MetaClass): # 元类默认type, 改成Metaclass
    id = 200

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

class B(A): # 继承时, 元类与父类的元类相同
    pass

C = MetaClass('C', (), {}) # 元类使用这种方式构建新的类

print(type(A), A.__bases__)
print(type(B), B.__bases__)
print(type(C), C.__bases__)

# D, E是type的实例
class D:pass # D = type('D', (), {})
E = type('E', (), {})
print(type(D), D.__bases__)
print(type(E), E.__bases__)

print("==============")

class F(MetaClass):pass # F继承自MetaClass

print(type(F), F.__bases__)
<class '__main__.MetaClass'>
('A', (), {'__module__': '__main__', '__qualname__': 'A', 'id': 200, '__init__': <function A.__init__ at 0x000001C4BC4D4F28>})
{}

<class '__main__.MetaClass'>
('B', (<class '__main__.A'>,), {'__module__': '__main__', '__qualname__': 'B'})
{}

<class '__main__.MetaClass'>
('C', (), {})
{}

<class '__main__.MetaClass'> (<class 'object'>,)
<class '__main__.MetaClass'> (<class '__main__.A'>,)
<class '__main__.MetaClass'> (<class 'object'>,)
<class 'type'> (<class 'object'>,)
<class 'type'> (<class 'object'>,)
==============
<class 'type'> (<class '__main__.MetaClass'>,)

从运行结果可以分析出__new__(cls, *args, **kwargs)的参数结构
中间是一个元组('A', (), {'__module__': '__main__', '__qualname__': 'A', 'id': 200, '__init__': <function A.__init__ at 0x000001C4BC4D4F28>})
对应(name, bases, dict)
修改代码如下:

class MetaClass(type): # 继承自type
    def __new__(cls, name, bases, dict):
        print(cls)
        print(name)
        print(bases)
        print(dict)
        return super().__new__(cls, name, bases, dict)

从运行结果可以看出,只要元类是MetaClass, 创建类对象时, 就会调用MetaClass的__new__方法
上例中,F也是元类, F --继承自–> ModelMeta --继承自–> type。type(元类) 返回type。但是type(被metaclass修改了的元类的类)返回其元类, 就像A修改了元类为MetaClass, type(A)返回MetaClass, 继承A的B类也继承了基类的元类

元类的应用

以sqlalchemy模块为例, 不考虑内部描述器实现, 简单实现基本属性, 主要看元编程应用过程

# 不考虑描述器, 元编程实验例子
class Column:
    def __init__(self, filename=None, pk=False, nullable=False):
        self.filename = filename
        self.pk = pk
        self.nullable = nullable

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

# 简单基本属性实现
class ModelMeta(type):
    def __new__(cls, name, bases, attrs:dict):
        print(cls)
        print(name, bases, attrs)

        if '__tablename__' not in attrs:
            attrs['__tablename__'] = name.lower() # 添加表名

        primarykeys = []
        for k, v in attrs.items():
            if isinstance(v, Column):
                if v.filename is None or v.filename.strip() == '':
                    v.filename = k # 字段没有名字使用属性名
                if v.pk: # 主键
                    primarykeys.append(v)

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

class Base(metaclass=ModelMeta):
    """从MedolBase继承的类的类型都是ModelMeta"""

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

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

元编程总结

元类是制造类的工厂,是用来构造类的类。
构造好元类, 就可以在类定义时, 使用关键字参数metaclass指定元类, 可以使用最原始的metatype(name,bases, dict)的方式构造一个类
元类的 __new__()方法中,可以获取元类信息、当前类、基类、类属性字典。

元编程一般用于框架开发中

开发中除非你明确的知道自己在干什么,否则不要随便使用元编程

Django、SQLAlchemy使用了元类,让我们使用起来很方便

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值