元编程
元编程概述
一般写程序就是直接写代码,能否用代码生成所需的代码?例如,写了一个类 class A,能否用代码生成一个类出来?
用来生成代码的程序称为元程序 metaprogram,编写这种程序就称为元编程 metaprogramming。
python能通过反射实现元编程。在python中:
- 所有非object类都继承自object类;
- 在 Python 中,所有的类都可以追溯到 object 类,这意味着 object 类是所有类的基类。这种继承关系意味着所有类都继承了 object 类的属性和方法。
- 所有类的类型包括type类都是type;
- 在 Python 中,类本身也是对象,它们的类型是 type。这包括了普通的类以及 type 类本身。
- type类继承自object类,object类的类型也是type类。
- 这意味着 type 类本身也是一个对象,它继承了 object 类的属性和方法。同时,object 类的类型也是 type 类,因为 object 类是一个类,而类的类型是 type。
这些概念在元编程中非常重要,因为它们揭示了类和对象之间的关系,以及如何使用反射和元编程技术来操作类和对象。
—
Python中的元编程是指在运行时创建或修改Python代码的能力。这种技术允许程序在运行时动态地生成类、函数、方法和模块,或者在运行时修改它们的行为。元编程通常用于创建通用框架、装饰器、插件系统等。
Python提供了几种元编程的机制,包括:
-
元类(Metaclasses):元类是用于创建类的类。通过定义自己的元类,您可以控制类的创建过程。元类的
__new__和__init__方法可以用来拦截类的创建过程,并且允许您在类创建时进行自定义操作。 -
装饰器(Decorators):装饰器是用于修改函数、方法或类的行为的函数。它们允许您在不修改原始对象的情况下,动态地添加额外的功能。装饰器是Python元编程中常用的技术之一,用于实现日志记录、性能分析、权限检查等功能。
-
类装饰器(Class Decorators):类装饰器是用于修改类行为的装饰器。它们允许您在类定义时对类进行修改或增强。类装饰器可以用于实现单例模式、缓存类实例等功能。
-
元编程模块(Metaprogramming modules):Python标准库中的一些模块提供了元编程的支持,如
inspect模块用于检查对象的属性和源代码,ast模块用于操作抽象语法树(AST),types模块用于动态创建新类型等。 -
动态属性和方法:Python允许在运行时动态地添加、修改或删除对象的属性和方法。这种灵活性使得在运行时根据需要动态地修改对象成为可能,这对于某些特定的应用场景非常有用。
元编程是Python中非常强大且灵活的一部分,但也需要谨慎使用,因为它可以使代码更加复杂和难以理解。优秀的元编程代码应该具有清晰的文档和易于理解的设计。
元编程通常与面向对象编程(Object-Oriented Programming,OOP)概念相关联,因为它涉及到在运行时创建、修改或操作类、对象和其行为。
在面向对象编程中,类是对象的蓝图,它定义了对象的属性和方法。元编程提供了一种在程序运行时动态创建、修改或扩展这些类和对象的能力,从而增强了面向对象编程的灵活性和可扩展性。
通过元编程,您可以在运行时创建新的类,添加新的方法或属性,或者修改现有类的行为,而无需在代码编写阶段静态定义它们。这使得代码可以更具动态性,并且可以根据需要进行自我适应或扩展。因此,尽管元编程是一个独立的概念,但通常与面向对象编程一起使用,以提供更灵活和强大的编程范式。
type 类
type是元类,是构造其他类的类。
在 Python 中,type 是一个内置的元类,它用于创建 Python 中的所有类。type 类本身也是一个类,同时也是自身的实例。
以下是关于 type 类的一些详解:
-
创建类对象:使用
type类可以动态地创建类对象。通常,我们可以使用类定义语法来创建类,但是type类提供了一种以编程方式创建类的方式。例如,下面的代码使用type类创建了一个名为MyClass的类:MyClass = type('MyClass', (), {})这行代码的作用等同于下面的类定义语法:
class MyClass: pass -
类的元类:
type本身也是一个元类,用于创建其他类的类。在 Python 中,所有的类都是type类的实例,包括type类本身。这种特性使得type成为 Python 中元编程的基础。 -
type的构造函数:type类具有构造函数的功能。其签名如下:type(name, bases, dict)name是要创建的类的名称。bases是一个元组,表示新类的基类。如果新类没有基类,则应传入一个空元组()。dict是一个字典,包含新类的属性和方法。
-
探索类的信息:
type类也提供了一些方法来探索类的信息,例如type.__name__可以获取类的名称,type.__bases__可以获取类的基类。 -
元类的自定义:通过继承
type类并覆盖其方法,可以自定义元类,从而控制类的创建过程和行为。这种能力使得 Python 中的元编程变得非常灵活。
总的来说,type 类在 Python 中具有重要的地位,它是类创建的基础,也是元编程的核心。通过了解和使用 type 类,可以更深入地理解 Python 中的类和对象模型,以及如何利用元编程来实现更加灵活和动态的代码结构。
示例1
## type(name, bases, dict, **kwds) -> a new type
XClass = type('X', (), {}) # x是名字,给人看的。XClass是标识符,给程序员用的。
print(XClass) # <class '__main__.X'>
print(type(XClass)) # <class 'type'>
print(XClass.__name__) # X等价于:
class YClass: pass # 可以理解为这是一种通过语法糖的创建方式。通过这种方式定义,标识符和name同名
print(YClass) # <class '__main__.YClass'>
print(type(YClass)) # <class 'type'>
print(YClass.__name__) # YClass示例2
## type(name, bases, dict, **kwds) -> a new type
XClass = type('X', (object, ), {})
print(XClass.__bases__) # (<class 'object'>,)等价于:
class YClass(object): pass
print(YClass.__bases__) # (<class 'object'>,)示例3
## type(name, bases, dict, **kwds) -> a new type
XClass = type('X', (list, ), {})
print(XClass.__bases__) # (<class 'list'>,)
a = XClass()
print(a) # []
a.append(1)
a.extend(range(10, 15))
print(a) # [1, 10, 11, 12, 13, 14]示例4
def a(self):
print('init~~~')
self.x = 1000
def show(self):
print(self.x)
XClass = type('X', (list, ), {'a': 123, 'b': 'abc', '__init__': a, 'show': show})
print(XClass.__dict__) # {'a': 123, 'b': 'abc',...
x = XClass()
print(x)
'''
init~~~
[]
'''
print(x.__dict__) # {'x': 1000}
x.show() # 1000等价于:
class XClass(list):
a = 123
b = 'abc'
def __init__(self):
print('init~~~')
self.x = 1000
def show(self):
print(self.x)
print(XClass.__dict__) # {'a': 123, 'b': 'abc',...
x = XClass()
print(x)
'''
init~~~
[]
'''
print(x.__dict__) # {'x': 1000}
x.show() # 1000示例5
—
实际应用1
class ModelMeta(type):
def __new__(cls, name, bases, attrs):
print('Meta ~~~')
return super().__new__(cls, name, bases, attrs)
class Model(metaclass=ModelMeta):
pass
class Student(Model):
pass
## 输出两次:
'''
Meta ~~~
Meta ~~~
'''实际应用2
class Field:
def __init__(self, fieldname=None, pk=False, nullable=False):
self.fieldname = fieldname
self.pk = pk
self.nullable = nullable
class ModelMeta(type):
def __new__(cls, name, bases, attrs):
print('Meta ~~~')
return super().__new__(cls, name, bases, attrs)
class Model(metaclass=ModelMeta):
pass
class Student(Model):
id = Field(pk=True, nullable=False)
name = Field(fieldname='username', nullable=False)
age = Field(nullable=True)
def __repr__(self):
return '<Field {{} {} {}}>'.format(
self.id, self.name, self.age
)
__str__ = __repr__实际应用3
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, self.pk, self.nullable
)
__str__ = __repr__
class ModelMeta(type):
def __new__(cls, name, bases, attrs):
print('Meta ~~~')
if name != 'Model':
primarykeys = []
print(name)
print(bases)
print(attrs)
if 'db_table' not in attrs:
print('-' * 30)
attrs['db_table'] = name
for k, v in attrs.items():
# print(f"Key: {k}, Value: {v}")
if isinstance(v, Field):
if not v.fieldname or v.fieldname.strip() == '':
v.fieldname = k
if v.pk:
primarykeys.append(v)
attrs['primarykeys'] = primarykeys
print(attrs)
return super().__new__(cls, name, bases, attrs)
class Model(metaclass=ModelMeta):
pass
class Student(Model):
id = Field(pk=True, nullable=False)
name = Field(fieldname='username', nullable=False)
age = Field(nullable=True)
print('=' * 30)
print(Student.__dict__)
s1 = Student()
print(s1.db_table)元编程总结
元类是制造类的工厂,是用来构造类的类。
构造好元类,就可以在类定义时,使用关键字metaclass指定元类,可以使用最原始的metatype(name, bases, dict)的方式构造一个类。
元类的__new__()方法中,可以获取元类信息、当前类、基类、类属性字典。
元编程一般用于框架开发中。
Django、SQLAlchemy使用了元类,让我们使用起来很方便。
注意:
- 开发中除非你明确的知道自己在干什么,否则不要随便使用元编程;
- 99%的情况下用不到元类,可能有些程序员一辈子都不会使用元类。