In Python 3.5, how can the class name be assigned to a class variable? 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
.
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
. my_class = Foo.class_name()
produces 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)
Note that having the class method
@classmethod
def class_name(cls):
return cls.__name__
Brings nothing compared to calling x.__class__.__name__
directly.
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
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.
class Foo(object):
def __init__(self):
self.class_name = self.__class__.__name__
x = Foo()
x.class_name
EDIT 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 ):
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):
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. 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 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:
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. :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.