8

For example:

def foo():
    print 'first foo'
def foo():
    print 'second foo'

foo()

silently produces: second foo

Today I copy/pasted a function definition in the same file and changed a few lines in the body of second definition but forgot to change the function name itself. I scratched my head for a long time looking at the output and it took me a while to figure it out.

How to force the interpreter throw at least a warning at redefinition of a function? Thanks in advance.

Thom Wiggers
  • 6,938
  • 1
  • 39
  • 65
subba
  • 1,625
  • 2
  • 16
  • 18
  • 1
    If the intepreter warned about redefining functions, things like `@decorators` would be a pain – jonrsharpe Apr 18 '14 at 13:16
  • @jonrsharpe Interesting implementation detail (try it with `dis`): In CPython, `@deco def f(): ...` loads `deco`, creates the function *without* binding it to `f`, calls the decorator function retrieved in the first step (it and its arguments are already on the stack in the right order), and only then binds the result to `f`. This saves a redundant `STORE_FAST, LOAD_FAST` pair, and unintentionally sidesteps the problem you describe. –  Apr 18 '14 at 13:21
  • @delnan interesting indeed; I didn't know that, thanks! – jonrsharpe Apr 18 '14 at 13:24
  • 3
    There are actually great use-cases for *allowing* rebinding function objects. `@property` in a class definition for example, lets you reuse the same object to bind additional setters and getters, rebinding to an updated descriptor object. – Martijn Pieters Apr 18 '14 at 13:25
  • This didn't raise any warnings with `-Wall` enabled, so I think it's just part of the language you have to live with. PyCharm flags it as a problem, but YMMV with other IDEs. – dmcauslan Apr 18 '14 at 13:37
  • suggesting reopen, since the answer here is better than the "duplicated" question – Aprillion Dec 01 '16 at 14:08

5 Answers5

10

How about using pylint?

pylint your_code.py

Let your_code.py be

1 def dup():
2    print 'a'
3 def dup():
4    print 'a'
5
6 dup()

pylint shows

C:  1,0: Missing docstring
C:  1,0:dup: Missing docstring
E:  3,0:dup: function already defined line 1     <--- HERE!!!!
C:  3,0:dup: Missing docstring

...

If you are using Pydev, You can find duplication interactively. When mouseover the second dup, It says Duplicated signature: dup.

pydev

emesday
  • 6,078
  • 3
  • 29
  • 46
3

It is one of features of Python. Functions are values just as integers, so you can pass them around and rebind to names, just as you would in C++ using function pointers.

Look at this code:

def foo(): # we define function and bind func object to name 'foo'
print "this if foo"

foo()     # >>>this if foo

bar = foo # we bind name 'bar' to the same function object

def foo(): # new function object is created and bound to foo
    print "this is new foo"

foo() # foo now points to new object
# >>>this is new foo
bar() # but old function object is still unmodified:
# >>>this if foo

Thus interpreter works fine. In fact it is common to redefine functions when you are working with interactive interpreter, until you get it right. Or when you use decorators.

If you want to be warned about redefining something in python, you can use 'lint' tools, like pylint (see function-redefined (E0102))

m.wasowski
  • 6,329
  • 1
  • 23
  • 30
2

I think it is a similar behaviour for what happens with variables (called identifiers):

In [4]: a = 2

In [5]: a = 3

In [6]: a
Out[6]: 3

you don't see the interpreter whining about a being redefined.

EDIT Somebody commented below and I think it might help clarifying my answer:

[this is due to] function objects are not treated differently from other objects, and that names defined via def aren't treated differently from names defined via other means

See the language reference about def being a reserved identifier.

lorenzog
  • 3,483
  • 4
  • 29
  • 50
  • 1
    That `def` is a reserved identifier has nothing to do with functions being ordinary variables, it just means you can't have a variable called `def` because that would clash with its use in defining function. Function names *are* ordinary names, but that shows in other ways. –  Apr 18 '14 at 13:41
  • @delnan it's as you said: function names are ordinary names. I just could not find it on the language spec (care to help?) – lorenzog Apr 18 '14 at 13:42
  • I don't think it's explicitly mentioned anywhere. It's a consequence of the fact that function objects aren't treated differently from other objects, and that names defined via `def` aren't treated differently from names defined via other means. –  Apr 18 '14 at 13:44
  • I clarified my answer and made community-wiki. – lorenzog Apr 18 '14 at 13:51
0

You need to know python philosophy of object. Everything in python is object. When you create a function, you actually create object of class function and name it as your function name.

When you re-define it you simply replace old object with new one simple as creating new variable of same name.

e.g.

>>> a=10
>>> print a
10
>>> a=20
>>> print a
20

same way you can check class of the function.

 >>> def a():
 ...     pass
 ... 
 >>> a.__class__
 <type 'function'>

which indicates your function is actually a object or variable that can be replaced with any other object variable of same class.

New_User123
  • 104
  • 11
-1

Well, you could check if it exists like this

def foo():
    pass

def check_foo(variable_dict):
    if 'foo' in variable_dict:
        print('Function foo already exists!')
    else:
        print('Function foo does not exist..')

>>> check_foo()
True
>>> del foo
>>> check_foo(locals())
False
Prateek Alat
  • 216
  • 2
  • 8
  • 1
    Of course one can do the check manually, but that's of no use at preventing accidental overwriting. Unless you explicitly code an `assert` before *every* function definition, which is an awful lot of noise and just as prone to copy&paste errors. –  Apr 18 '14 at 13:23
  • @delnan Yeah, that's true. Maybe it can be prevented by making the method 'final' in a class like in Java? – Prateek Alat Apr 18 '14 at 13:34
  • @delnan It can be done, but is not advised, according to [link]http://stackoverflow.com/questions/2425656/how-to-prevent-a-function-from-being-overridden-in-python[/link] – Prateek Alat Apr 18 '14 at 13:36
  • Why the -1? The code just checks whether the function exists. – Prateek Alat Apr 18 '14 at 15:24