The error is raised from here:
_TABLE: Final[ClassVar[Dict[str, str]]] = dict({(chr(i + ord("A")), rotate(i)) for i in range(26)})
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
A class variable in python is some object, so it can refer to any objects in your program. Here some idioms you can follow:
Approach 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)}
Approach 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)})()
Approach 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)),
))
Approach 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)}
There are also approaches based on:
- locals function;
- metaclasses;
- __init__subclass__ method;
- descriptor's __set_name__;
- stack frames;
- using
global
keyword.
You can find a more detailed answers in the related topic