Help on object scope?

H

hg

Hello everybody,

I have a (hopefully) simple question about scoping in python. I have a
program written as a package, with two files of interest. The two
files are /p.py and /lib/q.py

My file p.py looks like this:

---

from lib import q

def main():
global r
r = q.object1()
s = q.object2()

if __name__ == "__main__":
main()

---

My file q.py in the subdirectory lib looks like this:

class object1:
t = 3

class object2:
print r.t

---

Python gives me an error, saying it can't recognize global name r.
However I define r as global in the top-level main definition! Can
anyone suggest how I can get around this, if I want to define and bind
global names inside of main() which are valid in all sub-modules?

Thanks very much for your help!

Might be wrong, but globals can only be global to the module they're
declared in.

I suggest you find another way such as passing your object as a parameter

hg
 
B

bmaron2

Hello everybody,

I have a (hopefully) simple question about scoping in python. I have a
program written as a package, with two files of interest. The two
files are /p.py and /lib/q.py

My file p.py looks like this:

---

from lib import q

def main():
global r
r = q.object1()
s = q.object2()

if __name__ == "__main__":
main()

---

My file q.py in the subdirectory lib looks like this:

class object1:
t = 3

class object2:
print r.t

---

Python gives me an error, saying it can't recognize global name r.
However I define r as global in the top-level main definition! Can
anyone suggest how I can get around this, if I want to define and bind
global names inside of main() which are valid in all sub-modules?

Thanks very much for your help!
 
B

bmaron2

Might be wrong, but globals can only be global to the module they're
declared in.

I suggest you find another way such as passing your object as a parameter

hg

Dear hg,

Thank you for the advice, but that seems a bit unwieldy. My code will
have about 10 of these global objects, all of which interact with
eachother. It seems silly to have to pass 10 parameters around to each
instance I work with. I hope there is a smarter way to do it, or
perhaps someone can suggest a smarter way to code it.

Am I stuck with just having to put all the code in one file? That is
what I wanted to avoid, because the file will get incredibly long. It
seems like the only reason my code above failed is because there were
two separate modules. Perhaps I just need to import /lib/q.py in a
different way?

Many thanks.
 
D

Diez B. Roggisch

Thank you for the advice, but that seems a bit unwieldy. My code will
have about 10 of these global objects, all of which interact with
eachother. It seems silly to have to pass 10 parameters around to each
instance I work with. I hope there is a smarter way to do it, or
perhaps someone can suggest a smarter way to code it.

Am I stuck with just having to put all the code in one file? That is
what I wanted to avoid, because the file will get incredibly long. It
seems like the only reason my code above failed is because there were
two separate modules. Perhaps I just need to import /lib/q.py in a
different way?

You can interact just fine, just qualify the objects with the module
names. So in q, you need to use p.r instead of just r.

It's another question if this design is really good - relying on so many
globals. It would certainly be better to have e.g. a class that looks
like this:


import p
import q
class GlueThingy(object):
def __init__(self):
self.p1 = p.SomeObject(self)
self.q1 = q.SomeOtherObject(self)


Then in SomeObject you can use the passed GlueThingy reference to access
other instances:

class SomeObject(object):

def __init__(self, glue):
self.glue = glue

def do_something(self):
self.glue.q1.foobar()


Diez
 
B

Ben Finney

My code will have about 10 of these global objects, all of which
interact with eachother. It seems silly to have to pass 10
parameters around to each instance I work with.

Yes. A better solution would be to put them inside a module, and
import that module. Then the objects are available at any level as
attributes of the imported module.

===== foo.py =====
def spam():
return max(eggs, ham)

eggs = 17
ham = 12
=====

===== bar.py =====
import foo

def main():
spork = do_something_with(foo.eggs)
foo.spam(spork)
=====
 
D

Dennis Lee Bieber

Hello everybody,

I have a (hopefully) simple question about scoping in python. I have a
program written as a package, with two files of interest. The two
files are /p.py and /lib/q.py

My file p.py looks like this:

---

from lib import q

def main():
global r

This statement only means that all assignments/binding to the name
"r" take place at the level of the "p" file.
r = q.object1()
s = q.object2()
Whereas, "s" here is strictly local to the scope of "main" (and not
to the file "p")
My file q.py in the subdirectory lib looks like this:

class object1:
t = 3

class object2:
print r.t

There is no "r" object in the scope of file "q". Furthermore, your
object2 class can only access a single instance of "r" regardless of how
many object1 class instances are created...

r1 = q.object1()
r2 = q.object1()

These will never be seen by any instance of object2. If object2
instances really need a particular object1 instance, they should create
that instance internally, or accept it as part of the initialization
call...

s = q.object2(r)
Python gives me an error, saying it can't recognize global name r.
However I define r as global in the top-level main definition! Can
anyone suggest how I can get around this, if I want to define and bind
global names inside of main() which are valid in all sub-modules?
The common method is to put ALL "globals" into a module (file) of
their own, import that module into all other modules (files) that need
the objects, and reference the objects using fully qualified (that is,
do NOT use "from module import ...", only use "import module") name.

The above:

common.py
-=-=-=-=-=-=-
r = None #just a placeholder

p.py
-=-=-=-=-=-
import common
import q

common.r = q.object1()


q.py
-=-=-=-=-=-
import common

....
print common.r.t


Also, your example Classes don't show any code for use of class
instances. No "self...." for instance data. Is that a result of
simplifying for this query, or is that your actual understanding of how
to write classes?
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
H

Hendrik van Rooyen

Make a third file for all the system wide globals, say param.py:

global r
r = 42

from param import *

from param import *
Might be wrong, but globals can only be global to the module they're
declared in.
Correct.


I suggest you find another way such as passing your object as a parameter

or make the third file and import it everywhere you need them...

- Hendrik
 
D

Duncan Booth

Diez B. Roggisch said:
You can interact just fine, just qualify the objects with the module
names. So in q, you need to use p.r instead of just r.

No. When p.py is being run as a script, the module you need to access is
__main__.

Much better to put the globals into a separate module created specifically
to hold the global variables rather than having them in something which
might or might not be the main script.
 
B

bmaron2

"from <> import *" (or any "from <> import ..." variant) is NOT the
best thing to use.

Any rebinding to an imported name breaks the linkage to the import
module.

--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/

Thank you all for the advice.

The suggestion Dennis made about using a 3rd, "common" module to hold
global names seemed to be the best idea. The only problem is now I
have to type common.r.t instead of just r.t. If I put common in the /
lib directory, it is even worse and I have to type lib.common.r.t. I
like that it is explicit and perhaps this is the Python way, but it is
annoying and produces ugly code to see all those fully-qualified names
when all I'd really like to use is r.t throughout the program.

Is there a way to import lib.common but then re-bind its attributes to
the local space without breaking the linkage?
 
J

Jussi Salmela

(e-mail address removed) kirjoitti:
global names seemed to be the best idea. The only problem is now I
have to type common.r.t instead of just r.t. If I put common in the /
lib directory, it is even worse and I have to type lib.common.r.t. I
like that it is explicit and perhaps this is the Python way, but it is
annoying and produces ugly code to see all those fully-qualified names
when all I'd really like to use is r.t throughout the program.

Is there a way to import lib.common but then re-bind its attributes to
the local space without breaking the linkage?

See section "6.12 The import statement" in the "Python Reference
Manual". (Hint the part "as name" is what you want)

HTH,
Jussi
 
B

Bart Ogryczak

Hello everybody,

I have a (hopefully) simple question about scoping in python. I have a
program written as a package, with two files of interest. The two
files are /p.py and /lib/q.py

My file p.py looks like this:

---

from lib import q

def main():
global r
r = q.object1()
s = q.object2()

if __name__ == "__main__":
main()

---

My file q.py in the subdirectory lib looks like this:

class object1:
t = 3

class object2:
print r.t

"Globals" are only global within the module they are defined in.
Change "global r" to "import __main__; __main__.r = r", and in q.py
add "from __main__ import r".
 
D

Dennis Lee Bieber

Is there a way to import lib.common but then re-bind its attributes to
the local space without breaking the linkage?
By definition, re-binding means breaking the existing linkage.

Qualified names

x.y

whether module or class instance, and

x[y]

for lists, tuples (though those are read-only), and dictionaries, both
do similar actions. The name "x" is defining a container, and "y"
specifies the component within the container to be manipulated. This is
why a "common" module works -- all accesses specify a component within
the same container. Rebinding components still leaves the binding within
the container. "from <> import ...", however, binds a local name to the
component, and any rebinding disconnects from the component.

However, if you must shorten the name, you could try the

import long.module.path as lmp

format (which, in effect, is binding a new name to the module itself),
then you qualify with

lmp.component

instead of

long.module.path.component

--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 

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

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,120
Latest member
ShelaWalli
Top