Reputation: 662
I have a number of classes with code like this. Each __init__
starts a thread and a logger with the name of the class. How do I get the name of the current class in its own definition, as a string, inside __init__
? Note that self
may not be an instance of the current class, so the following is not quite foolproof.
from threading import Thread
import logging
def myClassName(myclass):
myclass._class_name = myclass.__name__
return myclass
@myClassName
class SomeClass(object):
def __init__(self):
class_name = type(self)._class_name
print "My class name in __init__ is", class_name
self.thread = Thread(name=class_name)
self.logger = logging.getLogger(class_name)
Update:
To clarify:
Upvotes: 12
Views: 16926
Reputation: 251116
In Python 3 this is pretty straight forward, we can use the __class__
cell variable to get the current class.
In Python 2 we can achieve something similar by injecting class's name in functions globals scope using a metaclass and later cleaning it up.
from functools import wraps
from types import FunctionType
def decorate(func, class_name):
@wraps(func)
def wrapper(*args, **kwargs):
sentinel = object()
actual_value = func.__globals__.get('__class__', sentinel)
func.__globals__['__class__'] = class_name
try:
result = func(*args, **kwargs)
finally:
if actual_value is sentinel:
del func.__globals__['__class__']
else:
func.__globals__['__class__'] = actual_value
return result
return wrapper
class Meta(type):
def __new__(cls, name, bases, attrs):
for k, v in attrs.items():
if isinstance(v, FunctionType):
attrs[k] = decorate(v, name)
return type.__new__(cls, name, bases, attrs)
class A:
__metaclass__ = Meta
def func(self):
print(__class__)
print('Inside A')
class B(A):
def func(self):
print(__class__)
print('Inside B')
super(B, self).func()
B().func()
Output:
B
Inside B
A
Inside A
To get the __class__
variable as the class object itself we can make few changes:
def decorate(func, cls):
@wraps(func)
def wrapper(*args, **kwargs):
sentinel = object()
actual_value = func.__globals__.get('__class__', sentinel)
func.__globals__['__class__'] = cls
try:
result = func(*args, **kwargs)
finally:
if actual_value is sentinel:
del func.__globals__['__class__']
else:
func.__globals__['__class__'] = actual_value
return result
return wrapper
class Meta(type):
def __new__(cls, name, bases, attrs):
cls = type.__new__(cls, name, bases, attrs)
for k, v in attrs.items():
if isinstance(v, FunctionType):
setattr(cls, k, decorate(v, cls))
return cls
Now output would be:
<class '__main__.B'>
Inside B
<class '__main__.A'>
Inside A
Upvotes: 9
Reputation: 168766
You can retrieve the name of the class of an an object thus:
obj.__class__.__name__
Example:
class SomeClass(object):
def __init__(self):
print("I am a %s"%self.__class__.__name__)
class Derived(SomeClass):
pass
x = SomeClass()
y = Derived()
Result:
$ python x.py
I am a SomeClass
I am a Derived
Upvotes: 12