获取某些duck-type类的变量名

时间:2014-11-27 00:31:08

标签: python class duck-typing repr

我有一个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

[OUT]:

EN

我尝试在语言课程中添加__repr____str__,但在我EN时我没有print l1

class Language:
    EN = _Language("English")

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

    def __str__(self):
        return self.__name__

[OUT]:

Language

我如何访问变量名称,以便{I} print l1EN

3 个答案:

答案 0 :(得分: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")

当然,您可以通过在Language上提供类方法来创建和注册_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

答案 1 :(得分:1)

正如b4hand所指出的,__name__类型的名称,这显然不是您想要的。对象不知道已分配给它们的变量的名称。如果你考虑一下,他们怎么样?同一个对象可以分配给20个不同的变量,或者没有(可能它唯一存在的位置是一个集合的成员)。

将代码传递到_Language构造函数中,就像在kindall's answer中一样,显然是最干净的解决方案......但它需要重复一些。除了单调乏味之外,它还带来了错误的机会 - 以及最难以调试的愚蠢错字。

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

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或enum.Enum而不是除了类属性之外的任何类,这可能会更好。

或者,如果你想获得幻想,有各种Enum食谱显示如何创建一个自定义枚举元类,它将使用现有的魔法让Enum值知道他们的名字,并且还允许您像在_Language类中一样将其他属性填充到其中。

答案 2 :(得分:0)

覆盖,__str__是正确的方法,但self.__name__是类名而不是成员名,这就是为什么你总是看到"语言"。

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

一种方法是通过"短"作为构造函数的参数的名称。更hacky的方法是使用Language类对象的内部字典。