将类名分配给Python中的类变量

时间:2016-02-25 17:33:40

标签: python python-3.x static-variables

在Python 3.5中,如何将类名分配给类变量?显而易见的替代方法是对类名进行硬编码。

class Foo(object):
    the_module = __name__
    also_the_module = __module__

    def name_of_module(self):
        return __name__
    def name_of_class(self):
        return __class__.__name__  

print("Foo.the_module=      ", Foo.the_module)
print("Foo.also_the_module= ", Foo.also_the_module)
print("Foo.__name__=        ", Foo.__name__)  # what is desired but outside of class def
print("Foo().name_of_module=", Foo().name_of_module())
print("Foo().name_of_class= ", Foo().name_of_class()) # what is desired but inside a method

我尝试从@classmethod的第一个参数中获取该类。

class Foo(object):
    @classmethod
    def class_name(cls):
        return cls.__name__

# Both of these produce the correct response but neither
# can be used assign to a class variable
print("Foo.class_name()=    ", Foo.class_name())
print("Foo().class_name()=  ", Foo().class_name()) 

不幸的是,在分配给类变量时无法调用此函数。 class = class_name生成NameError: name 'class_name' is not definedmy_class = Foo.class_name()生成NameError: name 'Foo' is not defined

注意:更新了问题以使用正确的Python术语“类变量”而不是静态变量(反映我的C ++背景)

3 个答案:

答案 0 :(得分:1)

请注意具有类方法

@classmethod
def class_name(cls):
    return cls.__name__

与直接致电x.__class__.__name__相比,什么也没有带来。

如果要分配类名,只需修改类本身:

class Foo(object):
@classmethod
def class_name(cls):
    return cls.__name__

Foo.__name__ = "bar"
a = Foo()
print(a.class_name())

输出bar

如果只想为一个实例使用不同的类名,则需要动态创建一个新类(从旧类继承)并更改该类的名称。

def set_class_name(instance, new_class_name):
orig_class = instance.__class__

class _new_class(orig_class):
    pass

_new_class.__name__ = new_class_name
a.__class__ = _new_class

a = Foo()
set_class_name(a, 'bar')
print(a.class_name())

也输出bar

答案 1 :(得分:0)

class Foo(object):

def __init__(self):
    self.class_name = self.__class__.__name__

x = Foo()

x.class_name

编辑 Waitaminute。我不认为我能得到你。静态变量是什么意思?

答案 2 :(得分:0)

在Python 3(从3.3版开始)中,最简单的方法是使用__qualname__(感谢这个answer的帮助):

class Foo(object):
    name = __qualname__

class Bar(Foo):
    name = __qualname__

print((Foo.name, Bar.name))

这将产生所需的输出:

('Foo', 'Bar')

对于较早的版本,或者如果您想更明确一些,您总是可以提及您的类的名称(是的,它不是DRY,而是KISS):

class Foo(object):
    name = Foo.__name__

class Bar(Foo):
    name = Bar.__name__

print((Foo.name, Bar.name))

但是,以上两个建议都要求您在派生类中重新分配名称。显然,当您在问题中实现一个时,您意识到可以只使用类方法,但是每次您想使用该名称时,都必须调用它:

class Foo(object):
    @classmethod
    def name(cls):
        return cls.__name__

class Bar(Foo):
    pass

print((Foo.name(), Bar.name()))

如果您不喜欢紧跟name的括号,则可能要考虑的是创建一个类属性。这样,您可以使其保持只读和可继承性,就像使用类方法一样,但仍保持类变量的外观。创建类属性是this question的主题。一个answer建议使用一种方法修饰符(在那里定义的classproperty,尽管有些冗长(尽管您可以削减setter方法):

# classproperty is defined in the aforementioned answer

class Foo(object):
    @classproperty
    def name(cls):
        return cls.__name__

class Bar(Foo):
    pass

print((Foo.name, Bar.name))

另一个answer建议使用元类。对我来说这是一个新概念。尽管提供了简洁的代码,但Tim Peters mentioned in this pretty good guide about meta classes的引用阻止了我推荐它:

class FooMetaclass(type):
    @property
    def name(cls):
        return cls.__name__

class Foo(metaclass=FooMetaclass):
    # for Python 2, remove the metaclass assignment above, and add:
    # __metaclass__ = FeatureMetaclass
    pass

class Bar(Foo):
    pass

print((Foo.name, Bar.name))

我认为这些就足够了。 :)