views:

112

answers:

5

Is it possible to declare functions in python and define them later or in a separate file?

I have some code like:

class tata:
   def method1(self):
      def func1():
         #  This local function will be only used in method1, so there is no use to
         # define it outside.
         #  Some code for func1.
      # Some code for method1.

The problem is that the code becomes messy and difficult to read. So I wonder if it's possible for instance to declare func1 inside method1 and define it later?

+2  A: 

The inner definition creates a separate name in the inner scope. It will shadow anything you define later on with the same name. If you want to define the function later on, then just do so. The name will only be checked for when it is actually used.

def foo():
  print 'foo'
  bar()

def bar():
  print 'bar'

foo()
Ignacio Vazquez-Abrams
+6  A: 

Sure, no problem:

foo.py:

def func1():
    pass

script.py:

import foo
class tata:
   def method1(self):
      func1=foo.func1
unutbu
Nice thinking! However the idea of a local function is to make this function usable only inside the inner scope. So, what's the point of defining the new `func1` inside `method1`? Wouldn't be easier to do: `from foo import func1` and use it.
banx
@banx: Alex Martelli's answer here (http://stackoverflow.com/questions/1744258/is-import-module-better-coding-style-than-from-module-import-function) persuaded me to avoid `from foo import func1` entirely.
unutbu
@banx: Yes, putting the definition of `func1` inside `method1` makes it at least semi-private, though I would not put it past an enterprising bytecode hacker (http://stackoverflow.com/questions/3908335/python-function-local-name-binding-from-an-outer-scope/3913185#3913185) to find a way to make what you think is private not-so-private.
unutbu
@banx: However, if you want semi-privacy, your best choice is to define func1 inside method1.You could import a string and run `exec` on it, or use bytecode hacking to inject func1 into method1, but the first could be very bad for performance, and neither of those options promote clean, readable code.
unutbu
@ubuntu: Alex Martelli's answer persuaded me too, thanks for the link! Do you think it would be better to call the `import` statement inside `method1` as suggested by @intuited (in case no other functions are needed from `foo`).
banx
@banx: I wouldn't worry about the performance implication until it has been demonstrated that `import foo` is the bottleneck. The PEP8 style guide (http://www.python.org/dev/peps/pep-0008/) urges "Imports are always put at the top of the file" and I think this is a good practice because it makes clear what the total dependencies of your module or program are.
unutbu
+3  A: 

I think what you want is to import the function within method1, e.g.

def method1(...):
    from module_where_func1_is_defined import func1
    # do stuff
    something = func1(stuff, more_stuff)
    # do more stuff

Python modules are basically just files; as long as the file module_where_func1_is_defined.py is in the same directory as your script, method1 will be able to import it.

If you want to be able to customize the way method1 works, and also make it even more clear that it uses func1, you can pass func1 to method1 as a default parameter:

import other_module

# various codes

def method1(other_args, func=other_module.func1)
    # do stuff
    something = func(stuff, more_stuff)
    # do more stuff
intuited
+2  A: 

If func1() needs to handle anything contained in the scope of method1() you're best leaving func1()'s definition there. You'll have to have func1() receive any pertinent data as parameters if it's not defined within the scope of method1()

Ishpeck
+1 Because having nested functions directly access names from their containing scope is an important idiom in Python. It's current scoping rules are very powerful and well thought-out -- see [PEP 227 - Statically Nested Scopes(ttp://www.python.org/dev/peps/pep-0227/) introduced in Python 2.1. Putting definitions in a separate file would currently prevent this unless worked around somehow.
martineau
A: 

You can create methods afterwards


class Something(object):
   def test1(self):
     pass

def dummy(self):
   print "ok", self

Something.test1 = dummy

However it's not possible to have an anonymous function (well, there are lambda expressions but you cannot have statements there), so you have to provide a temporary name

You might want to use decorators in order to make it more readable:

def define(cls, name):
  def decor(f):
     setattr(cls, name, f)
  return decor


class Something(object):
   def test1(self):
     pass

@define(Something, "test1")
def dummy(self):
   print "ok", self

This code should be more readable. It will still pollute dummy but initialize it with null.

ithkuil