1

I have a class which is instantiated many times. It requires a certain parameter from a configuration file. I thought of reading the config file once in the module level so that each instance can refer to the loaded parameter.

I'm probably missing something as I'm receiving:
UnboundLocalError: local variable 'the_parameter' referenced before assignment

Here's the outline of the code:

import ConfigParser

config = ConfigParser.ConfigParser()
config.read('config.cfg')
the_parameter = config.getint('my_section','the_parameter')

class MyClass():
    def my_func(self):
        print(the_parameter)
Jonathan Livni
  • 101,334
  • 104
  • 266
  • 359
  • @S.Lott - I added the missing "self" - thanks – Jonathan Livni Jul 12 '11 at 12:07
  • `class MyClass():` doesn't look right. Why do this? In Python 2, use `class MyClass(object):`. In Python 3 use `class MyClass:` – S.Lott Jul 12 '11 at 12:09
  • The parentheses in the class definition isn't necessary unless you're inheriting from another class, ie. `class MyClass(object): ...`. `class MyClass: ...` is acceptable. – Manny D Jul 12 '11 at 12:10
  • 1
    I've realized I was trying to modify the global variable - I think the following question covers this. I'm voting to delete my question http://stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-the-one-that-created-them – Jonathan Livni Jul 12 '11 at 12:12
  • Turns our I can't vote to delete it as it has answers - I flagged it – Jonathan Livni Jul 12 '11 at 12:13

5 Answers5

4

Works for me

>>> class MyClass( object ):
...     def aFunc( self ):
...         print( some_global )
... 
>>> some_global= 3
>>> x= MyClass()
>>> x.aFunc()
3

The code that's posted has probably had too many details removed to show the real error.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • I just had a similar issue that was caused by the module variable name having a double underscore, as described at https://stackoverflow.com/q/21236818/1671320 -- changing the variable to a single underscore name fixed it. – foz May 23 '18 at 08:37
3

Don't try to use global variables in your classes, this is somewhat against the purpose of classes. If your class requires a config object, you could pass it via dependency injection, i.e. explicitely pass it as an argument to your class:

config = ConfigParser.ConfigParser()
config.read('config.cfg')

class MyClass(object):
    def __init__(self, config):
        self._config = config

    def my_func(self):
        print self._config.getint('my_section', 'the_parameter')

Btw if you really only need the single parameter, you can of course pass the parameter instead of the whole config object. If you might need other parameters in the future, passing the config object would be the better choice.

jena
  • 8,096
  • 1
  • 24
  • 23
  • It is far best than using a useless ``global`` statement, but your code has only half of the interest it could have IMO. However, I upvote for the comment on the purpose of classes – eyquem Aug 26 '11 at 10:22
1

S.Lott is right: the OP's code works.
It works either with the_parameter defined before the class's definition or after, it doesn't matter.

What happens is that when the function my_func is called as a method of one of the instances, the object the_parameter is searched in the environment of the my_func's code block, that is to say: first in the local scope of the function, then outside the function, until the global namespace (= module level), because "When a name is used in a code block, it is resolved using the nearest enclosing scope." (ref)

So there's no need to find a solution to a problem that doesn't exist.

.

However, this code can be improved IMO, because, as it is, it implies that the_parameter must be found among all the objects binded at the global level, and these objects are possibly very numerous.
Defining global the_parameter inside the function's code shortens the process of research: the execution will go directly at the global level to search the object, without exploring the function's namespace.

But anyway, in these two cases, it is a poor process, contrary to the the purpose of classses, as underlined by jena : an instance must be a self-sufficient object having fields that provide all that is necessary to its functionning.

.

The solution of jena isn't the best yet, because it implies that the_parameter must be passed as argument each time an instance will be created.
If the_parameter is intended to be invariably common to all the instances of MyClass, the code should make it a more strictly associated object to all the instances of MyClass.

So it seems to me that the following code is the more convenient:

class MyClass(object):
    import ConfigParser
    config = ConfigParser.ConfigParser()
    config.read('config.cfg')
    the_parameter = config.getint('my_section','the_parameter')
    del ConfigParser,config  

    def my_func(self):
        print('the_parameter == ' + str(MyClass.the_parameter)) 

Doing so, the search of the_parameter will be done by exploring the namespace of the class, not in the vast global namespace.

.

Update

Well, I realize that to find MyClass.the_parameter , the execution must first search the object MyClass in the global namespace, and that anihilates what I pretended.

To avoid the search in the global namespace, the call to the _class_ attribute of the instance must be done like that:

def my_func(self):
    print('the_parameter == ' + str(self.__class__.the_parameter)) 
eyquem
  • 26,771
  • 7
  • 38
  • 46
0

If you don't declare var as global and don't initialize it, accessing value of non-defined variable is error

so

global the_parameter = config.getint(...)

is the answer

Samuele Mattiuzzo
  • 10,760
  • 5
  • 39
  • 63
  • that doesn't work for me and also http://stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-the-one-that-created-them – Jonathan Livni Jul 12 '11 at 12:09
0

Put global the_parameter in the function to fix the issue.

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • I'm kind of shocked that such an answer has been upvoted and accepted. Sometimes, there are codes on SO that are reproached because of minor points that don't respect PEP8, but I find the erroneous content of this answer more serious. Otherwise I understand nothing to OOP and Python – eyquem Aug 26 '11 at 10:15