面向对象柯里化
项目描述
概述
Factory是一个面向对象的局部函数应用方法,也称为柯里化。Factory模块是这个模式的一个更强大的实现。一些改进包括
更安全,因为无效参数会立即检测到,而不是在调用时
智能支持类、实例方法以及所有其他可调用对象
绑定参数可以作为属性检查和修改
几个方便的参数绑定方法
没有嵌套lambda的“俄罗斯套娃”
使用Factory可以
简化回调函数的编写
减少并发应用程序中的错误
提供易于懒加载的评估
安装
Factory模块可以从Cheeseshop获取。源代码可在Google Code项目页面获取。
Factory模块可以像其他纯Python模块一样安装。支持Setuptools但不强制。您还可以将Factory.py文件直接包含在项目的源代码树中,但必须保留版权声明、版本和归属信息。
要在模块中运行测试,请在Factory/目录中执行以下命令
python doctest_Factory.py
nosetests test_Factory.py
关于柯里化
柯里化通过绑定原始函数的一些参数来从现有函数创建一个新函数
>>> def adder(x, y): ... return x + y >>> add_lambda = lambda y: adder(1, y) >>> add_lambda(10) 11
截至Python 2.5,此模式内置了局部函数。
>>> add_partial = functools.partial(adder, 1) >>> add_partial(y=10) 11
工厂
工厂是柯里化模式更好的实现
>>> from Factory import * >>> add_factory = Factory(adder, x=1) >>> add_factory #doctest: +ELLIPSIS <Factory(<function adder at ...>) at ...> >>> add_factory(y=10) 11
与lambda和partial不同,工厂可以被检查和修改
>>> add_factory.x 1 >>> add_factory.x = 2 >>> add_factory(y=10) 12
可以检查将传递给函数的参数,这在调试时有时很有帮助
>>> import pprint >>> args, kwargs = add_factory.generateArgs(y=10) >>> pprint.pprint(kwargs) {'x': 2, 'y': 10} >>> args []
用法
在以下示例中,我们混合了FactoryMixin
以在基类上提供factory
类方法。
>>> class Foo(FactoryMixin): ... def __init__(self, foo): ... self.foo = foo ... >>> foo_factory = Foo.factory() >>> foo_factory.foo = 66
这相当于
>>> Factory(Foo) #doctest:+ELLIPSIS <Factory(<class 'Foo'>) at ...>
使用mixin不是必需的,但它看起来不错且拼写更简单。
工厂有bind方法,可以同时设置多个属性并返回工厂。这在不需要将工厂分配给局部变量的情况下绑定参数非常有用。
>>> def doStuff(foo_factory): ... return foo_factory.foo >>> doStuff(foo_factory.bind(foo=11)) 11 >>> foo_factory2 = foo_factory.bind(foo=42) >>> foo_factory2 is foo_factory True >>> foo_factory.foo 42
您也可以在构建工厂时绑定属性
>>> foo_factory = Factory(Foo, foo=11) >>> foo_factory.foo 11
工厂确保属性与参数匹配;这使得查找错误更容易(而不是在以后抛出意外的关键字参数)
>>> foo_factory.bar = 42 #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'No such argument bar'
调用工厂时,参数会覆盖属性
>>> foo = foo_factory(foo=1111) >>> foo.foo 1111
每次调用都返回一个新的实例
>>> foo2 = foo_factory() >>> foo2 is foo False
有效属性的集合是继承链中所有__init__参数的并集
>>> class Bar(Foo): ... def __init__(self, bar, **kwargs): ... super(Bar, self).__init__(**kwargs) ... self.bar = bar ... >>> bar_factory = Bar.factory() >>> bar_factory.foo = 11 >>> bar_factory.bar = 42 >>> bar_factory.quux = 666 #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'No such argument quux' >>> bar = bar_factory() >>> bar.foo 11 >>> bar.bar 42
请确保传递给Factory的可调用对象(一个类,而不是一个实例)
>>> Factory(bar) #doctest:+ELLIPSIS, +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: must provide known callable type, not <Factory.Bar object at ...>
当然,可调用对象是可行的
>>> class CallMe(object): ... def __init__(self, x): ... self.x = x ... def __call__(self, y): ... return self.x + y >>> Factory(CallMe(1))(1) 2
可以将现有工厂作为新工厂的调用者传递。
>>> bar_factory = Bar.factory(bar=2) >>> bar_factory2 = Factory(bar_factory, foo = 1) >>> bar_factory is not bar_factory2 True >>> bar_factory2.bar 2 >>> bar_factory2.bar = 4 >>> bar_factory.bar 2
与使用lambda不同,这不会创建嵌套的“套娃”
>>> bar_factory2.getCallable() <class 'Bar'>
装饰器
returnFactory是一个装饰器,它用其生成的Factory等价物替换函数
>>> @returnFactory ... def mult(x, y): ... return x * y >>> fac = mult(x=10, y=5) >>> isinstance(fac, Factory) True >>> fac() 50
factoryAttribute为装饰函数添加一个factory属性
>>> @factoryAttribute ... def adder(x, y): ... return x + y >>> fac = adder.factory(x=10) >>> isinstance(fac, Factory) True >>> fac2 = adder.factory() >>> fac is not fac2 True >>> fac(y=42) 52
factoryDescriptor生成具有factory属性的实例方法。在类内部,使用此描述符而不是factoryAttribute。此类可以用作装饰器
>>> class Quux(object): ... @factoryDescriptor ... def doStuff(self, whatnot): ... pass >>> quux = Quux() >>> fac = quux.doStuff.factory(whatnot=42) >>> isinstance(fac, Factory) True >>> fac.whatnot 42
对象模板
对象模板是创建对象的模板。它们与工厂配合得很好。
Bunch只是一堆属性。Bunch的关键字参数被转换为属性
>>> b = Bunch(pants=42, shirt=15) >>> b.pants 42 >>> b.shirt 15
调用Bunch返回一个新的副本
>>> c = b() >>> c.__dict__ == b.__dict__ True >>> c is b False
当调用ObjectTemplate实例时,它将产生bunchClass的新实例。模板上的属性作为kwargs传递给bunch。但是,如果属性是可调用的,它将被调用,并使用返回值代替
>>> counter = itertools.count(1).next # an incrementing counter >>> def color(): ... return "blue" >>> template = ObjectTemplate(size=42, ... color=color, ... count=counter, ... bunchClass=Bunch) >>> bunch = template() >>> isinstance(bunch, Bunch) True >>> bunch.size 42 >>> bunch.color 'blue' >>> bunch.count 1
每次调用模板都产生一个新的bunch。任何函数都将再次被调用
>>> bunch2 = template() >>> bunch2.count 2
如果您想将可调用对象传递给bunch,请将其包装在lambda中
>>> template = ObjectTemplate() >>> template.return_val = color >>> template.a_function = lambda: color >>> bunch = template() >>> bunch.return_val 'blue' >>> bunch.a_function #doctest:+ELLIPSIS <function color at ...>
错误
错误、功能请求和赞誉可以直接发送给作者。
项目详情
Factory-1.2.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | c0af96e123ac9164ca7d1b9905de749f94e819c8e85341c8fb9f1dd2e349c8cc |
|
MD5 | a1e0c5d326cea1c4e7a588f28ce9c5de |
|
BLAKE2b-256 | 187b342e9c93d32b21deaaded9fb929413b71c37187079bbdce4b6bae4568f47 |