2

If the following function is defined in a different file and returned and executed in a separate file, will it give the file name of where it was defined? Or where it was called?

File1.py
-----
def get_current_filename():
        return lambda: os.path.realpath(os.path.abspath(__file__))

File2.py
----
import File1
x= File1.get_current_filename()
x()
Dr. Chocolate
  • 2,043
  • 4
  • 25
  • 45
  • 1
    You could try this yourself by changing the lambda body to `print(__file__)` – Carcigenicate Mar 05 '19 at 18:44
  • 1
    this isn't to do with `lambda` directly, a regular `def` function would behave the same – Chris_Rands Mar 05 '19 at 18:47
  • You're essentially asking if Python is dynamically scoped or statically scoped language (it's the latter). Using a lambda is a irrelevant here, it's not like a lisp lambda. – wim Mar 05 '19 at 19:01
  • `lambda` is irrelevant, Python uses lexical scoping, and does not support dynamic scoping. Maybe a duplicate of: https://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture ? – juanpa.arrivillaga Mar 05 '19 at 19:07
  • I don't think it's irrelevant in some languages being that the Lambda is passed to the calling script and executed in the context of the calling script. – Dr. Chocolate Mar 05 '19 at 22:30

2 Answers2

2

This will use the filename where it was defined, i.e. File1.py.

The import system populates the __file__ attribute on each module object during module loading. Docs here.

Note that there is no supported way to get the calling module's filename (File2.py) here, that's only possible with hacks. Avoid.

wim
  • 338,267
  • 99
  • 616
  • 750
  • 1
    Haha was literally typing up how to get the name with the calling file when your edi popped up. Thank you for the guidance. – Dr. Chocolate Mar 05 '19 at 18:54
2

As wim said, the function gets executed in such a way that __file__ will return the name of the file the function is present in (File1.py).

It is however possible to achieve what you want, although again as wim said it is a bit hacky. You can do this by looking at the frame records in the call stack using inspect.stack:

File1.py:

import inspect

def get_current_filename():
        return inspect.stack()[1][1]

File2.py:

import File1
x = File1.get_current_filename()
print(x)

Output:

C:\<omitted>\File2.py

The first [1] indicates to look at the second frame in the call stack (the first frame being the location that called inspect.stack, the second being the location that called that), the second [1] gets the filename from the frame.

Nick is tired
  • 6,860
  • 20
  • 39
  • 51