¿Cómo obtengo la ruta de archivo para una clase en Python?

95

Dada una clase C en Python, ¿cómo puedo determinar en qué archivo se definió la clase? Necesito algo que pueda funcionar desde la clase C o desde una instancia de C.

La razón por la que estoy haciendo esto es porque generalmente soy un fanático de los archivos que pertenecen juntos a la misma carpeta. Quiero crear una clase que use una plantilla de Django para representarse como HTML. La implementación base debe inferir el nombre de archivo de la plantilla en función del nombre de archivo en el que está definida la clase.

Digamos que puse una clase LocationArtifact en el archivo "base / artifacts.py", luego quiero que el comportamiento predeterminado sea que el nombre de la plantilla sea "base / LocationArtifact.html".

Staale
fuente
2
Esos asumen que conoce el módulo que está buscando en el archivo, solo tendré la cadena del módulo mientras trabajo con implementaciones de una clase.
Staale

Respuestas:

130

Puede utilizar el módulo de inspección , así:

import inspect
inspect.getfile(C.__class__)
DNS
fuente
1
No estoy seguro de qué estaba haciendo diferente, pero en lugar de getfiletener que usar: inspect.getmodule(C.__class__)
AJP
4
Nota: no funciona en clases creadas por el usuario
Daniel Braun
6
Probablemente debería ser así inspect.getfile(C). Si Ces una clase, entonces se C.__class__refiere a object, lo que generará una excepción TypeError: <module 'builtins' (built-in)> is a built-in class. Creo que solo cquieres usar una instancia inspect.getfile(c.__class__).
Cheshirekow
1
Esto no fue así para una clase que extiende una clase base abstracta ( metaclass=abc.ABCMeta), ya que devuelve en /usr/local/lib/python3.7/abc.pylugar del archivo apropiado. La solución de @JarretHardie (abajo) funcionó mejor.
martian111
36

tratar:

import sys, os
os.path.abspath(sys.modules[LocationArtifact.__module__].__file__)
Jarret Hardie
fuente
1
Para obtener la ruta de una instancia de C (como lo desea el OP), reemplace LocationArtifactcon obj.__class__donde obj es una instancia de LocationArtifact.
martian111
5

Este es el enfoque incorrecto para Django y realmente forzar las cosas.

El patrón típico de la aplicación Django es:

  • /proyecto
    • /nombre de la aplicación
      • modelos.py
      • views.py
      • /plantillas
        • index.html
        • etc.
Soviut
fuente
1
+1: Haz lo que Django hace de forma natural y la vida es mucho más sencilla.
S.Lott
1
Convenido. Django es uno de los frameworks con la menor cantidad de "magia", pero las plantillas, etiquetas de plantilla y aplicaciones tienen algunas expectativas como parte de su patrón. Si tienes que hacer una inferencia de clase alocada, probablemente vas en la dirección equivocada.
Soviut