在Python中解决装饰器的TypeVar错误

bgtovc5b  于 2023-08-08  发布在  Python
关注(0)|答案(1)|浏览(105)

我一直在给我的装饰器添加类型,让我自己高兴。我一直在关注this,也一直在关注pep 484。我已经取得了很大的进展,但我得到的错误信息

decorators.py:12: error: A function returning TypeVar should receive at least one argument containing the same TypeVar  [type-var]
decorators.py:12: note: Consider using the upper bound "Callable[..., Any]" instead

字符串
但是,当你看代码的时候。我已经使用了bound=Callable[..., Any],我不知道它希望我如何进行。
脚本:decorators.py

"""Decorator Functions."""

from typing import Any, Callable, List, TypeVar, Union, cast
from pandas import DataFrame, concat

F = TypeVar('F', bound=Callable[..., Any])

# Decorator to process DataFrame with ignore columns
def process_without_columns(
    ignore_cols: List[str], final_cols_order: Union[List[str], None] = None
) -> F:
    """
    Decorate to process a DataFrame, removing specified ignore columns, and then joining them back.

    Parameters
    ----------
    ignore_cols: List[str]
        List of column names to ignore during processing.
    final_cols_order: Union[List[str], None]
        List specifying the desired order of columns in the final DataFrame.
        If None, the original DataFrame's column order will be used. Default is None.

    Returns
    -------
        decorator_process: Decorator function that processes the DataFrame.
    """

    def decorator_process(func: F) -> F:
        def inner(self, data_df: DataFrame, *args: Any, **kwargs: Any) -> DataFrame:
            """
            Inner function that performs the actual processing of the DataFrame.

            Parameters
            ----------
                data_df: DataFrame
                    DataFrame to be processed.
                *args
                    args passed into inner function
                **kwargs
                    Kwargs passed into inner function

            Returns
            -------
                DataFrame: Processed DataFrame with the original columns
            """
            ignore_df = data_df[
                ignore_cols
            ]  # Extract the ignore columns as a separate DataFrame
            data_df = data_df.drop(
                columns=ignore_cols
            )  # Remove the ignore columns from the original DataFrame

            # Process the DataFrame (smaller DataFrame without ignore columns)
            processsed_df = func(self, data_df, *args, **kwargs)

            # Join back the processed DataFrame with the ignore columns DataFrame
            processsed_df = concat([processsed_df, ignore_df], axis=1)

            # Reorder DataFrame columns if final_cols_order is specified
            if final_cols_order is not None:
                processsed_df = processsed_df[final_cols_order]

            return processsed_df

        return cast(F, inner)

    return cast(F, decorator_process)

kgsdhlau

kgsdhlau1#

在Python中输入装饰器仍然有点问题。
下面是一个似乎可以进行类型检查的版本:

from typing import Any, Callable, List, TypeVar, Union, cast
from pandas import DataFrame, concat

F = TypeVar('F', bound=Callable[..., Any])

def process_without_columns(
    ignore_cols: List[str], final_cols_order: Union[List[str], None] = None
) -> Callable[[F], F]:

    def decorator_process(func: F) -> F:
        def inner(self: Any, data_df: DataFrame, *args: Any, **kwargs: Any) -> DataFrame:
            ignore_df = data_df[
                ignore_cols
            ]  # Extract the ignore columns as a separate DataFrame
            data_df = data_df.drop(
                columns=ignore_cols
            )  # Remove the ignore columns from the original DataFrame

            # Process the DataFrame (smaller DataFrame without ignore columns)
            processsed_df = func(self, data_df, *args, **kwargs)

            # Join back the processed DataFrame with the ignore columns DataFrame
            processsed_df = concat([processsed_df, ignore_df], axis=1)

            # Reorder DataFrame columns if final_cols_order is specified
            if final_cols_order is not None:
                processsed_df = processsed_df[final_cols_order]

            return processsed_df

        return cast(F, inner)

    return decorator_process

字符串
https://mypy-play.net/?mypy=latest&python=3.11&gist=1496165d26c4f924f652613473b950f3&flags=strict
主要问题是F是外部process_without_columns函数的错误返回类型。它实际上返回一个函数,该函数接受F并返回和F,即另一层筑巢。
不过,在inner函数上需要cast有点不幸。
我还尝试了另一个使用https://peps.python.org/pep-0612/特性的版本。

from typing import Any, Callable, Concatenate, List, ParamSpec, Union, cast
from pandas import DataFrame, concat

P = ParamSpec('P')
F = Callable[Concatenate[Any, DataFrame, P], DataFrame]

def process_without_columns(
    ignore_cols: List[str], final_cols_order: Union[List[str], None] = None
) -> Callable[[F[P]], F[P]]:
    def decorator_process(func: F[P]) -> F[P]:
        def inner(self: Any, data_df: DataFrame, /, *args: Any, **kwargs: Any) -> DataFrame:
            ignore_df = data_df[
                ignore_cols
            ]  # Extract the ignore columns as a separate DataFrame
            data_df = data_df.drop(
                columns=ignore_cols
            )  # Remove the ignore columns from the original DataFrame

            # Process the DataFrame (smaller DataFrame without ignore columns)
            processsed_df = func(self, data_df, *args, **kwargs)

            # Join back the processed DataFrame with the ignore columns DataFrame
            processsed_df = concat([processsed_df, ignore_df], axis=1)

            # Reorder DataFrame columns if final_cols_order is specified
            if final_cols_order is not None:
                processsed_df = processsed_df[final_cols_order]

            return processsed_df

        return inner

    return decorator_process


https://mypy-play.net/?mypy=latest&python=3.11&gist=6c56fd4381d1fc9bb463965c7c32d7de&flags=strict
我们使用ParamSpec来捕获*args**kwargs的类型。
然后我们需要Concatenate,因为在*args前面有位置参数self, data_df
我们还必须在inner def中使用/来使它们成为位置参数-如果修饰的func不这样做,这将是一个问题。

相关问题