0

我有这样的Language课程:

class _Language:
    def __init__(self, name, bRightToLeft=False):
        self.name = name
        self.bRightToLeft = bRightToLeft

    def isRightToLeft(self):
        return self.bRightToLeft

    def getName(self):
        return self.name

class Language:
    EN = _Language("English")
    AF = _Language("Afrikaans")
    SQ = _Language("Albanian")  

我创建了一个 Language 对象:

l1 = Language.EN

在对对象进行一些处理后english,我想检索它的“子类型”,即EN. 例如:

print l1

[出去]:

EN

我尝试在 Language 类中添加__repr__or ,但是当我没有得到:__str__ENprint l1

class Language:
    EN = _Language("English")

    AF = _Language("Afrikaans")
    SQ = _Language("Albanian")   

    def __str__(self):
        return self.__name__

[出去]:

Language

我怎样才能访问变量名称,以便当print l1我得到EN

4

3 回答 3

5

任何单个_Language实例都不知道您在Language命名空间(或其他任何地方)中给它的两个字母名称。所以你有两种可能:

(1) 让每个实例都存储该信息,以免不得不重复自己:

class _Language:

    def __init__(self, name, code, rtl=False):
        self.name = name
        self.code = code.upper()
        self.rtl  = rtl

    def __str__(self):
        return self.code

# ...

class Language:
    EN = _Language("English", "EN")

当然,您可以通过提供类方法 onLanguage来创建和注册_Language实例来减少重复,而不是在类定义时创建它们:

class Language:
    @classmethod
    def add(cls, name, code, rtl=False):
        settatr(cls, code, _Language(name, code, rtl))

Language.add("English", "EN")
Language.add("Afrikaans", "AF")
Language.add("Albanian", "SQ")

这可能是我个人喜欢的解决方案。

(2) 让您的_Language.__str__方法搜索Language命名空间以找出它在那里知道的名称:

def __str__(self):
    for k, v in Language.__dict__.iteritems():
        if v is self:
           return k

在这种情况下,您可以存储结果,因此只需要查找一次:

class _Language:

# ...

    code = None
    def __str__(self):
        if self.code:
            return self.code
        for k, v in Language.__dict__.iteritems():
            if v is self:
               self.code = k
               return k
于 2014-11-27T00:38:22.867 回答
1

正如b4hand 所指出的,__name__type的名称,这显然不是您想要的。对象不知道分配给它们的变量的名称。如果你仔细想想,他们怎么可能?同一个对象可以分配给 20 个不同的变量,或者没有(也许它唯一存在的地方是作为集合的成员)。

将代码传递给_Language构造函数,就像kindall 的回答一样,显然是最干净的解决方案……但它需要一些重复。除了乏味之外,它还引入了出错的机会——以及最难调试的那种愚蠢的拼写错误。

那么,有没有办法解决这个问题?当然。只需在构建后添加代码:

class _Language:
    def __init__(self, name, bRightToLeft=False):
        self.name = name
        self.bRightToLeft = bRightToLeft

    def isRightToLeft(self):
        return self.bRightToLeft

    def getName(self):
        return self.name

    def __str__(self):
        return self.code

class Language:
    EN = _Language("English")
    AF = _Language("Afrikaans")
    SQ = _Language("Albanian")

for code, language in inspect.getmembers(Language):
    if code.isalpha() and code.isupper():
        language.code = code

但是,当我们这样做的时候,我们也可以省去所有的重复_Language

class Language:
    EN = "English"
    AF = "Afrikaans"
    SQ = "Albanian"

for code, language in inspect.getmembers(Language):
    if code.isalpha() and code.isupper():
        _language = _Language(language)
        _language.code = code
        setattr(Language, code, _language)

尽管我认为如果您使用 dict 或 anenum.Enum而不是只包含类属性的类,这可能会更好。

或者,如果你想变得花哨,有各种各样的Enum食谱展示了如何创建一个自定义枚举元类,该元类将使用现有的魔法让Enum值知道它们的名称,还可以让你像在其中一样将其他属性塞入其中_Language班级。

于 2014-11-27T01:03:51.353 回答
0

压倒一切__str__是正确的方法,但是self.__name__是类名而不是成员名,这就是为什么您总是看到“语言”的原因。

为了做你想做的事,你需要做一些元编程。

一种方法是将“短”名称作为参数传递给构造函数。一个更hacky的方法是使用Language类对象的内部字典。

于 2014-11-27T00:38:15.587 回答