Python Forum
accessing globals from a function
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
accessing globals from a function
#1
normally a function only has read-only access to global variables. in order to update a global variable the code must declare which variable names it will access using the global statement. i am finding that if i initially make these variables be mutable container types such as list or dictionary, i can update the container contents without a global statement. so, instead of doing:
counter = 0
...
def increment():
    global counter
    counter += 1
    return
i could do:
counter = [0]
...
def increment():
    counter[0] += 1
    return
is this safe to do? if not, why not?
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#2
You only need the global keyword to assign to the name.
You can always access and mutate globals without it.
The second one is mutable, so yeah, it works.

As to whether it is safe, I suppose. It is as safe as any other method of mutatating a global. Both methods are horrible and shouldn't be used unless absolutely necessary.

Pretty much the only use case I encourage for the global keyword is writing a function that creates the global object which, from that point on, will be considered constant everywhere else. For instance I load graphics in a function in pygame as they can't be loaded until some initialization is done but I still want them accessible everywhere. They are created as global but are never again altered.
Reply
#3
i do agree using global where not necessary is a bad thing. but where it is necessary, how would you choose to do it between the 2 examples i gave?
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#4
There is a third way
glo = type('glo', (), {})()
glo.counter = 0

def increment():
    glo.counter += 1
You can even do this
>>> glo = type('glo', (), {})()
>>> glo.__dict__ = globals()
>>> counter = 0
>>> def increment():
...     glo.counter += 1
... 
>>> increment()
>>> increment()
>>> increment()
>>> counter
3
Reply
#5
I prefer the 'third' (Gribouillis) way.
He made a class. Here the same not in compact form with an __iter__ method:

class Count:

    def __init__(self, start=0):
        self.counter = start

    def increment(self):
        self.counter += 1
        return self.counter
    def __iter__(self):
        while True:
            yield self.increment()
Somewhere you create an instance of Counter and then you can assign to instance.counter.
My first reaction, if I see a global, can I do this with a class. The benefit is, that I can control the behavior with the magic methods. For example this implementation allows iteration. The class itself is an Iterator. You can also protect attributes in the class with @property. You can have also class-attributes, for example to see how much instances of Counter has been created.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#6
A modern count Think
from dataclasses import dataclass

@dataclass
class Counter:
    counter: int = 0

    def __call__(self):
        self.counter += 1
        return self.counter
>>> count = Counter()
>>> count()
1
>>> count()
2
>>> count()
3
>>> count
Counter(counter=3)
>>> count.__annotations__
{'counter': <class 'int'>}
Reply
#7
lots of ways!

you need to develop a function. while designing it you realize it needs to remember something from a previous call. which of these ways would you use? would you need to start all over with the design or would you adapt what you have done so far? yeah i know; sorry that's so vague.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#8
(Sep-01-2018, 07:55 PM)Skaperen Wrote: while designing it you realize it needs to remember something from a previous call. which of these ways would you use?
I would immediately turn the function into a method of a class.

That said, there are nice alternatives. I sometimes use the following trick
class Static:
    def __init__(self, *args, **kwargs):
        self.__dict__.update(*args, **kwargs)

def myfunc(static=Static(counter=0)):
    static.counter += 1
    return static.counter

print(myfunc(), myfunc(), myfunc()) # prints 1 2 3
Reply
#9
what if you are trying to implement a function for some very large program that calls it as a function in thousands of places all over its code?
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  why globals() exits python when quit() is aliased as q abc12346 4 687 May-23-2023, 08:56 AM
Last Post: Gribouillis
  How to avoid exec(), globals(), locals(), eval() paul18fr 10 5,014 Apr-21-2021, 05:53 PM
Last Post: snippsat
  accessing a second level nested function varsh 3 2,473 Aug-13-2020, 06:57 AM
Last Post: varsh
  Accessing method as function object ClassicalSoul 2 2,008 Feb-14-2020, 09:31 PM
Last Post: wavic
  Use of Globals CWatters 5 3,828 Nov-13-2017, 09:00 PM
Last Post: CWatters
  Globals vs Function mcmxl22 2 3,336 Feb-04-2017, 11:38 AM
Last Post: ichabod801

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020