Global Variables in OOP and Python

N

newbie

Hello,

I have questions about global variables in OOP (in general) and Python
(in specific). I understand (I think) that global variables are
generally not a good idea. However, if there are variables that need to
be accessed by a number of classes that exists in separate namespaces
(files), what would be the best way to do this?

So far, I have approached the problem by making the variables
attributes of one class and passing instances of the class as variables
to the other class' methods.

The other way I thought of is to create a separate class that consists
of the variables and to use the

from <file name> import *

in all of the files (namespaces) where it is needed.

Is there a better way?

Are the two ideas presented above acceptable? If so, is one better than
the other from an OOP POV?
 
S

Steven D'Aprano

Hello,

I have questions about global variables in OOP (in general) and Python
(in specific). I understand (I think) that global variables are
generally not a good idea. However, if there are variables that need to
be accessed by a number of classes that exists in separate namespaces
(files), what would be the best way to do this?

So far, I have approached the problem by making the variables
attributes of one class and passing instances of the class as variables
to the other class' methods.


Do you mean something like this?

# Module care_and_feeding

import birds
import foods

def feed_my_pet():
pet = birds.Parrot("Norwegian Blue")
snack = foods.Spam("A tasty meat-like treat")
pet.eats(snack)
return "Yummy!"


That is a good way of handling the problem.


The other way I thought of is to create a separate class that consists
of the variables and to use the

from <file name> import *

in all of the files (namespaces) where it is needed.

That's a bad way of handling it. It has all the worst aspects of using
global variables, plus the worst aspects of import * (namespace pollution
and shadowing of existing names).

Unless I'm badly mistaken, Guido has decided that "from module import *"
was a mistake, and that will be removed from the (legendary) Python 3, if
and when it gets created. In the meantime, it is highly recommended that
you don't use that form.

Is there a better way?

Are the two ideas presented above acceptable? If so, is one better than
the other from an OOP POV?


I think the first way is fine, but of course the Devil is in the details:
I can't judge your code without seeing it.
 
M

Mike Meyer

newbie said:
So far, I have approached the problem by making the variables
attributes of one class and passing instances of the class as variables
to the other class' methods.

That's the standard way to do it in OO languages.
The other way I thought of is to create a separate class that consists
of the variables and to use the

from <file name> import *

in all of the files (namespaces) where it is needed.

Except for one detail, this is a Pythonesque method. The detail is
that "from <module> import *" is generally considered a bad
idea. There are two reasons for this:

1) Blindly adding everything in a module to your namespace is liable
to cause collisions. If the module you're doing this to is stable,
this isn't much of a problem.

2) It makes finding where a variable came from harder. Having to
search extra modules for globals is a pain. If the exported names have
a prefix on them to identify the module, that goes away. But in that
case, you might as well do "import <module> as <prefix>", and leave
the prefix off the variable names in the module.

A better way to do this is to give your module a name that denotes
it's function ("config", for instances, or maybe even "globals") and
use that.
Are the two ideas presented above acceptable? If so, is one better than
the other from an OOP POV?

With the one change, they are. From an OO point of view, they're
almost identical. In Python, a module is an object, so the difference
is whether you want to instantiate a custom class to hold your
globals, or use the builtin module type for that purpose.

<mike
 
G

Gary Herron

newbie said:
Hello,

I have questions about global variables in OOP (in general) and Python
(in specific). I understand (I think) that global variables are
generally not a good idea. However, if there are variables that need to
be accessed by a number of classes that exists in separate namespaces
(files), what would be the best way to do this?

So far, I have approached the problem by making the variables
attributes of one class and passing instances of the class as variables
to the other class' methods.

The other way I thought of is to create a separate class that consists
of the variables and to use the

from <file name> import *
That form is deprecated. Better (and certainly clearer to any reader of
the code) is to leave them in the module.

Define a module, say Parameters, that defines any number of variables
containing useful values. Then
import Parameters
wherever you want and refer to
Parameters.a
and
Parameters.b

You can even add runtime parameters (say options and paths from the
command line) to the module during your initialization code, and those
will be available wherever Parameters is imported:
Parameters.xyzzy = 'whatever'
Parameters.startDirectory = os.getcwd() # Get working directory at startup
(Even if the import of Parameters in some file occurs before the
initialization code has a chance to run.)

Gary Herron
 
B

Brian van den Broek

Gary Herron said unto the world upon 30/12/05 08:03 PM:
newbie wrote:





That form is deprecated. Better (and certainly clearer to any reader of
the code) is to leave them in the module.

Define a module, say Parameters, that defines any number of variables
containing useful values. Then
import Parameters
wherever you want and refer to
Parameters.a
and
Parameters.b

<snip>

An other variant seems rarely to come up.

import Parameters as P

provides almost all the brevity of the * variant and none of the dangers.

Best to all,

Brian vdB
 
S

Steven D'Aprano

Except for one detail, this is a Pythonesque method. The detail is
that "from <module> import *" is generally considered a bad
idea. There are two reasons for this:

Agree about from module import * being bad, but it is still generally poor
practice for the same reason using global variables is generally poor
practice.

1) Blindly adding everything in a module to your namespace is liable
to cause collisions. If the module you're doing this to is stable,
this isn't much of a problem.

How does stability come in to it? If I have a module spam with an object
parrot, and it imports another module with an object parrot, there will be
a namespace collision regardless of whether the two modules are 0.1 alpha
versions or 3.2 stable versions. If the collision is subtle enough, the
bug might take years to discover.

If you mean that namespace collisions are less likely to have remained
undetected by the time the modules reach stability, then I will cautiously
agree with you. But if you mean what you say, that collisions are not a
problem for stable modules, then I disagree strongly.


2) It makes finding where a variable came from harder. Having to
search extra modules for globals is a pain. If the exported names have
a prefix on them to identify the module, that goes away. But in that
case, you might as well do "import <module> as <prefix>", and leave
the prefix off the variable names in the module.
Agreed.


A better way to do this is to give your module a name that denotes
it's function ("config", for instances, or maybe even "globals") and
use that.

And an even better way is to use the absolute minimum number of global
variables possible. In general, that means global functions and classes
Good, global instances and other data Bad.

In other words, any time you feel the need to put "global name" in a
function or method, think twice, have a cold shower, do fifty push-ups,
and then re-write the function to not use globals. 99 times out of a 100,
you'll end up with better code.
 
D

Dennis Lee Bieber

Do you mean something like this?

# Module care_and_feeding

import birds
import foods

def feed_my_pet():
pet = birds.Parrot("Norwegian Blue")
snack = foods.Spam("A tasty meat-like treat")
pet.eats(snack)
return "Yummy!"


That is a good way of handling the problem.
Except for the minor facet that you are buying a new parrot each
 
S

Steven D'Aprano

Except for the minor facet that you are buying a new parrot each
time, and the bird dies after going "Yummy!" <G>

It's a Norwegian Blue with beautiful plumage. It's not dead, it's just
pining for the fjords.
 
K

Kay Schluehr

Steven said:
Agree about from module import * being bad, but it is still generally poor
practice for the same reason using global variables is generally poor
practice.

No, I don't think so. The general wisdom is that global variables are
bad not because they are global, but because they are variable.
Responsibility about state mutation is scattered across the code and
spaghetti is the likely consequence. This cannot be prevented by
changing the access protocoll ( getters / setters ) or using static
variables. Mutable OO-singletons are not less harmfull than good old
globals.

Namespace pollution or name clashes are another issue and we have to
make a tradeoff between easeness of following references and namespace
security on the one hand conciseness on the other. I'm not completely
unhappy using "True" instead of "__builtins__.True" allthough the
latter would be more pure.
 
S

Steven D'Aprano

No, I don't think so. The general wisdom is that global variables are
bad not because they are global, but because they are variable.
Responsibility about state mutation is scattered across the code and
spaghetti is the likely consequence. This cannot be prevented by
changing the access protocoll ( getters / setters ) or using static
variables. Mutable OO-singletons are not less harmfull than good old
globals.

Now that you mention it, how obvious it is. That is good thinking,
thanks.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top