如何告诉 PyCharm 类装饰器创建的类变量?

问题描述 投票:0回答:1

比如说,我有一个装饰器可以使日志记录更加简单:

from typing import TypeVar

_T = TypeVar("_T", bound=type)


def with_logger(cls: _T) -> _T:
    from logging import getLogger

    cls.logger = getLogger(cls.__name__)
    return cls


@with_logger
class Spam:
    def __init__(self) -> None:
        print(f"{Spam.logger.name = }")


Spam()

代码运行良好。然而,PyCharm 和

mypy
都抱怨
Spam
没有名为
logger
的属性。引起警告的行是
print(f"{Spam.logger.name = }")

这个问题之后,我将代码转换为以下可怕的代码:

from typing import TypeVar

_T = TypeVar("_T", bound=type)


def with_logger(cls: _T) -> _T:
    from logging import getLogger
    from typing import TYPE_CHECKING

    setattr(cls, 'logger', getLogger(cls.__name__))
    if TYPE_CHECKING:
        from typing import ClassVar, Protocol, cast

        class LoggerMixin(Protocol):
            from logging import Logger

            logger: ClassVar[Logger] = getLogger(cls.__name__)

        return cast(_T, type(cls.__name__, (LoggerMixin, cls), dict()))
    else:
        return cls


@with_logger
class Spam:
    def __init__(self) -> None:
        print(f"{Spam.logger.name = }")


Spam()

还是没用。 PyCharm、

mypy
basedmypy
声称
logger
尚未解决。

还有什么可做的吗?距离提问已经一年多了。

我可以在每个装饰类中显式键入

logger
,但解决方案就是完全丢弃装饰器:

from logging import Logger, getLogger
from typing import ClassVar, TypeVar

_T = TypeVar("_T", bound=type)


def with_logger(cls: _T) -> _T:
    setattr(cls, 'logger', getLogger(cls.__name__))
    return cls


@with_logger
class Spam:
    logger: ClassVar[Logger]

    def __init__(self) -> None:
        print(f"{Spam.logger.name = }")


Spam()

正如@KamilCuk建议的那样,一个可行的方法是继承一个创建

logger
的类:

from logging import Logger, getLogger
from typing import ClassVar


class BaseLogger:
    logger: ClassVar[Logger]
    
    def __new__(cls, *args, **kwargs):
        cls.logger = getLogger(cls.__name__)
        return super().__new__(cls)


class Spam(BaseLogger):
    def __init__(self) -> None:
        print(f"{Spam.logger.name = }")


Spam()

效果很好。它在 PyCharm 中正确突出显示。我只是想知道是否可以通过装饰器来完成。

basedmypy
还是不开心。

python pycharm mypy python-decorators python-typing
1个回答
0
投票

只是超正常的继承。一些事情:

from logging import Logger, getLogger

class BaseLogger:
    @property
    @classmethod
    def logger(cls):
        return getLogger(cls.__name__)


class Spam(BaseLogger):
    def __init__(self) -> None:
        print(f"{Spam.logger.name = }")
© www.soinside.com 2019 - 2024. All rights reserved.