Python学习笔记38:类元编程
《Fluent Python》中多次提到,在Python中,类和函数都是一类对象,这指的是其开放程度对于Python语言的定制者和普通开发者是相同的,拥有同样的权限,我们可以像Python语言的底层开发人员那样,对类和函数进行定制和改造,以实现某种“高级需求”。
虽然对于普通的开发者来说似乎用不到,但作为语言学习的一部分,了解这部分知识至少对帮助你更深入的理解这门语言是有益的。而书中也提到,Python之所以能流行,似乎这种对于初学者好用的同时为资深开发者提供高级工具的特性带来很多益处。
在接下来我会按照《Fluent Python》中的内容进行说明类元编程,我认为书中这部分的切入点是非常恰当的,同时我也找不出更好的知识组织脉络,所以完全按照原书。此外我同样找不到比原书更恰当的示例,所以示例部分也同样会大部分都按照原书进行编写。
这同时也是《Fluent Python》的最后一部分内容,很高兴能和大家分享所学所思。
类工厂函数
所谓的类工厂函数,和之前的属性描述符工厂函数没有本质的区别,最大的区别就是其生产的不是普通对象,也不是函数,而是类。
我们要时刻清楚,在Python中,类不过也是一种特殊类型的对象罢了,自然可以“动态”创建。
namedtuple
在Python学习笔记19:列表 III,提到过具名元组namedtuple
,其实质上就是一个类工厂函数,通过指定类名和属性,会返回一个类,利用返回的类我们可以创建相应的实例:
from collections import namedtuple
Student = namedtuple('Student', 'age name sex')
s1 = Student(15,'Han Meimei','female')
s2 = Student(20, 'Li Lei', 'male')
print(s1)
print(s2.name)
# Student(age=15, name='Han Meimei', sex='female')
# Li Lei
现在应该会理解namedtuple
为什么会指定一个参数Student
了,既然要创建一个类,自然要指定相应的类名。
虽然这里
Student = namedtuple('Student', 'age name sex')
相当于给新的类重新指定了一个全局变量Student
,当然这个全局变量可以和新的类不同名,但那样显然没有必要。
我们现在按照标准库的namedtuple
的功能,创建一个表现完全相同的类工厂函数,来说明如何通过工厂函数创建一个新的类。
def named_tuple_factory(clsName, fields):
try:
fields = fields.replace(',', ' ').split(' ')
except AttributeError:
pass
clsBody = {
}
def __init__(self, *args, **kwArgs):
if args:
for key, value in zip(fields, args):
setattr(self, key, value)
if kwArgs:
for key, value in kwArgs.items():
if key in fields:
setattr(self, key, value)
def __str__(self):
fieldsStr = ",".join("{}={!s}".format(key, value)
for key, value in self.__dict__.items())
return "{}({})".format(clsName, fieldsStr)
clsBody['__init__'] = __init__
clsBody['__str__'] = __str__
return type(clsName, (object,), clsBody)
Student = named_tuple_factory('Student'