0

I have occurrences of accidentally redeclared functions in a python codebase. The occurrences are simple function definitions, no functools.singledispatch involved. I want to fix that. However, I do not know which of the functions python actually uses. I want to keep only that function.

Please understand, that I ask this question to understand what happens behind the scene and how to solve the issue properly. Of course, I know that redeclaring functions in python is bad coding practice. I also know that a linter can hint you on that. But if the problem is there and I want to solve that, I must understand and find out all of which occurrences should be deleted.

I made a small test and it seems that python actually uses the last definition:

def func1(a: int):
    print("Num", a)


def func1(a: int):
    print("A number: ", a)


func1(100)

->

/home/user/PycharmProjects/project/.venv/bin/python /home/user/.config/JetBrains/PyCharm2023.1/scratches/redeclared_func.py 
A number:  100

I just wanted to ask, to be sure that this interpretation is correct. In that case I would keep none but the last occurrence, of course. There may be a difference between, e.g. Python versions, Python interpreters etc. What happens, if a module with redeclared functions is imported and then the function is redeclared again?

  • *"python actually uses the last definition"* Not exactly: in your example, look at what happens if you insert `func1(100)` **between** the two definitions. – slothrop Aug 23 '23 at 09:08
  • Related: https://stackoverflow.com/questions/73093750/why-does-two-main-functions-in-a-single-python-script-work – slothrop Aug 23 '23 at 09:09
  • 1
    Function and class statements simply assign objects to names in the *local scope*, and the resulting variables behave in exactly the same way as any other variables. Your example is therefore equivalent to e.g. `func1 = 1; func1 = 2`. In Python there's only ever variable *assignment*; there's no such thing as variable *declaration* as such. If you add the line `func1 = func0` between the two `def` statements, you can still access both functions (only by different names). – ekhumoro Aug 23 '23 at 09:49

1 Answers1

4

The definition that holds is the last that was met in the flow of execution, just as if you were assigning a variable.

E.g.

def F():
    print("First")
F()

if True:
    def F():
        print("Second")
    F()
else:
    def F():
        print("Third")
    F()

F()

says

First
Second
Second
Yves Daoust
  • 672
  • 9
  • That sounds quite logical! However, it makes fixing the problem more difficult, as dependent on the actual function call this or the other definition may be used. So I have to trace code flow to see which function is used for each call. – Wör Du Schnaffzig Aug 23 '23 at 09:12
  • if you are importing the function from another module then I believe the last definition is the one that would be imported, that may help a little bit – Anentropic Aug 23 '23 at 09:21
  • 1
    @WörDuSchnaffzig: it is no problem to let the functions emit a message to identify themselves when they are called. Unless the function definitions and calls are made "statically", you cannot spare tracing. – Yves Daoust Aug 23 '23 at 09:55
  • @WörDuSchnaffzig What "problem"? Variable shadowing is just an irrelevant side-effect unless your code actually needs to access the object being shadowed. In such cases, you can simply use different names (i.e. within the current scope). – ekhumoro Aug 23 '23 at 09:55