-1

I wish to do :

if var not in globals():
     global var
     var = -1

or

try : var
except NameError :
    global var
    var = -1

The problem is :

global var
^
SyntaxError: name 'var' is used prior to global declaration

So what can be done to achieve similar effect ?


EDIT :

This is not at module level, but rather in a function. The variable is supposed to store a position value that the function uses and updates in it but needs to persist between calls.

I have been made aware that the above code is bad practise, and I agree, and request those agreeing to suggest alternative "good practise" methods, if possible.


EDIT 2 :

This question is required to help me fix my previous question. There, the obj_cnt is getting reset at every call, bugging up the function that accesses objects from a pickled file by an "index" (an abstraction), as I try to avoid unnecessary seeking and reading by querying indexes in sorted order.

The above should clear up the "Why?" part.


EDIT 3:

I did not end up needing to do this convoluted stuff. I solved the above question by using classes.

Nevertheless, thanks to everyone who helped me here.

user426
  • 213
  • 2
  • 9
  • This code is run at module level. Do you want to do this in a function or at the module level as you show? – tdelaney Jul 30 '21 at 03:53
  • @tdelaney I'm calling a function that accesses objects in a binary pickled file. To avoid excessive seeking and reading through for every access, I have ordered the access requests in order that they are in the file. But, the function that fetch's the object needs a variable persistent through calls that keeps the current object index (an abstraction used by the caller). – user426 Jul 30 '21 at 03:57
  • Why don't you just move the global statement up? In any case, I too find this dubious – juanpa.arrivillaga Jul 30 '21 at 03:59
  • @juanpa.arrivillaga it's ugly for the caller to have to define variables that the callee uses – user426 Jul 30 '21 at 04:00
  • 1
    @juanpa.arrivillaga then please feel free to ignore the question and answer something more worthy of your time. thanks for all the help. – user426 Jul 30 '21 at 04:02
  • 1
    It's not about being worthy of my time or not, it's about pointing out bad practices and anti-patterns. – juanpa.arrivillaga Jul 30 '21 at 04:07
  • @user426 - The `global` keyword can't be used at module level. If you are trying to do this in a function, then have your example show that. In a function, you just have to make sure that `global` is declared before the variable is used. The very top of the function perhaps. – tdelaney Jul 30 '21 at 04:07
  • @juanpa.arrivillaga "everything you are doing here is ugly...makes no sense" is not constructive, helpful criticism, though thanks anyways. I am interested in the code working though, and I will love to use better practise for that, but find not such alternative. If there is one, I will use it. – user426 Jul 30 '21 at 04:09
  • Using global state for this is a bad move, and the *way* you're managing that global state is another bad move on top of that. Even if you wanted to use global state, it would make more sense to just initialize `var = None` immediately after the function definition so you don't have to check whether the variable exists. – user2357112 Jul 30 '21 at 04:09
  • @juanpa.arrivillaga - I don't see this as particularly anti-pattern-y. Its kindof a late binding. If a function wants to use a configuration, it can catch the `NameError` and use that for the initialization. Try and ask forgiveness. – tdelaney Jul 30 '21 at 04:10
  • @user2357112supportsMonica could you suggest an alternative for a position-keeping variables used only by the function but that needs to persist across function calls ? Apart from passing it as an argument, that is – user426 Jul 30 '21 at 04:11
  • 1
    Rather than using global state, it might make more sense to have a class instance with instance variables, or use a generator and `yield`, or just pass an argument (it's not clear why you don't want to do that). – user2357112 Jul 30 '21 at 04:13
  • @tdelaney I see mutable global state as a fairly widely recognized anti-pattern. Indeed, things like OOP, functional programming, they are all fundamentally ways of handling *global state*, either by encapsulation in objects, or via *removing it entirely* – juanpa.arrivillaga Jul 30 '21 at 04:13
  • Alternatives: 1) use an object to manage this state, 2) pass the value as an argument to the function, and return a new value to the caller. – juanpa.arrivillaga Jul 30 '21 at 04:14
  • @user2357112supportsMonica passing an argument is a bit ugly in terms of the caller sending variables it does not use simply so that the function uses them as storage objects, seemed odd and un-pythonic too. – user426 Jul 30 '21 at 04:15
  • @juanpa.arrivillaga - but I'm sure I could find a dozen examples in the standard library. Deferring initialization is a normal thing. Some people might use a sentinel like `var = None`, but the try-and-die approach is reasonable IMHO. – tdelaney Jul 30 '21 at 04:15
  • @juanpa.arrivillaga come on. Global state is very important to keep track of and update in many, many, many programs – user426 Jul 30 '21 at 04:17
  • @user2357112supportsMonica - I get what you are saying, but a module is already working much like a singleton class. If a program is never intended to have multiple instances, modules and functions can be a reasonable solution. Adding classes just for the extra weight may be unreasonable sometimes. – tdelaney Jul 30 '21 at 04:17
  • @user426 you realize, there are *entire paradigms* that don't allow you to mutate state, correct? I am aware that there are a lot of poorly designed programs out there. – juanpa.arrivillaga Jul 30 '21 at 04:17
  • 1
    @tdelaney yeah, and I consider the singleton to be bad for this very reason - it is basically obfuscated, mutable global state. – juanpa.arrivillaga Jul 30 '21 at 04:18
  • @juanpa.arrivillaga - but not python. As an example, I've written test suites where any test is a single python module that I load and prepopulate with the goodies needed for the test. The goal was to have small fragments of python code focused on a single test. The module encapsulation worked well. – tdelaney Jul 30 '21 at 04:19

2 Answers2

0

It is considered bad practice to alter the global variables (see Why are global variables evil?), but for the sake of knowledge, you can do:

if 'var' not in globals():
     globals()['var'] = var
     var = -1

for what you're trying to do.

Red
  • 26,798
  • 7
  • 36
  • 58
0

The global keyword doesn't unilaterally declare a variable name as a module level variable. It is used within a function to declare that assignments to a variable should be in the module namespace instead of the function instance namespace. The global keyword makes no sense at module level because the module namespace is already the place variable assignments go.

So, just leave the global out.

try:
    var
except NameError:
    var = 1
print(var)

In a function you need the global, but it needs to be before first use.

def foo():
    global var
    try:
        var += 1
    except NameError:
        print("making var")
        var = 1
    return var

print(foo())
print(foo())

Outputs

making var
1
2
tdelaney
  • 73,364
  • 6
  • 83
  • 116