在Python 3中使用partial在元类中创建实例方法
使用元类,我尝试通过简化现有实例方法来创建实例方法。问题是部分不适用于实例方法。这是我试图实现的一个简单示例:
from functools import partial
class Aclass(object):
def __init__(self, value):
self._value = value
def complex(self, a, b):
return a + b + self._value
class Atype(type):
def __new__(cls, name, bases, attrs):
return super(Atype, cls).__new__(cls, name, (Aclass, ) + bases, attrs)
def __init__(cls, name, bases, attrs):
setattr(cls, 'simple', partial(cls.complex, b=1))
class B(metaclass=Atype):
pass
b = B(10)
print(b.complex(1, 2))
print(b.simple(1))
输出是:
13
Traceback (most recent call last):
File "metatest.py", line 22, in <module>
print(b.simple(1))
TypeError: complex() takes exactly 3 non-keyword positional arguments (1 given)
我已经解决了使用 lambda 将:更改
setattr(cls, 'simple', partial(cls.complex, b=1))
为:
setattr(cls, 'simple', lambda self, x: cls.complex(self, x, b=1))
但它很丑陋并且在可选参数方面存在问题。
我可以在实例 __init__ 中创建这些方法,但我想这更有意义,并且使用元类在类 __init__ 上执行此操作更有效。
有什么想法如何正确地做到这一点吗?
Using metaclasses, I am trying to create an instance method by simplifying an existing instance method. The problem is that partial does not work with instance method. This is a simple example of what I try to achieve:
from functools import partial
class Aclass(object):
def __init__(self, value):
self._value = value
def complex(self, a, b):
return a + b + self._value
class Atype(type):
def __new__(cls, name, bases, attrs):
return super(Atype, cls).__new__(cls, name, (Aclass, ) + bases, attrs)
def __init__(cls, name, bases, attrs):
setattr(cls, 'simple', partial(cls.complex, b=1))
class B(metaclass=Atype):
pass
b = B(10)
print(b.complex(1, 2))
print(b.simple(1))
and the output is:
13
Traceback (most recent call last):
File "metatest.py", line 22, in <module>
print(b.simple(1))
TypeError: complex() takes exactly 3 non-keyword positional arguments (1 given)
I have solved using lambda changing:
setattr(cls, 'simple', partial(cls.complex, b=1))
to:
setattr(cls, 'simple', lambda self, x: cls.complex(self, x, b=1))
but it is ugly and has problems with optional parameters.
I could create these method at the instance __init__
but I guess it makes more sense, and is more efficient to do it on class __init__
using metaclasses.
Any ideas how to do it properly?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好吧,我对 Python 3 方法处理还有点不熟悉 -
我能想到的最简单的事情是重写
partial
,以便保留原始调用中的第一个参数,然后插入“部分”参数。它适用于您的示例,但需要使用更复杂的模式进行测试。
Well, I am a bit unfamiliar with Python 3 method handling yet -
the simplest thing I could think of is rewriting
partial
so that it preserves the first argument from the original call, then inserts the "partial" parameters.It worked with your example, but it needs testing with more complex patterns.
我不使用
partial
,而是像这样定义类Atype
:__init__()
方法也可以写得更紧凑:Instead of using
partial
, I'd just define classAtype
like this:The
__init__()
method can also be written more compactly:问题是 functools.partial() 返回的对象是可调用对象,而不是函数。显然,Python 并不关心非函数试图在这种情况下表现得像函数一样。一种解决方案是创建一个函数作为
partial
对象的包装器。jsbueno 的解决方案(返回真实函数的
partial
的重新实现)很好。我真的不知道为什么 functools.partial() 不能那样工作;无法在这种情况下使用它是一个令人惊讶的陷阱。The problem is that the object returned by
functools.partial()
is a callable object, not a function. So apparently Python doesn't care for a non-function trying to act like one in this context. One solution is to create a function as a wrapper for thepartial
object.jsbueno's solution (a reimplementation of
partial
that returns a real function) is good though. I really don't know whyfunctools.partial()
doesn't work that way; not being able to use it in this context is a surprising pitfall.