如何从类变量中引用静态方法 [英] How to reference static method from class variable

查看:151
本文介绍了如何从类变量中引用静态方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给班上

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 function;
  • metaclasses;
  • __init__subclass__ method;
  • descriptor's __set_name__;
  • stack frames;
  • using global keyword.

您可以在相关的 查看全文

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆