如何添加或更改类(不是实例)?

时间:2015-10-12 11:35:51

标签: python

我想直接在类对象中设置一个属性,而不需要创建实例,例如:有一个可以像__ 名称 __属性一样访问的替代名称:

class Foo:
    pass

> Foo.__name__
Foo

但这不起作用:

some_file.py:

class Foo:
    alternativ_name = __name__ + "_ending"

print(Foo.alternativ_name)

打印:

__main___ending

如果我在交互式控制台中尝试它,它会再次返回其他内容:

>>> class Foo:
...   alt_name = __name__ + "_ending"
...
>>> Foo.alt_name
'builtins_ending'

我想要达成的目标是:

class Foo:
    alt_name = __name__ + "_ending"
Foo.alt_name

应该返回:

'Foo_ending'

我该怎么做?

2 个答案:

答案 0 :(得分:1)

变量__name__Foo.__name__实际上指向了两个不同的东西。在__name__类中使用Foo仍然使用全局变量,而不是Foo.__name__

在类中,不可能显式引用同一个类:

class Foo:
    alt_name = Foo.__name__ + "_ending"
    # raises NameError: name 'Foo' is not defined

如果您想要对象上的属性,可以在运行时执行此操作,例如在__init__。如果你真的想要类本身的属性,你可以使用元类来实现:

class Foo:
    class __metaclass__(type):
        @property
        def alt_name(cls):
            return cls.__name__ + "_ending"

答案 1 :(得分:0)

在您尝试访问它时,尚未创建

Foo.__name__。因此,当您访问__name__时,它会获得模块的__name__。有几种方法可以解决这个问题。一种是通过使用元类,但这对于仅向类添加属性来说是非常过分的。第二种是在类上使用装饰器,第三种是使alt_name成为非数据描述符或者属性。

使用装饰者:

def add_alt_name(template):
    def decorator(klass):
        klass.alt_name = template.format(klass.__name__)
        return klass
    return decorator

@add_alt_name(template="{}_ending")
class Foo:
    pass

print(Foo.alt_name)

使用非数据描述符:

class AlternativeName:
    def __init__(self, template, name="alt_name"):
        self.template = template
        self.name = "_" + name

    def __get__(self, instance, klass):
        try:
            return getattr(klass, self.name)
        except AttributeError:
            pass
        alt_name = self.template.format(klass.__name__)
        setattr(klass, self.name, alt_name)
        return alt_name

class Foo:
    alt_name = AlternativeName(template="{}_ending")

print(Foo.alt_name)

使用装饰器要简单得多。