Re: Messing up with classes and their namespace

2009-06-06 Thread Dave Angel

Jean-Michel Pichavant wrote:
Scott 
David Daniels wrote:

Jean-Michel Pichavant wrote:

Hello world,

I had recently a very nasty bug in my python application. The 
context is quite complex, but in the end the problem can be resume 
as follow:


2 files in the same directory :

lib.py:
 >import foo
 >foo.Foo.BOOM='lib'

foo.py:
 >class Foo:
 >BOOM = 'F'
 >
 >if __name__=='__main__':
 >import lib # I'm expecting BOOM to be set to 'lib'
 >print Foo.BOOM

I was expecting 'lib' as output, but I got 'Fooo'. I don't really 
understand what python mechanism I'm messing with but I have the 
feeling I've misunderstood a very basic concept about class, 
namespace or whatever import notion.




I guess there is 2 different objects for the same class Foo. How I 
do I make both Foo objects the same object ?


OK, here is one solution (from which you may infer the problem):

lib.py:
import __main__
__main__.Foo.BOOM = 'lib'

foo.py:
class Foo:
BOOM = 'F'

if __name__ == '__main__':
import lib # I'm expecting BOOM to be set to 'lib'
print(Foo.BOOM)

Here is another solution:

lib.py:
import foo
foo.Foo.BOOM = 'lib'

foo.py:
class Foo:
BOOM = 'F'

if __name__ == '__main__':
import sys
sys.modules['foo'] = sys.modules['__main__']
import lib # I'm expecting BOOM to be set to 'lib'
print(Foo.BOOM)

Here is a demo of what is actually going wrong:

foo.py:
class Foo:
inside = __name__

import foo

if __name__ == '__main__':
print(Foo is foo.Foo)
print(Foo.inside, foo.Foo.inside)

And here is a fix
foo.py:
if __name__ == '__main__':
import sys
sys.modules['foo'] = sys.modules['__main__']

class Foo:
inside = __name__

import foo

if __name__ == '__main__':
print(Foo is foo.Foo)
print(Foo.inside, foo.Foo.inside)


--Scott David Daniels
scott.dani...@acm.org


Thanks for the explanation. I'll have to give it a second thought, I'm 
still missing something but I'll figure it out.


Jean-Michel



In general, two or more modules with mutual imports can cause problems.  
If  modulea.py imports moduleb, and moduleb.py imports modulea, you can 
end up with difficulties.


But even more gross difficulties come from importing the module that 
started the execution, as it's got another name, "__main__"   If you 
import it again with its traditional name, these two do not get 
combined, and you end up with multiple instances of things you thought 
were safe.


Scott has given you a solution for the second problem.  But the first 
problem is more general, and should perhaps be the one you try first.


The simplest answer in many cases is to factor the script into two 
separate files.  One will have "library" functions and classes, like the 
Foo in your example.  And the other will have the logic for parsing 
command line arguments and suchlike.


The general problem isn't unique to Python.  You can also end up with 
problems in C, where one header includes a second one, which re-includes 
the first.  The workarounds for it are well known, but most of them also 
contain subtle difficulties.


If it's possible, factor out mutual dependencies into a separate module.

--
http://mail.python.org/mailman/listinfo/python-list


Re: Messing up with classes and their namespace

2009-06-05 Thread Terry Reedy

Jean-Michel Pichavant wrote:

Thanks for the explanation. I'll have to give it a second thought, I'm 
still missing something but I'll figure it out.


Perhaps it is this:
1. When you run foo.py as a script, the interpreter creates module 
'__main__' by executing the code in foo.py.
2. When that code does 'import lib', the interpreter looks for an 
existing module named 'lib', does not find it, and creates module 'lib' 
by executing the code in lib.py.
3. When that code does 'import foo', the interpreter looks for an 
existing module named 'foo', does not find it, and creates module 'foo' 
by executing (again) the code in foo.py.


Module 'foo' is slightly different from module '__main__', created from 
the same code, because of the section conditioned by 'if __name__ == 
'__main__', that being the purpose of that incantation.  But each of the 
two modules have their own class Foo.  You sort of guessed this ...


> I guess there is 2 different objects for the same class Foo.

They are the same in content, but not in identify, until you change one 
of then.


> How I do I make both Foo objects the same object ?

As Scott hinted, by not making two of them, and you do that by not 
making two modules from the same file.


Terry Jan Reedy

--
http://mail.python.org/mailman/listinfo/python-list


Re: Messing up with classes and their namespace

2009-06-05 Thread Jean-Michel Pichavant

Scott David Daniels wrote:

Jean-Michel Pichavant wrote:

Hello world,

I had recently a very nasty bug in my python application. The context 
is quite complex, but in the end the problem can be resume as follow:


2 files in the same directory :

lib.py:
 >import foo
 >foo.Foo.BOOM='lib'

foo.py:
 >class Foo:
 >BOOM = 'F'
 >
 >if __name__=='__main__':
 >import lib # I'm expecting BOOM to be set to 'lib'
 >print Foo.BOOM

I was expecting 'lib' as output, but I got 'Fooo'. I don't really 
understand what python mechanism I'm messing with but I have the 
feeling I've misunderstood a very basic concept about class, 
namespace or whatever import notion.




I guess there is 2 different objects for the same class Foo. How I do 
I make both Foo objects the same object ?


OK, here is one solution (from which you may infer the problem):

lib.py:
import __main__
__main__.Foo.BOOM = 'lib'

foo.py:
class Foo:
BOOM = 'F'

if __name__ == '__main__':
import lib # I'm expecting BOOM to be set to 'lib'
print(Foo.BOOM)

Here is another solution:

lib.py:
import foo
foo.Foo.BOOM = 'lib'

foo.py:
class Foo:
BOOM = 'F'

if __name__ == '__main__':
import sys
sys.modules['foo'] = sys.modules['__main__']
import lib # I'm expecting BOOM to be set to 'lib'
print(Foo.BOOM)

Here is a demo of what is actually going wrong:

foo.py:
class Foo:
inside = __name__

import foo

if __name__ == '__main__':
print(Foo is foo.Foo)
print(Foo.inside, foo.Foo.inside)

And here is a fix
foo.py:
if __name__ == '__main__':
import sys
sys.modules['foo'] = sys.modules['__main__']

class Foo:
inside = __name__

import foo

if __name__ == '__main__':
print(Foo is foo.Foo)
print(Foo.inside, foo.Foo.inside)


--Scott David Daniels
scott.dani...@acm.org


Thanks for the explanation. I'll have to give it a second thought, I'm 
still missing something but I'll figure it out.


Jean-Michel
--
http://mail.python.org/mailman/listinfo/python-list


Re: Messing up with classes and their namespace

2009-06-05 Thread Scott David Daniels

Jean-Michel Pichavant wrote:

Hello world,

I had recently a very nasty bug in my python application. The context is 
quite complex, but in the end the problem can be resume as follow:


2 files in the same directory :

lib.py:
 >import foo
 >foo.Foo.BOOM='lib'

foo.py:
 >class Foo:
 >BOOM = 'F'
 >
 >if __name__=='__main__':
 >import lib # I'm expecting BOOM to be set to 'lib'
 >print Foo.BOOM

I was expecting 'lib' as output, but I got 'Fooo'. I don't really 
understand what python mechanism I'm messing with but I have the feeling 
I've misunderstood a very basic concept about class, namespace or 
whatever import notion.




I guess there is 2 different objects for the same class Foo. How I do I 
make both Foo objects the same object ?


OK, here is one solution (from which you may infer the problem):

lib.py:
import __main__
__main__.Foo.BOOM = 'lib'

foo.py:
class Foo:
BOOM = 'F'

if __name__ == '__main__':
import lib # I'm expecting BOOM to be set to 'lib'
print(Foo.BOOM)

Here is another solution:

lib.py:
import foo
foo.Foo.BOOM = 'lib'

foo.py:
class Foo:
BOOM = 'F'

if __name__ == '__main__':
import sys
sys.modules['foo'] = sys.modules['__main__']
import lib # I'm expecting BOOM to be set to 'lib'
print(Foo.BOOM)

Here is a demo of what is actually going wrong:

foo.py:
class Foo:
inside = __name__

import foo

if __name__ == '__main__':
print(Foo is foo.Foo)
print(Foo.inside, foo.Foo.inside)

And here is a fix
foo.py:
if __name__ == '__main__':
import sys
sys.modules['foo'] = sys.modules['__main__']

class Foo:
inside = __name__

import foo

if __name__ == '__main__':
print(Foo is foo.Foo)
print(Foo.inside, foo.Foo.inside)


--Scott David Daniels
scott.dani...@acm.org
--
http://mail.python.org/mailman/listinfo/python-list