22

So i have this problem, i want to get the name of a python class in this way:

class TestClass():
 myName = (get class name here automatically)
 saveDirectory = os.path.join(saveDir, myName) # so i can save it in unique location
 def __init__(self):
 pass # do something

However, it seems that __class__.__name__ doesn't actually exist as of yet at the time when myName is created. So i have been forced to put that into the __init__() function, like this:

class TestClass():
 def __init__(self):
 self.myName = self.__class__.__name__
 saveDirectory = os.path.join(saveDir, self.myName) # so i can save it in unique location
 pass # do something

But this has a big problem, because I cannot get the name of the class until I instantiate the class, I instend to create a few gigabytes of data for each instance of the class to be saved in the saveDirectory, so it can be re-used later. So I don't actually want to do go ahead with my current solution.

Is there anyway to get the class name as I have intended? Or am I just dreaming?

EDIT:

Thanks guys for your great suggestions. I am going to spend a little bit of time taking a look at Metaclasses. Otherwise, I will probably create a dictionary globally, and have references to these instantiated classes instead.

asked Jan 24, 2013 at 23:52
5
  • 1
    If you're trying to get the name of the class just after defining it, isn't a constant string attribute sufficient? You can change it in subclasses, if needed Commented Jan 24, 2013 at 23:56
  • 3
    If you are always using the class name, why not just use a string? The class name is static so there should be no reason to continuously ask for it. Commented Jan 24, 2013 at 23:57
  • It’s not possible to get the type name from within the class definition as at the time it is interpreted, the class is not created yet. Commented Jan 24, 2013 at 23:59
  • you could do it in a metaclass or decorator. but that's insane. implementation left as an exercise to the reader. Commented Jan 25, 2013 at 0:00
  • 7
    There's no reason to set self.MyName to self.__class__.__name__ in __init__(). Just use self.__class__.__name__! Commented Jan 25, 2013 at 0:01

7 Answers 7

17

Since python 3.3, you can use the __qualname__ variable:

class TestClass():
 myName = __qualname__
answered Nov 3, 2017 at 22:53
Sign up to request clarification or add additional context in comments.

Comments

9

Just use a method?

class TestClass(object):
 @classmethod
 def get_save_directory(cls):
 return os.path.join(save_dir, cls.__name__)

Or you could just have a class attribute indicating the save directory; less magic is usually a good thing. Plus you could change the name of the class later without breaking your storage.

Also, what? Gigabytes?!

answered Jan 24, 2013 at 23:59

Comments

7

The only way to actually do what you are trying to during the class definition is to use a metaclass:

def saveDirMeta(name, bases, dct):
 dct['saveDirectory'] = os.path.join(saveDir, name)
 return type(name, bases, dct)
class TestClass(object):
 __metaclass__ = saveDirMeta # this adds the 'saveDirectory' attribute
 def __init__(self):
 pass # do something

Or on Python 3.x:

class TestClass(metaclass=saveDirMeta):
 def __init__(self):
 pass # do something

This is definitely less clear than just using the following:

class TestClass():
 saveDirectory = os.path.join(saveDir, 'TestClass')
 def __init__(self):
 pass # do something
answered Jan 25, 2013 at 0:10

Comments

2

I guess what you're doing is not possible, because the class doesn't even exist when you do:

myName = (get class name here automatically)

But soon after the class has been interpreted you can pass the class object to some other function to do the job for you.

In [1]: def save_class(cl):
 myName = cl.__name__
 print myName #or do whatever you wanna do here
 ...: 
In [2]: class A:pass
In [3]: save_class(A)
A
answered Jan 25, 2013 at 0:06

Comments

2

During class interpretation, there is no "there" there yet. So, yes, what your initial example shows is not possible. But please explain why this would need to be known before the class even technically exists?

Barring a good answer to that outstanding question, one is left with trying to get the class' name from:

1. outside the interpreted class definition, uninstantiated
 class demo(object):
 pass
 print demo.__name__ # 'demo'
2. from within the class definition, uninstantiated (or instantiated ;-)
 class demo2(object):
 @classmethod
 def myName(cls):
 return cls.__name__
 print demo2.myName() # 'demo2'
 print demo2().myName() # 'demo2'
or
3. within an actual instance of the class
 class demo3(object):
 def myClassName(self):
 return self.__class__.__name__
 print demo3().myClassName() # 'demo3'

Beyond that, please edit the question and add some details that explain why your initial attempt needs to work the way you want, before instantiation and yet internal to the class definition, while your 2nd example is problematic. Also, how does saveDir get passed/come from? (A global outside of the class?) Please show some code showing how you intend to use what you'd like to work. There may be a way to redesign to get there from here, in effect if not literally.

answered Oct 6, 2013 at 0:16

Comments

2

Other than the metaclass in F J's answer, I can think of two other ways. I'll start with the nicer looking one. You don't need to use a metaclass; sometimes a descriptor is perfectly adequate.

class ClassNameDescriptor(object):
 def __get__(self, instance, owner):
 return owner.__name__
class BaseClass(object):
 name = ClassNameDescriptor()
class Foo(BaseClass):
 pass

The other way, if you really need the class name from inside the class body (unlikely), you can snoop on the call stack. The class name, as it appears in source, is on the code object being executed by the class definition:

import sys
def get_class_name_from_inside_class():
 return sys._getframe().f_back.f_code.co_name
class Foo(object):
 name = get_class_name_from_inside_class()
 print name

Of the ones presented so far, only this last one allws you to use the name, as a string, from inside the class body, Unfortunately, this doesn't work in all versions of python, notably IronPython does not implementent the call stack introspection as it's not available in the DLR.

There's a way to get it without introspecting the stack, portably. It's similar to the answer provided by F J, using a metaclass, but instead uses the __prepare__ feature available in Python 3:

class namedMeta(type):
 def __prepare__(mcls, name, bases, **kwargs):
 return {'name': name}
class Foo(metaclass=named):
 print name
answered Oct 6, 2013 at 2:28

Comments

0

try this. you can refer to your current class by _class. (I'm using python 2.7)

class Meta(type):
 def __init__(self, *args):
 super(Meta, self).__init__(*args)
 self._class = self
 self.saveDir = str(self._class)
class Wow(object):
 __metaclass__ = Meta
>>> Wow.saveDir
>>> Wow().saveDir
answered Jun 3, 2014 at 12:41

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.