43

Is there a way to define a function to be global from within a class( or from within another function, as matter of fact)? Something similar to defining a global variable.

7
  • 4
    Why would you want to do that at all? Commented Jan 13, 2015 at 19:32
  • 2
    You can assign a global variable a function defined locally, if that's what you mean Commented Jan 13, 2015 at 19:32
  • 2
    I venture to propose a concrete use case for this: dynamical redefinition of functions aliases, based on user input. Eg, let's say you use bytearray() for optimization purposes, because all your values are assumed to be within 0 and 255. Now let's say that you want to support values above 255 in some cases, but you want to get maximum performance for cases when values are guaranteed to be bounded to 0..255. One way to do that is at my_setup_function() to redefine bytearray dynamically to a list() if needed. Commented Dec 28, 2015 at 1:39
  • 7
    Can anyone explain why this was downvoted? I think it's a very valid question, I've just come across this issue myself. Commented Jul 20, 2017 at 13:09
  • 6
    @Eddy: There are numerous valid reasons to do this (e.g., non-premature optimization as highlighted by @gaborous). Sadly, some Pythonistas believe that their personal failure to conceive of a valid use case for a requested solution implies all possible solutions to be harmful. See also: the snark radiating from Martijn Pieters' comment above. Commented Aug 7, 2018 at 2:41

4 Answers 4

46

Functions are added to the current namespace like any other name would be added. That means you can use the global keyword inside a function or method:

def create_global_function():
    global foo
    def foo(): return 'bar'

The same applies to a class body or method:

class ClassWithGlobalFunction:
    global spam
    def spam(): return 'eggs'

    def method(self):
        global monty
        def monty(): return 'python'

with the difference that spam will be defined immediately as top-level class bodies are executed on import.

Like all uses of global you probably want to rethink the problem and find another way to solve it. You could return the function so created instead, for example.

Demo:

>>> def create_global_function():
...     global foo
...     def foo(): return 'bar'
... 
>>> foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>> create_global_function()
>>> foo
<function foo at 0x102a0c7d0>
>>> foo()
'bar'
>>> class ClassWithGlobalFunction:
...     global spam
...     def spam(): return 'eggs'
...     def method(self):
...         global monty
...         def monty(): return 'python'
... 
>>> spam
<function spam at 0x102a0cb18>
>>> spam()
'eggs'
>>> monty
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'monty' is not defined
>>> ClassWithGlobalFunction().method()
>>> monty()
'python'
Sign up to request clarification or add additional context in comments.

3 Comments

@flamenco: I was indeed assuming that the OP meant from a method on a class. Not from the class body itself. In any case, the same applies to using the statement in a class definition body, but I'd be rather pushed as to why you'd want to do that.
@flamenco: The code in my previous answer clearly explains that you don't a wrapper function.
@flamenco: altering globals is not thread-safe and can easily lead to very confusing code. Altering functions this way even more so.
12

You can use global to declare a global function from within a class. The problem with doing that is you can not use it with a class scope so might as well declare it outside the class.

class X:
  global d
  def d():
    print 'I might be defined in a class, but I\'m global'

>> X.d

   Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   AttributeError: 'X' object has no attribute 'd'

>> d()

I might be defined in a class, but I'm global

2 Comments

So I haven't posted more than 4 times in stackoverflow. Big deal? The answer nonetheless does explain to you how to get this done and a native problem associated with the question.
outside the class is like breaking the encapsulation principle of OOPS. However the method declared as global can be called by other methods within the class but on a any object of the class. In which case the 'global'word really does not makes sense. Its more local (private in java terms) than global as only the class methods can access this method declared as global. This all sounds messy naming convention is this specif scenario. I believe this aspect needs rectification in python
4

I found a case where global does not have the desired effect: inside .pdbrc file. If you define functions in .pdbrc they will only be available from the stack frame from which pdb.set_trace() was called.

However, you can add a function globally, so that it will be available in all stack frames, by using an alternative syntax:

def cow(): print("I'm a cow")
globals()['cow']=cow

I've tested that it also works in place of the global keyword in at least the simplest case:

def fish():
    def cow(): 
        print("I'm a cow")
    globals()['cow']=cow

Despite being more verbose, I thought it was worth sharing this alternative syntax. I have not tested it extensively so I can't comment on its limitations vs using the global keyword.

Comments

1

The global trick doesn't seem to work with python 3.12 or later (and likely earlier)

This does, setting the name in the builtins module directly with sys.modules:

sys.modules['builtins'].name=name

e.g.

import sys
def cow():
    print("I'm a cow")
sys.modules['builtins'].cow = cow

The builtins module has all the identifiers that are globally available in Python.

This can be done even more neatly using decorators. After reading the excellent essay at How do I make function decorators and chain them together? I also provide this tested solution:

def make_builtin(func):
    def builtin_func(*args, **kwargs):
        func(*args, **kwargs)
    import sys
    sys.modules['builtins'].__dict__[func.__name__]=func
    return builtin_func

@make_builtin
def cow(): print("I'm a cow")

Be warned though, just because it is easy, doesn't make it a good idea.

Why not do it nicely, with functools.wrap https://docs.python.org/3/library/functools.html?

def make_builtin(func):
    import functools
    @functools.wraps(func)
    def builtin_func(*args, **kwargs):
        func(*args, **kwargs)
    import sys    
    sys.modules['builtins'].__dict__[func.__name__]=func
    return builtin_func

But I don't like import functools making functools available to the wrapper function when it would not otherwise have been, so maybe a sly loader is needed

5 Comments

the answer just above yours works well in Python 3.11.2
is the function made available in another module?
ah no, supposing the file p.py contains the definition of fish (containing the definition of cow) then the call fish(), after import p I must do p.cow() and globals()['cow'] is erroned. I must do from p import * to be able to do cow() and globals()['cow']. Sorry, when I did the test it was entering the definition and call of fish directly in the python shell, not through an import
I think to add a non built-in in sys.modules['builtins'] is a very bad idea !
You are correct

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.