就像元数据是关于数据的数据一样,元编程是编写程序来操作程序(Just like metadata is data about data, metaprogramming is writing programs that manipulate programs)。一个常见的看法是元编程是用来成成其他程序的程序,但是实际上它的含义更为广泛(It's a common perception that metaprograms are the programs that generate other programs. But the paradigm is even broader)。所有用于读取、分析、转换或修改自身的程序都是元编程的例子。比如:
type并不是我们以为的那样
type 本身就是一个类,并且它是他自己的 type,它是一个元类。元类可以实例化为类并且定义类的行为,就像类可以实例化为对象并且定义对象的行为一样。
type 是 Python 中一个内建的元类,来控制Python中类的行为,我们可以通过继承自 type 来自定义一个元类。元类是Python中进行元编程的途径。
定义一个类时发生了什么
让我们先复习一下我们已知的知识,在Python中构成代码的基本单元有:
Statements
Functions
Classes
在代码中由 Statements 来完成实际的工作,Statements 可以在全局范围(module level)或是本地范围(within a function)。函数是包含一条或多条语句,用来执行特定任务的,可复用的代码单元。函数同样可以定义在全局范围或本地范围,也可以作为类的方法。类提供了“面向对象编程”的能力,类定义了对象如何被实例化以及他们实例化后将会拥有的属性和方法。
类的命名空间存储于字典中,例如
@some_decorator只是一种语法糖,表示函数some_func被另一个函数some_decorator封装起来。我们知道函数和类(除了 type 这个元类)在Python中都是对象,这意味着它们可以:
分配给一个变量(Assigned to a variable)
复制(copied)
作为参数传递给另一个函数(Passed as parameters to other functions)
上面的写法等同于
some_func = some_decorator(some_func)
你可能会想知道 some_decorator 是如何定义的
def some_decorator(f): """
The decorator receives function as a parameter.
"""
def wrapper(*args, **kwargs):
# doing something before calling the function
f(*args, **kwargs)
# doing something after the function is called
return wrapper
def>for name, val in vars(cls).items():
# `callable` return `True` if the argument is callable
# i.e. implements the `__call`
if callable(val):
# instead of val, wrap it with our decorator.
setattr(cls, name, wait_random()(val))
return cls
创建一个子类继承自元类 type(Write a subclass of the metaclass type)
通过“元类钩子”将新的元类插入到类创建过程(Insert the new metaclass into the>
我们创建 type 元类的子类,修改一些魔术方法,像__init__,__new__,__prepare__以及__call__以实现在创建类的过程中修改类的行为。这些方法包含了像父类,类名,属性等信息。Python2中,元类钩子(metaclass hook)是类中一个名为__metaclass__的静态属性(the metaclass hook is a static field in the>metaclass)。Python3中, 你可以在类的基类列表中指定元类作为元类参数(you can specify the metaclass as a metaclass argument in the base-class list of a>
>>>>
... def __init__(cls, name, bases, attrs):
... for name, value in attrs.items():
# do some stuff
def camel_to_snake(name): """
A function that converts camelCase to snake_case.
Referred from: https://stackoverflow.com/questions/1175208/elegant-python-function-to-convert-camelcase-to-snake-case
"""
import re
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
class SnakeCaseMetaclass(type):
def __new__(snakecase_metaclass, future_class_name,
future_class_parents, future_class_attr):
snakecase_attrs = {}
for name, val in future_class_attr.items():
snakecase_attrs[camel_to_snake(name)] = val
return type(future_class_name, future_class_parents,
snakecase_attrs)