如何从类变量中引用静态方法 [英] How to reference static method from class variable
问题描述
给班上
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
但是,根据此帖子,rotate
应该可以解决.请注意,使用类名称VigenereCipher
进行限定也不起作用,因为它找不到VigenereCipher
(这很有意义,因为我们正在定义它).
However, according to this post, rotate
should be resolvable. Note that qualifying with class name VigenereCipher
doesn't work either since it can't find VigenereCipher
(makes sense, since we are in the process of defining it).
我可以将rotate
设为模块级别的方法,并且可以使用,但是我真的不想这样做,因为只有VigenereCipher
才需要它.
I can make rotate
a module-level method, and that works, but I don't really want to since it only is needed in VigenereCipher
.
也尝试了此答案,但未成功.
Also tried this answer with no success.
Actual code is here. Unit test is here.
推荐答案
错误从这里引发:
_TABLE: Final[ClassVar[Dict[str, str]]] = dict({(chr(i + ord("A")), rotate(i)) for i in range(26)})
您正在尝试引用位于类命名空间中的变量rotate
.但是python理解有其自己的范围,没有简单的方法将其与类名称空间连接.理解评估时不存在闭包或全局变量rotate
-因此将调用NameError
.上面的代码与您的代码相同:
You are trying to refer the variable rotate
that is located in class namespace. However python comprehensions have their own scope and there is no simple way to connect it with class namespace. There is no closure or global variable rotate
at the moment of comprehension evaluation - thus NameError
is invoked. The code above is equal to your code:
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
如何从类变量中引用静态方法
How to reference static method from class variable
python中的类变量是某个对象,因此它可以引用程序中的任何对象.您可以按照以下惯用语进行操作:
A class variable in python is some object, so it can refer to any objects in your program. Here some idioms you can follow:
方法1:
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)}
方法2:
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
函数; - 元类;
-
__init__subclass__
方法; - 描述符的
__set_name__
; - 堆栈框架;
- 使用
global
关键字.
locals
function;- metaclasses;
__init__subclass__
method;- descriptor's
__set_name__
; - stack frames;
- using
global
keyword.
您可以在相关的 查看全文