简体   繁体   English

将可调用的 object 作为方法注入 class

[英]Injecting a callable object into a class as a method

It is possible to inject a function into a class like this:可以像这样将 function 注入 class 中:

class MainClass:
    ...


def simple_injected_func(self: MainClass, arg: str) -> None:
    print(f"simple_injected_func({arg})")


MainClass.simple_injected_func = simple_injected_func
main_object = MainClass()

main_object.simple_injected_func("arg")
# outputs: simple_injected_func(arg)

Furthermore it is possible to make an object callable like this此外,可以像这样调用 object

class SimpleCallableClass:
    def __call__(self, arg: str) -> None:
        print(f"SimpleCallableClass()({arg})")


simple_callable_object = SimpleCallableClass()
simple_callable_object("arg")
# outputs: SimpleCallableClass()(arg)

I now want to combine these two things and inject a callable class/object as a function into another class while keeping access to object variables and methods of both the CallableClass as well as the MainClass .我现在想将这两件事结合起来,将一个可调用的类/对象作为 function 注入另一个 class,同时保持对 object 变量和CallableClassMainClass方法的访问。 (Internally I want to use this to effectively implement method inheritance and inject those methods into a class from another file) (在内部我想用它来有效地实现方法 inheritance 并将这些方法从另一个文件注入到 class 中)

from inspect import signature

class CallableClass:
    def __call__(self_, self: MainClass, arg: str) -> None:
        print(f"CallableClass()({arg})")


callable_object = CallableClass()

MainClass.callable_object = callable_object

main_object = MainClass()

print(signature(simple_injected_func))
# outputs: (self: __main__.MainClass, arg: str) -> None
print(signature(callable_object))
# outputs: (self: __main__.MainClass, arg: str) -> None

print(signature(main_object.simple_injected_func))
# outputs: (arg: str) -> None
print(signature(main_object.callable_object))
# outputs: (self: __main__.MainClass, arg: str) -> None

main_object.simple_injected_func("my arg")
# outputs: simple_injected_func(my arg)
main_object.callable_object("my arg")
# Traceback (most recent call last):
#   main_object.callable_object("my arg")
# TypeError: CallableClass.__call__() missing 1 required positional argument: 'arg'

Why does the second self not get correctly stripped in case of the callable object?在可调用的 object 的情况下,为什么第二个self没有被正确剥离? Is there some way of achieving this?有没有办法做到这一点?

When methods of an instance are accesses, Python performs "binding", ie it creates a bound method.当实例的方法被访问时,Python 执行“绑定”,即创建绑定方法。 See here:看这里:

>>> class Class:
...     def method(self, x):
...         return x
... 
>>> 
>>> instance = Class()
>>> Class.method
<function Class.method at 0x7fa688037158>
>>> instance.method
<bound method Class.method of <__main__.Class object at 0x7fa688036278>>

The binding is done because methods are implemented as descriptors.绑定已完成,因为方法是作为描述符实现的。

You can also implement your callable as a descriptor if you want to have that behaviour.如果您想拥有这种行为,您还可以将您的可调用对象实现为描述符

In short, you would have to implement a class with at least a __get__ method.简而言之,您必须使用至少一个__get__方法来实现 class。 That __get__ method will be called when either Class.method or instance.method is evaluated.当评估Class.methodinstance.method时,将调用该__get__方法。 It should return the callable (which should be a different one depending on whether there is an instance or not).它应该返回可调用对象(根据是否存在实例,它应该是不同的)。

BTW, to actually bind a method to an instance, it is simplest to use functors.partial :顺便说一句,要将方法实际绑定到实例,使用functors.partial是最简单的:

bound_method = functors.partial(method, instance)

All summed up:全部总结:

class Callable:
    def __call__(self, instance, arg):
        print(f"Callable()(arg)")


class Descriptor:
    def __init__(self, callable):
        self._callable = callable

    def __get__(self, instance, owner):
        if instance is None:
            return self._callable
        else:
            return functools.partial(self._callable, instance)


class Class:
    pass


Class.method = Descriptor(Callable())

And then:接着:

>>> signature(Class.method)
<Signature (instance, arg)>
>>> signature(Class().method)
<Signature (arg)>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM