Re: [Python-checkins] CVS: python/dist/src/Misc NEWS,1.108,1.109
On Mon, Jan 29, 2001 at 05:27:30PM -0800, Jeremy Hylton wrote:
add note about two kinds of illegal imports that are now checked
+ - The compiler will report a SyntaxError if "from ... import *" occurs + in a function or class scope or if a name bound by the import + statement is declared global in the same scope. The language + reference has also documented that these cases are illegal, but + they were not enforced.
Woah. Is this really a good idea ? I have seen 'from ... import *' in a function scope put to good (relatively -- we're talking 'import *' here) use. I also thought of 'import' as yet another assignment statement, so to me it's both logical and consistent if 'import' would listen to 'global'. Otherwise we have to re-invent 'import spam; eggs = spam' if we want eggs to be global. Is there really a reason to enforce this, or are we enforcing the wording of the language reference for the sake of enforcing the wording of the language reference ? When writing 'import as' for 2.0, I fixed some of the inconsistencies in import, making it adhere to 'global' statements in as many cases as possible (all except 'from ... import *') but I was apparently not aware of the wording of the language reference. I'd suggest updating the wording in the language reference, not the implementation, unless there is a good reason to disallow this. I also have another issue with your recent patches, Jeremy, also in the backwards-compatibility departement :) You gave new.code two new, non-optional arguments, in the middle of the long argument list. I sent a note about it to python-checkins instead of python-dev by accident, but Fred seemed to agree with me there. -- Thomas Wouters <thomas@xs4all.net> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
On Mon, Jan 29, 2001 at 05:27:30PM -0800, Jeremy Hylton wrote:
add note about two kinds of illegal imports that are now checked
+ - The compiler will report a SyntaxError if "from ... import *" occurs + in a function or class scope or if a name bound by the import + statement is declared global in the same scope. The language + reference has also documented that these cases are illegal, but + they were not enforced.
Woah. Is this really a good idea ? I have seen 'from ... import *' in a function scope put to good (relatively -- we're talking 'import *' here) use. I also thought of 'import' as yet another assignment statement, so to me it's both logical and consistent if 'import' would listen to 'global'. Otherwise we have to re-invent 'import spam; eggs = spam' if we want eggs to be global.
Note that Jeremy is only raising errors for "from M import *".
Is there really a reason to enforce this, or are we enforcing the wording of the language reference for the sake of enforcing the wording of the language reference ? When writing 'import as' for 2.0, I fixed some of the inconsistencies in import, making it adhere to 'global' statements in as many cases as possible (all except 'from ... import *') but I was apparently not aware of the wording of the language reference. I'd suggest updating the wording in the language reference, not the implementation, unless there is a good reason to disallow this.
I think Jeremy has an excellent reason. Compilers want to do analysis of name usage at compile time. The value of * cannot be determined at compile time (you cannot know what module will actually be imported at run time). Up till now, we were able to fudge this, but Jeremy's new compiler needs to know exactly which names are defined in all local scopes, in order to do nested scopes right.
I also have another issue with your recent patches, Jeremy, also in the backwards-compatibility departement :) You gave new.code two new, non-optional arguments, in the middle of the long argument list. I sent a note about it to python-checkins instead of python-dev by accident, but Fred seemed to agree with me there.
(Tim will love this. :-) I don't know what those new arguments represent. If they can reasonably be assumed to be empty for code that doesn't use the new features, I'd say move them to the end and default them properly. If they must be specified, I'd say too bad, the new module is an accident of the implementation anyway, and its users should update their code. --Guido van Rossum (home page: http://www.python.org/~guido/)
On Tue, Jan 30, 2001 at 10:06:57AM -0500, Guido van Rossum wrote:
On Mon, Jan 29, 2001 at 05:27:30PM -0800, Jeremy Hylton wrote:
add note about two kinds of illegal imports that are now checked
+ - The compiler will report a SyntaxError if "from ... import *" occurs + in a function or class scope or if a name bound by the import + statement is declared global in the same scope. The language + reference has also documented that these cases are illegal, but + they were not enforced.
Woah. Is this really a good idea ? I have seen 'from ... import *' in a function scope put to good (relatively -- we're talking 'import *' here) use. I also thought of 'import' as yet another assignment statement, so to me it's both logical and consistent if 'import' would listen to 'global'. Otherwise we have to re-invent 'import spam; eggs = spam' if we want eggs to be global.
Note that Jeremy is only raising errors for "from M import *".
No, he says he's also raising errors for 'import spam' if 'spam' is declared global, like so: def viking(): global spam import spam
Is there really a reason to enforce this, or are we enforcing the wording of the language reference for the sake of enforcing the wording of the language reference ? When writing 'import as' for 2.0, I fixed some of the inconsistencies in import, making it adhere to 'global' statements in as many cases as possible (all except 'from ... import *') but I was apparently not aware of the wording of the language reference. I'd suggest updating the wording in the language reference, not the implementation, unless there is a good reason to disallow this.
I think Jeremy has an excellent reason. Compilers want to do analysis of name usage at compile time. The value of * cannot be determined at compile time (you cannot know what module will actually be imported at run time). Up till now, we were able to fudge this, but Jeremy's new compiler needs to know exactly which names are defined in all local scopes, in order to do nested scopes right.
Hrrmm.... I guess I have to agree with that. None the less, I wish we could have a "ack! this is stupid code! it uses 'from larch import *'! All bets are off, we do a lot of slow complicated runtime checking now!" mode. The thing I still enjoy most about Python is that it always does what I want, and though I'd never want to do 'from different import *' in a local scope, I do want other, less wise people to have the same experience, where possible :) And I also want to be able to do: def fill_me(with): global me if with == 1: import me elif with == 2: import me_too as me elif with == 3: from me.Tools import me_me as me elif with == 4: me = FakeModule() sys.modules['me'] = me else: raise ValueError And I can't quite argue that away with 'the compiler needs to know ...' -- it's all there!
I also have another issue with your recent patches, Jeremy, also in the backwards-compatibility departement :) You gave new.code two new, non-optional arguments, in the middle of the long argument list. I sent a note about it to python-checkins instead of python-dev by accident, but Fred seemed to agree with me there.
(Tim will love this. :-)
I don't know what those new arguments represent. If they can reasonably be assumed to be empty for code that doesn't use the new features, I'd say move them to the end and default them properly. If they must be specified, I'd say too bad, the new module is an accident of the implementation anyway, and its users should update their code.
Okay, I can live with that. It's sure to cause some gripes though. Then again, from looking at the code I'd say those arguments (freevars and cellvars) can easily default to empty tuples. -- Thomas Wouters <thomas@xs4all.net> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
Woah. Is this really a good idea ? I have seen 'from ... import *' in a function scope put to good (relatively -- we're talking 'import *' here) use. I also thought of 'import' as yet another assignment statement, so to me it's both logical and consistent if 'import' would listen to 'global'. Otherwise we have to re-invent 'import spam; eggs = spam' if we want eggs to be global.
Note that Jeremy is only raising errors for "from M import *".
No, he says he's also raising errors for 'import spam' if 'spam' is declared global, like so:
def viking(): global spam import spam
Yeah, this was just brought to my attention at our group meeting today. I'm with you on this one -- there really isn't a good reason why this shouldn't work. (I wonder why that constraint was ever added to the reference manual; maybe I was just upset that someone would *do* something as ugly as that, or maybe there was a J[P]ython reason???.)
I think Jeremy has an excellent reason. Compilers want to do analysis of name usage at compile time. The value of * cannot be determined at compile time (you cannot know what module will actually be imported at run time). Up till now, we were able to fudge this, but Jeremy's new compiler needs to know exactly which names are defined in all local scopes, in order to do nested scopes right.
Hrrmm.... I guess I have to agree with that. None the less, I wish we could have a "ack! this is stupid code! it uses 'from larch import *'! All bets are off, we do a lot of slow complicated runtime checking now!" mode. The thing I still enjoy most about Python is that it always does what I want, and though I'd never want to do 'from different import *' in a local scope, I do want other, less wise people to have the same experience, where possible :)
Hm, maybe, just *maybe* Jeremy can do this if there are no nested scopes in sight. But I don't think it's a big deal as long as the error message is clear -- it's bad style.
And I also want to be able to do:
def fill_me(with): global me if with == 1: import me elif with == 2: import me_too as me elif with == 3: from me.Tools import me_me as me elif with == 4: me = FakeModule() sys.modules['me'] = me else: raise ValueError
And I can't quite argue that away with 'the compiler needs to know ...' -- it's all there!
Sort of, although I would prefer to do a two-stager here: first some variation of "import me as meohmy", and then "global me; me = meohmy" .
I also have another issue with your recent patches, Jeremy, also in the backwards-compatibility departement :) You gave new.code two new, non-optional arguments, in the middle of the long argument list. I sent a note about it to python-checkins instead of python-dev by accident, but Fred seemed to agree with me there.
(Tim will love this. :-)
I don't know what those new arguments represent. If they can reasonably be assumed to be empty for code that doesn't use the new features, I'd say move them to the end and default them properly. If they must be specified, I'd say too bad, the new module is an accident of the implementation anyway, and its users should update their code.
Okay, I can live with that. It's sure to cause some gripes though. Then again, from looking at the code I'd say those arguments (freevars and cellvars) can easily default to empty tuples.
OK. I hope Jeremy can fix this when he gets home. --Guido van Rossum (home page: http://www.python.org/~guido/)
Note that Jeremy is only raising errors for "from M import *".
No, he says he's also raising errors for 'import spam' if 'spam' is declared global, like so:
def viking(): global spam import spam
Yeah, this was just brought to my attention at our group meeting today. I'm with you on this one -- there really isn't a good reason why this shouldn't work. (I wonder why that constraint was ever added to the reference manual; maybe I was just upset that someone would *do* something as ugly as that, or maybe there was a J[P]ython reason???.)
Previously Jython have had problems with "from .. import *" in function scope, and still have problems when used with the python -> java compiler: http://sourceforge.net/bugs/?func=detailbug&bug_id=122834&group_id=12867 Using global on an import name is currently ignored by Jython because the name assignment is done by the runtime, not the compiler. regards, finn
On Wed, Jan 31, 2001 at 12:49:22PM +0000, Finn Bock wrote:
Using global on an import name is currently ignored by Jython because the name assignment is done by the runtime, not the compiler.
So it's impossible to do, in Jython, something like: def fillme(): global me import me but it is possible to do: def fillme(): global me import me as _me me = _me ? I have to say I don't like that; we're always claiming 'import' (and 'def' and 'class' for that matter) are 'just another way of writing assignment'. All these special cases break that. -- Thomas Wouters <thomas@xs4all.net> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
On Wed, 31 Jan 2001 13:59:14 +0100, you wrote:
On Wed, Jan 31, 2001 at 12:49:22PM +0000, Finn Bock wrote:
Using global on an import name is currently ignored by Jython because the name assignment is done by the runtime, not the compiler.
So it's impossible to do, in Jython, something like:
def fillme(): global me import me
but it is possible to do:
def fillme(): global me import me as _me me = _me
?
Yes, only the second example will make a global variable.
I have to say I don't like that; we're always claiming 'import' (and 'def' and 'class' for that matter) are 'just another way of writing assignment'. All these special cases break that.
I don't like it either, I was only reported what jython currently does. The current design used by Jython does lend itself directly towards a solution, but I don't see anything that makes it impossible to solve. regards, finn
[Finn]
Using global on an import name is currently ignored by Jython because the name assignment is done by the runtime, not the compiler.
[Thomas]
So it's impossible to do, in Jython, something like:
def fillme(): global me import me
but it is possible to do:
def fillme(): global me import me as _me me = _me
?
[Finn again]
Yes, only the second example will make a global variable.
I have to say I don't like that; we're always claiming 'import' (and 'def' and 'class' for that matter) are 'just another way of writing assignment'. All these special cases break that.
I don't like it either, I was only reported what jython currently does. The current design used by Jython does lend itself directly towards a solution, but I don't see anything that makes it impossible to solve.
Tentatively, I'd say that this should be documented as a Jython difference and Jython should strive to fix this. So I see no good reason to rule it out in CPython. That doesn't mean I like Thomas's example! It should probably be redesigned along the lines of def fillme(): import me return me me = fillme() to avoid needing side effects on globals. --Guido van Rossum (home page: http://www.python.org/~guido/)
I'd like to summarize the thread prompted by the compiler changes that implemented long-stated restrictions in the ref manual and ask a related question about backwards compatibility. The two changes were: 1. If a name is declared global in a function scope, it is an error to import with that name as a target. Example: def foo(): global string import string # error 2. It is illegal to use 'from ... import *' in a function. Example: def foo(): from string import * I believe Guido's recommendation about these two rules are: 1. Allow it, even though it dodgy style. A two-stager would be clearer: def foo(): global string import string as string_mod string = string_mod 2. Keep the restriction, because it's really bad style. It can also cause subtle problems with nested scopes. Example: def f(): from string import * def g(): return strip .... It might be reasonable to expect that strip would refer to the binding introduced by "from string import *" but there is no reasonable way to support this. The other issue raised was the two extra arguments to new.code(). I'll move those to the end and make them optional. The related question is whether I should worry about backwards compatibility at the C level. PyFrame_New(), PyFunction_New(), and PyCode_New() all have different signatures. Should I do anything about this? Jeremy
On Wed, Jan 31, 2001 at 07:36:11PM -0500, Jeremy Hylton wrote:
I believe Guido's recommendation about these two rules are: 1. Allow it, even though it dodgy style. A two-stager would be clearer:
def foo(): global string import string as string_mod string = string_mod
I don't think it's dodgy style, and I don't think a two-stager would be clearer, since the docs always claim 'importing is just another assignment statement'. The whole 'import-as' was added to *avoid* these two-stagers! Furthermore, since 'global string;import string' worked correctly at least since Python 1.5 and probably much longer, I suspect it'll break some code and confuse some more programmers out there. To handle this 'portably' (between Python versions, because lets be honest: Python 2.0 is far from common right now, and I can't blame people for not upgrading with the licence issues and all), the programmer would have to do def assign_global_string(name): global string string = name def foo(): import string assign_global_string(name) or even def foo(): def assign_global_string(name): global string string = name import string assign_global_string(name) (Keeping in mind nested scopes, what would *you* expect the last one to do ?) I honestly think def foo(): global string import string is infinitely clearer.
2. Keep the restriction, because it's really bad style. It can also cause subtle problems with nested scopes. Example: def f(): from string import * def g(): return strip .... It might be reasonable to expect that strip would refer to the binding introduced by "from string import *" but there is no reasonable way to support this.
I'm still not entirely comfortable with disallowing this (rewriting code that uses it would be a pain, especially large functions) but I have good hopes that this won't be necessary because nothing large uses this :) Still, it would be nice if the compiler would only barf if someone uses 'from ... import *' in a local scope *and* references unbound names in a nested scope. I can see how that would be a lot of trouble for a little bit of gain, though.
The related question is whether I should worry about backwards compatibility at the C level. PyFrame_New(), PyFunction_New(), and PyCode_New() all have different signatures. Should I do anything about this?
Well, it could be done, maybe renaming the functions and doing something like #ifdef OLD_CODE_CREATION #define PyFrame_New PyFrame_OldNew ... etc, to allow quick porting to Python 2.1. I have never seen C code create code/function/frame objects by itself, though, so I'm not sure if it's worth it. The Python bit is, since it's a lot less trouble to fix it and a lot more common to use the 'new' object. -- Thomas Wouters <thomas@xs4all.net> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
participants (4)
-
bckfnn@worldonline.dk
-
Guido van Rossum
-
Jeremy Hylton
-
Thomas Wouters