Как напечатать подсказку возвращаемое значение для функции, оформленной, чтобы изменить функцию возврата? - PullRequest
5 голосов
/ 16 мая 2019

Я пишу пакет Python, который использует декораторы для удаления стандартного кода, одновременно анализируя функцию, чтобы получить имя функции по умолчанию. Примерно так:

def make_real_instance(func: Optional[Callable] = None,
                       *, func_name: Optional[str] = None):
    def make_wrapper(in_func):
        @functools.wraps(in_func)
        def wrapper(*args, **kwargs):
            nonlocal func_name
            # Use func_name if provided
            func_name = func_name or in_func.__name__
            # Construct params for new object from function and its inputs
            stuff = in_func(*args, **kwargs)
            # Process stuff commonly
            new_object = ObjectConstructor(processed_stuff, func_name)
            return new_object
        return wrapper

    if func:
        return make_wrapper(func)
    return make_wrapper

Теперь у меня есть такой класс:

class ObjectConstructor:
    def __init__(self, ...):
        #do stuff

    @make_real_instance
    def add_foo(self, foo_length: float):
        stuff = ... # process the input for this method
        return stuff

Декоратор @make_real_instance вызывает вызов метода add_foo экземпляра ObjectConstructor для возврата нового экземпляра. Однако фактический тип возвращаемого значения для неокрашенного метода - кортеж.

Что я хотел бы сделать, так это аннотировать метод, чтобы напечатать подсказку возврата как экземпляр ObjectConstructor. Т.е. строка:

        def add_foo(self, foo_length: float):

станет (импортировав annotations из __future__):

        def add_foo(self, foo_length: float): -> ObjectConstructor

Тем не менее, моя IDE (PyCharm, хотя я не обязательно считаю это материалом в данном случае) жалуется (справедливо, я полагаю), что выходные данные этого метода не совпадают с подсказкой возвращаемого типа.

Наконец, мой вопрос: есть ли способ правильно напечатать подсказку типа возврата вызова функции, который вы изменяете в результате использования декоратора? Или мой единственный выход - заменить декоратор на функцию, которую я вызываю в каждой декорированной функции, и каждый раз явно передаю свой параметр func_name? Под этим я подразумеваю что-то вроде:

def make_obj_from_stuff(stuff, func_name) -> ObjectConstructor:
    # process stuff commonly
    new_object = new_object = ObjectConstructor(processed_stuff, func_name)
    return new_object

class ObjectConstructor:
    def __init__(self, ...):
        #do stuff

    def add_foo(self, foo_length: float) -> ObjectConstructor:
        stuff = ... # process the input
        new_obj = make_obj_from_stuff(stuff, "add_foo")
        return new_obj

Если я хочу сохранить созданный мной интерфейс декоратора, нужно ли мне просто признать, что я не смогу правильно ввести подсказку, не пожаловавшись в мою среду IDE?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...