要包装模块的所有函数调用并通过包装类的
__getattr__
方法访问它,我尝试使用 typing
库,但我不知道如何正确执行此操作。
import interface
"""
>>> print(interface.__all__)
['execute_foo_operation', ...]
"""
class InterfaceWrapper(object):
def __init__(self, job_queue):
self.job_queue = job_queue
self.callbacks = []
def __getattr__(self, name):
func = getattr(interface, name)
return functools.partial(self._wrapper, func)
def _wrapper(self, func, *args, **kwargs):
job = func(*args, **kwargs)
self.job_queue.push(job)
for callback in self.callbacks:
callback(job)
return job
def register_callback(self, callback):
self.callbacks.append(callback)
class Operator(object):
def __init__(self, job_queue):
self.interface = InterfaceWrapper(job_queue)
def after_queuing(self):
# do something
def execute_foo_operation(self):
self.interface.register_callback(self.after_queuing)
self.interface.execute_foo_operation() # unresolved attribute
任何人都可以指导我的代码正常工作吗?
通常,
__getattr__
可以返回任何内容。所以你可以使用 Typing.Any
From Typing import Any
def __getattr__(self, name: str) -> Any:
...
但看起来你的
__getattr__
的实现是返回一个可调用的
From Typing import Callable
def __getattr__(self, name: str) -> Callable:
...
如果我理解正确的话,您的请求本质上是要求 statical 类型检查器推断 __getattr__
返回的
dynamical属性的引用,这对于大多数类型检查器来说可能相当具有挑战性。事实上,对于 PyCharm (>=2020.3.5 (203.7717.81)),如果在
class中定义了
__getattr__
,则禁用对未解析属性的检查。
存在一种解决方法,但要求您不使用
__getattr__
访问属性,而是事先通过 typing.Literal
手动静态定义所有属性名称,并使用这些文字在下面的自定义定义 name
方法中注释 get_attr
:
import functools
from typing import Literal
supported = Literal[Literal['a'], Literal['b']]
class InterfaceWrapper(object):
def __init__(self, job_queue):
self.job_queue = job_queue
self.callbacks = []
def get_attr(self, name: supported):
func = getattr(interface, name)
return functools.partial(self._wrapper, func)
def _wrapper(self, func, *args, **kwargs):
job = func(*args, **kwargs)
self.job_queue.push(job)
for callback in self.callbacks:
callback(job)
return job
def register_callback(self, callback):
self.callbacks.append(callback)
class Operator(object):
interface: InterfaceWrapper
def __init__(self, job_queue):
self.interface: InterfaceWrapper = InterfaceWrapper(job_queue)
def after_queuing(self):
# do something
...
def execute_foo_operation(self):
# ... do something
self.interface.get_attr('a')()
这里,如果您调用 self.interface.get_attr('c'),它将报告预期为 'a' 和 'b',但得到的是 'c'。
如果您只想通过
__getattr__
(interface.attr_name) 访问方法或属性,那么您至少需要在 InterfaceWrapper 中的某个位置静态定义接口的属性,例如,定义指向接口对象中的相应字段。