How to get filename of subclass?

Viewed 1833

How to get the filename of the subclass?

Example:

base.py:

class BaseClass:
    def __init__(self):
        # How to get the path "./main1.py"?

main1.py:

from base import BaseClass

class MainClass1(BaseClass):
    pass
3 Answers

Remember that self in BaseClass.__init__ is an instance of the actual class that's being initialised. Therefore, one solution, is to ask that class which module it came from, and then from the path for that module:

import importlib

class BaseClass:
    def __init__(self):
        m = importlib.import_module(self.__module__)
        print m.__file__

I think there are probably a number of way you could end up with a module that you can't import though; this doesn't feel like the most robust solution.

If all you're trying to do is identify where the subclass came from, then probably combining the module name and class name is sufficient, since that should uniquely identify it:

class BaseClass:
    def __init__(self):
        print "{}.{}".format(
            self.__module__,
            self.__class__.__name__
        )

You could do it by reaching back through the calling stack to get the global namespace of the caller of the BaseClass.__init__() method, and from that you can extract the name of the file it is in by using the value of the __file__ key in that namespace.

Here's what I mean:

base.py:

import sys

class BaseClass(object):
    def __init__(self):
        print('In BaseClass.__init__()')
        callers_path = sys._getframe(1).f_globals['__file__']
        print('  callers_path:', callers_path)

main1.py:

from base import BaseClass

class MainClass1(BaseClass):
    def __init(self):
        super().__init__()

mainclass1 = MainClass1()

Sample output of running main1.py:

In BaseClass.__init__()
  callers_path: the\path\to\main1.py

I think you're looking to the wrong mechanism for your solution. Your comments suggest that what you want is an exception handler with minimal trace-back capability. This is not something readily handled within the general class mechanism.

Rather, you should look into Python's stack inspection capabilities. Very simply, you want your __init__ method to report the file name of the calling sub-class. You can hammer this by requiring the caller to pass its own __file__ value. In automated fashion, you can dig back one stack frame and access __file__ via that context record. Note that this approach assumes that the only time you need this information is when __init__ is called is directly from a sub-class method.

Is that enough to get you to the right documentation?

Related