如何从类变量引用静态方法

Abh*_*kar 6 python static-methods decorator class-variables python-typing

鉴于班级

from __future__ import annotations
from typing import ClassVar, Dict, Final
import abc

class Cipher(abc.ABC):
    @abc.abstractmethod
    def encrypt(self, plaintext: str) -> str:
        pass

    @abc.abstractmethod
    def decrypt(self, ciphertext: str) -> str:
        pass

class VigenereCipher(Cipher):
    @staticmethod
    def rotate(n: int) -> str:
        return string.ascii_uppercase[n:] + string.ascii_uppercase[:n]

    _TABLE: Final[ClassVar[Dict[str, str]]] = dict({(chr(i + ord("A")), rotate(i)) for i in range(26)})
Run Code Online (Sandbox Code Playgroud)

编译失败(使用 3.8.0

../cipher.py:19: in <module>
    class VigenereCipher(Cipher):
../cipher.py:24: in VigenereCipher
    _TABLE: Final[ClassVar[Dict[str, str]]] = dict({(chr(i + ord("A")), rotate(i)) for i in range(26)})
../cipher.py:24: in <setcomp>
    _TABLE: Final[ClassVar[Dict[str, str]]] = dict({(chr(i + ord("A")), rotate(i)) for i in range(26)})
E   NameError: name 'rotate' is not defined
Run Code Online (Sandbox Code Playgroud)

但是,根据this post,rotate应该可以解决。请注意,使用类名进行限定VigenereCipher也不起作用,因为它找不到VigenereCipher(这是有道理的,因为我们正在定义它)。

我可以创建rotate一个模块级方法,并且可以,但我真的不想这样做,因为它只在VigenereCipher.

也试过这个答案但没有成功。

实际代码在这里。单元测试在这里

fac*_*ger 4

错误是从这里引发的:

_TABLE: Final[ClassVar[Dict[str, str]]] = dict({(chr(i + ord("A")), rotate(i)) for i in range(26)})
Run Code Online (Sandbox Code Playgroud)

您试图引用rotate位于类命名空间中的变量。然而,Python 推导式有其自己的作用域,并且没有简单的方法将其与类命名空间连接。rotate在理解评估时没有闭包或全局变量- 因此NameError被调用。上面的代码与您的代码相同:

def _create_TABLE():
    d = {}
    for i in range(26):
        d[chr(i + ord("A"))] = rotate(i) # -> NameError('rotate')
    return d
_TABLE: Final[ClassVar[Dict[str, str]]] = dict(_create_TABLE())
del _create_TABLE
Run Code Online (Sandbox Code Playgroud)

如何从类变量引用静态方法

python中的类变量是某个对象,因此它可以引用程序中的任何对象。您可以遵循以下一些习语:

方法一:

class VigenereCipher(Cipher):
    @staticmethod
    def rotate(n: int) -> str:
        return string.ascii_uppercase[n:] + string.ascii_uppercase[:n]

    _TABLE: Final[ClassVar[Dict[str, str]]]

VigenereCipher._TABLE = {chr(i + ord("A")): VigenereCipher.rotate(i) for i in range(26)}
Run Code Online (Sandbox Code Playgroud)

方法二:

class VigenereCipher(Cipher):
    @staticmethod
    def rotate(n: int) -> str:
        return string.ascii_uppercase[n:] + string.ascii_uppercase[:n]

    _TABLE: Final[ClassVar[Dict[str, str]]] = (
        lambda r=rotate.__func__: {chr(i + ord("A")): r(i) for i in range(26)})()
Run Code Online (Sandbox Code Playgroud)

方法三:

class VigenereCipher(Cipher):
    @staticmethod
    def rotate(n: int) -> str:
        return string.ascii_uppercase[n:] + string.ascii_uppercase[:n]

    _TABLE: Final[ClassVar[Dict[str, str]]] = dict(zip(
        (chr(i + ord("A")) for i in range(26)),
        map(rotate.__func__, range(26)),
    ))
Run Code Online (Sandbox Code Playgroud)

方法四:

class VigenereCipher(Cipher):
    @staticmethod
    def rotate(n: int) -> str:
        return string.ascii_uppercase[n:] + string.ascii_uppercase[:n]

    _TABLE: Final[ClassVar[Dict[str, str]]] = {
        chr(i + ord("A")): r(i) for r in (rotate.__func__,) for i in range(26)}
Run Code Online (Sandbox Code Playgroud)

还有一些基于以下基础的方法:

您可以在相关主题中找到更详细的答案