简体   繁体   English

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

[英]Assign class name to a class variable in Python

In Python 3.5, how can the class name be assigned to a class variable? 在Python 3.5中,如何将类名称分配给类变量? The obvious alternative is to hardcode the class name. 显而易见的替代方法是对类名进行硬编码。

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

I tried getting the class from the first argument of a @classmethod . 我尝试从@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()) 

Unfortunately, this function cannot be called when assigning to a class variable. 不幸的是,分配给类变量时不能调用此函数。 class = class_name produces NameError: name 'class_name' is not defined . class = class_name产生NameError: name 'class_name' is not defined my_class = Foo.class_name() produces NameError: name 'Foo' is not defined . my_class = Foo.class_name()产生NameError: name 'Foo' is not defined

NOTE: Updated question to use the correct Python term "class variable" and not a static variable (reflecting my C++ background) 注意:已更新问题,以使用正确的Python术语“类变量”而不是静态变量(反映了我的C ++背景)

Note that having the class method 请注意,具有class方法

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

Brings nothing compared to calling x.__class__.__name__ directly. 与直接调用x.__class__.__name__相比,什么也没有带来。

If you want to assign the class name, just modify the class itself: 如果要分配类名称,只需修改类本身即可:

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

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

outputs bar 输出bar

If you wanted different class name only for one instance, you need to create a new class on the fly (inheriting from the old class) and change the name of this class. 如果只想为一个实例使用不同的类名,则需要动态创建一个新类(继承自旧类)并更改该类的名称。

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())

outputs bar too. 输出bar

class Foo(object):

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

x = Foo()

x.class_name

EDIT Waitaminute. 编辑 Waitaminute。 I don't think I'm getting you. 我不认为我会得到你。 What do you mean with static variable? 静态变量是什么意思?

In Python 3 (since version 3.3), the most straightforward way to do this is to use __qualname__ (which I came across thanks to this answer ): 在Python 3(从3.3版开始)中,最简单的方法是使用__qualname__ (由于这个答案 ,我遇到了):

class Foo(object):
    name = __qualname__

class Bar(Foo):
    name = __qualname__

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

This produces the desired output: 这将产生所需的输出:

('Foo', 'Bar')

For earlier versions, or if you want to be more explicit, you could always just mention the name of your class (yes, it's not DRY, but it's KISS): 对于较早的版本,或者如果您想更明确一些,可以始终提及类的名称(是的,它不是DRY,而是KISS):

class Foo(object):
    name = Foo.__name__

class Bar(Foo):
    name = Bar.__name__

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

However, both suggestions above require you to re-assign the name in derived classes. 但是,以上两个建议都要求您在派生类中重新分配名称。 Obviously, as you implemented one in your question, you are aware that you could just use a class method, but then you'd have to call it each time you wanted the name: 显然,当您在问题中实现一个时,您知道可以只使用类方法,但是每次您想使用该名称时,都必须调用它:

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

class Bar(Foo):
    pass

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

If you don't like the parenthesis that cling to name , what you might want to consider is to create a class property. 如果您不喜欢紧贴name的括号,那么您可能要考虑的是创建一个class属性。 That way you can keep it read-only and inheritable, just like the class method approach, but still maintaining the appearance of a class variable. 这样,您可以使其保持只读和可继承性,就像使用类方法一样,但仍保持类变量的外观。 Creating a class property is the topic of this question . 创建类属性是此问题的主题。 One answer suggests using a method decorator ( classproperty , defined there), albeit with some verbosity (though you can cut the setter method): 一个答案建议使用方法装饰器( 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))

Another answer suggests using a meta-class. 另一个答案建议使用元类。 This is a new concept for me. 对我来说这是一个新概念。 While it provides succinct code, the quote by Tim Peters mentioned in this pretty good guide about meta classes deters me from recommending it: 尽管它提供了简洁的代码,但在有关元类的相当不错的指南中 ,Tim Peters所引用的引文阻止了我推荐它:

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))

I think those are enough. 我认为这些就足够了。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM