在python
中通用对象的工厂函数是很容易实现的。这得益于python的动态语言特性,以及python
中,类亦是对象的设计。
- 下面看一个简单的通用对象的工厂函数:
def factory(aCalss,*args):
return aClass(*args)
就这样简单的两句代码,就实现了一个对象工厂函数。如果使用lambda
,甚至可以使用一句代码来完成:factory = (lambda aClass,*args:aClass(*args))
为什么说上述的factory()
函数说一个通用对象的工厂函数呢?
- 假设有如下两个类
Person
&Cat
,怎么通过factory()
函数来创建实例?
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
class Cat:
def __init__(self, name, color):
self.name = name
self.color = color
创建对象代码如下:
p = factory(Person,'Kick Chen',59)
c = factory(Cat,'tomCat','black')
print(p, c)
# <Person:name=Kick Chen,age=59> <Cat:name=tomCat,color=black>
- 通过这个示例可以看出这个通用对象的工厂函数说可行的。
- 而且,看一下
factory()
函数的实现就明白了。实际上,和普通的对象实例化的操作没有任何的区别,只是在外面包装了一层函数而已。
对于此工厂函数,还有没有可优化的点:当然有。就是加上对关键字参数对支持。
def factory(aClass,*args,**kwargs):
return aClass(*args,**kwargs)
假设有如下类:
class Apple:
def __init__(self, weight,color = 'red',sweet = True):
self.weight = weight
self.color = color
self.sweet = sweet
调用方式如下:
a = factory(Apple,1.5,sweet = False,color = 'green')
p = factory(Person,'rose',24)
print(a,p)
# <Apple:weight=1.5,color=green,sweet=False> <Person:name=rose,age=24>
这样,一个通用的对象工厂函数就实现了。
当然,有以下注意点:
- 该工厂函数,不仅仅可以用来返回对象,也可以传入函数,或者普通对象,用来做其他的事情
关于上面的
*args
&**kwargs
,作为函数形参,及实参时表达的含义是不同的*args
作为形参时,是作为封包来使用的。比如,传入1,2,3,4
这4个参数,那么*
的作用是封包/压缩。将1,2,3,4
转化为(1,2,3,4)
这样的一个元祖。实际上函数得到的也是这样一个元组对象,而不是4个对象。*args
作为实参时,*
的作用时解包/解压。比如,传的是('tom',23)
,实际上,相当于传了两个参数'tom'
,23
进来。- *
**kwargs
和*args
作用类似,只是这里的封包与解包,不再是元祖,而是字典。* **kwargs
作为形参时,是作为字典封包来使用的。比如:传入age=23,name='tom'
,那么,实际上得到是{'age':23,'name':'tom'}
**kwargs
作为实参时,是作为解包来使用的。比如:传入{'age':23,'name':'tom'}
,相当于传递了两个关键字参数age=23,name='tom'
。
p s: 更多关于
*args
&**kwargs
的介绍,可以参阅python参数魔法 & python 函数参数魔法
参考资料:《Learning Python》