如何从类变量中引用静态方法[重复]

Posted

技术标签:

【中文标题】如何从类变量中引用静态方法[重复]【英文标题】:How to reference static method from class variable [duplicate] 【发布时间】:2020-04-15 20:48:35 【问题描述】:

给定班级

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))

编译失败(使用 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

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

我可以将rotate 设为模块级方法,这很有效,但我真的不想这样做,因为它只在VigenereCipher 中需要。

也试过this回答没有成功。

实际代码是here。单元测试是here。

【问题讨论】:

评论不用于扩展讨论;这个对话是moved to chat。 【参考方案1】:

从这里引发错误:

_TABLE: Final[ClassVar[Dict[str, str]]] = dict((chr(i + ord("A")), rotate(i)) for i in range(26))

您正在尝试引用位​​于类命名空间中的变量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

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

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)

方法二:

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))()

方法3:

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)),
    ))

方法4:

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)

还有一些方法基于:

locals function; metaclasses; __init__subclass__ method; descriptor's __set_name__; stack frames; 使用global关键字。

你可以在相关topic找到更详细的答案

【讨论】:

创建一个方法并删除它似乎是一个巨大的黑客攻击。另外,在您的代码中,rotate 仍然是静态方法吗? @Abhijit Sarkar 我刚刚以更易于理解的方式重写了您的代码 - 错误仍然存​​在 我没有关注,那会是什么错误?我不是在这里要求进行代码审查,所以如果你只是重写代码而不解决问题,那是没有帮助的。 这可能会导致任何类型检查失败,例如Final 类型应在定义时初始化。并且不应该被重新定义。 这行得通,但正如@AChampion 所说,它在Final 面前苍蝇。但它之所以有效,是因为,我从文档中引用,“这些属性没有运行时检查。”。太糟糕了,Python 中的静态类型只是语法糖。

以上是关于如何从类变量中引用静态方法[重复]的主要内容,如果未能解决你的问题,请参考以下文章

从类加载进内存到对象创建,各部分的执行顺序

从类外部的现有方法创建静态方法? (“未绑定方法”错误)

通过对象引用访问实例变量的静态嵌套类的 Java 示例 [重复]

如何在python中通过引用调用静态方法[重复]

如何从类变量中调用函数方法[重复]

无法从静态上下文中引用非静态方法 getSocketFactory [重复]