1

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'
9
  • 4
    form_fill and error are local variables with model1(). They don't even exist except during a call to the outer function. Commented Jul 28, 2021 at 1:06
  • 1
    Do you mean to define a class or perhaps a module (i.e. a separate file)? Commented Jul 28, 2021 at 1:07
  • 3
    You should define a class with methods instead of nested functions. The functions inside of a function cannot be used outside of it given Python's namespaces. Commented Jul 28, 2021 at 1:09
  • 2
    Why? Seems like an XY problem. Commented Jul 28, 2021 at 1:12
  • 2
    What you are trying to do is impossible, although the suggestions of using a class or a module are good. Commented Jul 28, 2021 at 1:14

4 Answers 4

4

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

Sign up to request clarification or add additional context in comments.

1 Comment

I was wondering about the cons and this was helpful thanks for the explanation!
0

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

Comments

0

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.

Comments

-1

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

2 Comments

the form_fill() and error() is inside mode1()
Yes you're right. Indentation error on my end while copying the code from the IDE to here

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.