从基类包装派生的类方法
想象一下,我有一个基础和一个类似的类别:
class A:
def foo(self):
pass
class B(A):
def foo(self):
pass
我希望通过b
实例进行调用foo
调用。不允许修改B的任何部分(我不拥有B)。
到目前为止,我现在拥有的
class A:
def __init__(self):
fnames = ["foo"]
for fname in fnames:
def capture(f):
def wrapper(*args, **kwargs):
print("wrapped")
return f(*args, **kwargs)
return wrapper
meth = capture(getattr(self, fname))
bound = meth.__get__(self)
setattr(self, fname, bound)
class B(A):
def foo(self):
print("b")
o = B()
o.foo()
print(o.foo)
是预期的,但是我担心这是不效率的记忆。
o.foo
是<界方法代码>。看来我必须为我创建的每个实例支付2个结局的费用。
有更好的方法吗?也许是基于元的方法?
Imagine I have a base and a derived class like so:
class A:
def foo(self):
pass
class B(A):
def foo(self):
pass
I wish to wrap calls foo
calls made by instances of B
. Modifying any part of B is not allowed (I don’t own B).
What I have as of now:
class A:
def __init__(self):
fnames = ["foo"]
for fname in fnames:
def capture(f):
def wrapper(*args, **kwargs):
print("wrapped")
return f(*args, **kwargs)
return wrapper
meth = capture(getattr(self, fname))
bound = meth.__get__(self)
setattr(self, fname, bound)
class B(A):
def foo(self):
print("b")
o = B()
o.foo()
print(o.foo)
This works as expected, however I am concerned about this being inefficient memory-wise.
o.foo
is a <bound method A.__init__.<locals>.capture.<locals>.wrapper of <__main__.B object at 0x10523ffd0>>
. It would seem that I would have to pay the cost of 2 closures for each instance I create.
Is there a better way to do this? Perhaps a metaclass based approach?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
除非您打算同时拥有数千个实例,否则这样做的资源使用情况不应关注您 - 与运行Python应用程序将使用的其他资源相比,它相当小。
只是为了进行比较:Asyncio Coroutines和Task是一种可以在一个过程中创建数千个的对象,并且它只是“确定”,它将具有类似的开销。
但是,由于您可以控制 base 类的
b
有几种方法可以执行此操作,而无需求助于“ monkey patching” - 它将在其之后修改B被创建了。当一个人必须修改不控制代码的类时,这通常是唯一的选择。将该方法自动包装,当它从
b
实例中检索时,以懒惰的方式可以节省这一点 - 并且肯定可以比在基类__ __ INT __ INT __ :
如果您事先知道您必须包装的方法,并且确定它们是在您控制的类的子类中实现的,则可以通过制作专业
__ getAttribute __
方法来制作。仅在使用即将使用时包装方法。至于包装
foo
创建b时,可以提供更少的资源 - 虽然可以在元素级别上完成,从python 3.6 on,__ INIT_SUBCLASS __
特殊方法可以处理它,而无需自定义元素。但是,如果代码可能在A
c(b)中进一步子类B,则此方法可能会很棘手:
它将再次覆盖foo
:如果包装器可以多次调用,如果方法使用super()
在基类中使用foo
的调用。避免包装器中的代码不止一次运行将需要一些复杂的状态处理(但可以毫无意外地完成)。Unless you are planning to have several thousands instances of these live at the same time, the resource usage of doing so should not concern you - it is rather small compared with other resources a running Python app will use.
Just for comparison: asyncio coroutines and tasks are the kind of object which one can create thousands of in a process, and it is just "ok", will have a similar overhead.
But since you have control of the base class for
B
there are several ways to do it, without resorting to "monkey patching" - which would be modifying B in place after it was created. That is often the only alternative when one has to modify a class for which they don't control the code.Wrapping the method either automatically, when it is retrieved from a
B
instance, in a lazy way, can spare even this - and sure can be more elegant than wrapping at the base class__init__
:If you know beforehand the methods you have to wrap, and is sure they are implemented in subclasses of classes which you control, this can be made by crafting a specialized
__getattribute__
method: this way, the method is wrapped only when it is about to get used.As for wrapping
foo
when B is created, that could give use even less resources - and while it could be done in a metaclass, from Python 3.6 on, the__init_subclass__
special method can handle it, with no need for a custom metaclass.However, this approach can be tricky if the code might further subclass B in a
class C(B):
which will again overridefoo
: the wrapper could be called multiple times if the methods usesuper()
calls tofoo
in the base classes. Avoiding the code in the wrapper to run more than once would require some complicated state handling (but it can be done with no surprises).以下内容@jsbueno wands bess
使用
type.methodtype(attr,self)
要好于使用
,因为部分没有描述符,因此返回的属性不绑定到类实例。只需要修复返回包装器
Following @jsbueno answer
Using
types.MethodType(attr, self)
is better than using
since partial doesn't have a descriptor so the returned attribute is not bound to the class instance. just need to fix the return wrapper to