142

Given a class C in Python, how can I determine which file the class was defined in? I need something that can work from either the class C, or from an instance of C.

I am doing this because I am generally a fan of putting files that belong together in the same folder. I want to create a class that uses a Django template to render itself as HTML. The base implementation should infer the filename for the template based on the filename that the class is defined in.

Say I put a class LocationArtifact in the file "base/artifacts.py", then I want the default behaviour to be that the template name is "base/LocationArtifact.html".

4
  • 1
    Duplicate: stackoverflow.com/questions/269795/…, stackoverflow.com/questions/602846/… Commented Mar 30, 2009 at 14:06
  • 3
    Those assume you know the module you are looking up the file for, I will just have the module string as I work with implementations off a class. Commented Mar 31, 2009 at 5:51
  • Does this answer your question? How do I find the location of Python module sources? Commented Jul 30, 2023 at 21:46
  • @mkrieger1 that doesn't work, because the input here is a class, not a module. It's easy enough to check the __file__ of a module, but classes don't generally have that, nor do they have a direct link to the module in which they were defined. It takes a couple of extra steps, as in Jarret Hardie's answer. Commented Jun 29, 2024 at 23:51

4 Answers 4

195

You can use the inspect module, like this:

import inspect
inspect.getfile(C.__class__)
Sign up to request clarification or add additional context in comments.

5 Comments

Not sure what I was doing different but instead of getfile I had to use: inspect.getmodule(C.__class__)
Note: does not work on a classes created by the user
This should probably be inspect.getfile(C). If C is a class, then C.__class__ refers to object, which will raise an exception TypeError: <module 'builtins' (built-in)> is a built-in class. I think that only for an instance c do you want to use inspect.getfile(c.__class__).
This did not for a class that extends an abstract base class (metaclass=abc.ABCMeta), as it returns /usr/local/lib/python3.7/abc.py instead of the appropriate file. The solution by @JarretHardie (below) worked better.
The accepted answer: guaranteed to be the wrong answer. It's a StackOverflow tradition by now.
55

try:

import sys, os
os.path.abspath(sys.modules[LocationArtifact.__module__].__file__)

5 Comments

To get the path from an instance of C (as desired by the OP), replace LocationArtifact with obj.__class__ where obj is an instance of LocationArtifact.
This also works for meta classes!
inspect take alot resources, this is perfect
This is the way. inspect should generally be avoided in production code. It's slow. It's fragile. It fails in common edge cases. If you can't write a one-liner that does it, you probably shouldn't do it.
yuck...........
5

This is the wrong approach for Django and really forcing things.

The typical Django app pattern is:

  • /project
    • /appname
      • models.py
      • views.py
      • /templates
        • index.html
        • etc.

2 Comments

+1: Do what Django does naturally and life is so much simpler.
Agreed. Django is one of the frameworks with the least amount of "magic", but templates, template tags and apps have some expectations as part of their pattern. If you're having to do wacky class inference you're probably going in the wrong direction.
-1

You can use the error to get the path of your class

import os
import traceback
class C:
  def getClassPath(self):
    #get foldet path
    try:
        raise ValueError("Example error")
    except Exception as e:
        tb = traceback.extract_tb(e.__traceback__)
       
        return os.path.dirname(tb[-1].filename)
c = C()
print('path is',c.getClassPath())

Comments

Your Answer

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.