7

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?

1
  • If the func1() is really only relevant to method1(), and the inner method becomes a problem to you, it is an indication that it really should be a separate class. Commented Oct 15, 2010 at 22:54

5 Answers 5

6

Sure, no problem:

foo.py:

def func1():
    pass

script.py:

import foo
class tata:
   def method1(self):
      func1=foo.func1
Sign up to request clarification or add additional context in comments.

6 Comments

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: Alex Martelli's answer here (stackoverflow.com/questions/1744258/…) persuaded me to avoid from foo import func1 entirely.
@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 (stackoverflow.com/questions/3908335/…) to find a way to make what you think is private not-so-private.
@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.
@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).
|
3

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

Comments

2

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()

1 Comment

+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.
2

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()

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.