Reputation: 122
I would like to set an attribute to an class object directly, without creating an instance, e.g. having an alternative name that can be accessed like the __ name __ attribute:
class Foo:
pass
> Foo.__name__
Foo
But this doesn't work:
some_file.py:
class Foo:
alternativ_name = __name__ + "_ending"
print(Foo.alternativ_name)
This prints:
__main___ending
If I try it in the interactive Console, it returns something else again:
>>> class Foo:
... alt_name = __name__ + "_ending"
...
>>> Foo.alt_name
'builtins_ending'
What I would like to achive is:
class Foo:
alt_name = __name__ + "_ending"
Foo.alt_name
should return:
'Foo_ending'
How do I do this?
Upvotes: 1
Views: 85
Reputation: 75588
The variables __name__
and Foo.__name__
actually point to two different things. Using __name__
within the Foo
class still uses the global variable, and not Foo.__name__
.
Within the class, it is not possible to explicitly reference the same class:
class Foo:
alt_name = Foo.__name__ + "_ending"
# raises NameError: name 'Foo' is not defined
If you want the property on objects, you can do it during runtime, e.g. in the __init__
. If you really want the property on the class itself, you can do that using metaclasses:
class Foo:
class __metaclass__(type):
@property
def alt_name(cls):
return cls.__name__ + "_ending"
Upvotes: 1
Reputation: 40703
Foo.__name__
has not yet been created at the point you are trying to access it. Therefore, when you access __name__
it gets the module's __name__
. There are several ways you can solve this. One is by using a metaclass, but this is pretty overkill for just adding an attribute to a class. The second is to use a decorator on the class, and the third is to make alt_name
a non-data descriptor or maybe a property.
Using a decorator:
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)
Using a non-data descriptor:
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)
Much simpler just to use a decorator.
Upvotes: 0