call a nested function (function inside another function)

Question:

I have a function like

def mode1():

  #some code

  def form_fill():
    #some code

  def error():
    #some other code

and in somewhere else in the code, I want to call the form_fill() only

what I’ve already tried is

event, value = window.read()
if event == 'Mode 1':
    mode1_submit()
    mode1()
if event == 'Mode 2':
    mode2_submit()
    mode2()
if event == 'Mode 3':
    try:
        mode1.form_fill()
    except:
        mode1.error()
        mode1.form_fill()

window.close()

in the event == 'Mode 3' I want to perform only a specific function
from the code above I get the following error

mode1.form_fill()
AttributeError: 'function' object has no attribute 'form_fill'
Asked By: CatChMeIfUCan

||

Answers:

You should probably use a class for this problem, but if you really want to use a nested loop you could do something like this:

def mode1(function_to_call=None):
    print("mode1")

    def form_fill():
        print("form_fill")

    def error():
        print("error")

    possibles = locals().copy()
    function = possibles.get(function_to_call)

    if function:  # checks if function exists
        function()



mode1("form_fill")

The output will be:

mode1
form_fill
Answered By: CozyCode

THIS IS NOT SOMETHING YOU SHOULD DO, but you could create a nested function attribute like so:

def foo():
    # for closures or strictly local function
    # then this is useful!
    # ugly hack other wise to try and create methods.
    def bar():
        print('bar')    
    
    # if there are multiple function, return a container...
    return bar

Then:

foo.bar=foo()
foo.bar()
# prints 'bar'

BUT, this is far easier with a class:

class Foo:
    # class can hold related methods, setters and getters, 
    # protected variables, etc. 
    # Python is DESIGNED to do this.
    def bar(self):
        print('bar')

Then:

f=Foo()
f.bar()
# prints 'bar'

Why is it easier?

  1. Because Python is designed to use the second example, a class, but the first example is a hack. The ways to use classes are well documented and tested.
  2. It does not scale well. Each function attribute needs to be added from the OUTSIDE of the function.
  3. You will run into local vs global namespace issues if you try and change variables. Classes gracefully support both instance and class data.

It is horrible — don’t do it. Use a class or a module to hold methods.


After a morning coffee, you can potentially do something like this if you really want to add function attributes — Use a decorator to monkey patch a function:

def add_func_to(function):
    # decorator to add function attributes
    def attr_f(new_func):
        setattr(function, new_func.__name__, new_func)
        return new_func
    return attr_f 

# some function to add an attribute function to:
def foo():
    pass

@add_func_to(foo)
# added attribute function below
def attr_f(string):
    print(string)

Test it:

>>> foo.attr_f('test')
test

This is still limited vs a class or module since you will be limited to using global or passed variables. It is more applicable if you just want to add a function attribute to an existing function and be done with it…

Answered By: dawg

The solution which I would recommend is

def mode1():

  #some code

  def form_fill():
    #some code

  def error():
    #some other code
return form_fill, error

event, value = window.read()
if event == 'Mode 1':
    mode1_submit()
    mode1()
if event == 'Mode 2':
    mode2_submit()
    mode2()
if event == 'Mode 3':
    form_fill, error = mode1()
    try:
        #mode1.form_fill()
        form_fill()
    except:
        #mode1.error()
        error()
        #mode1.form_fill()
        form_fill()

window.close()
Answered By: Akhil S

You can see this answer, in case it helps: https://stackoverflow.com/a/74326236/20386708

I think something like that would make it possible:

def mode1(invoke = None):
    #some code
    def form_fill():
        #some code
    def error():
        #some other code
    if invoke == 'form_fill':
        form_fill()
    if invoke == 'error':
        error()
    
# and in somewhere else in the code 
event, value = window.read()
if event == 'Mode 1':
    mode1_submit()
    mode1()
if event == 'Mode 2':
    mode2_submit()
    mode2()
if event == 'Mode 3':
    try:
        mode1(invoke='form_fill')
    except:
        mode1(invoke='error')
window.close()

But I agree with dawg, working with class multiplies the options and makes the code easier.

Answered By: José Juan
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.