Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #96305 > unrolled thread

Re: Python handles globals badly.

Started bytdev@freenet.de
First post2015-09-10 15:25 -0700
Last post2015-09-12 03:27 +0100
Articles 20 on this page of 27 — 10 participants

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Python handles globals badly. tdev@freenet.de - 2015-09-10 15:25 -0700
    Re: Python handles globals badly. Emile van Sebille <emile@fenx.com> - 2015-09-10 15:40 -0700
    Re: Python handles globals badly. Ian Kelly <ian.g.kelly@gmail.com> - 2015-09-10 18:35 -0600
      Re: Python handles globals badly. Marko Rauhamaa <marko@pacujo.net> - 2015-09-11 07:34 +0300
        Re: Python handles globals badly. Chris Angelico <rosuav@gmail.com> - 2015-09-11 14:59 +1000
          Re: Python handles globals badly. Marko Rauhamaa <marko@pacujo.net> - 2015-09-11 08:15 +0300
            Re: Python handles globals badly. Chris Angelico <rosuav@gmail.com> - 2015-09-11 15:25 +1000
            Re: Python handles globals badly. Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-09-12 03:43 +0100
        Re: Python handles globals badly. Ian Kelly <ian.g.kelly@gmail.com> - 2015-09-10 23:07 -0600
          Re: Python handles globals badly. Marko Rauhamaa <marko@pacujo.net> - 2015-09-11 08:27 +0300
        Re: Python handles globals badly. Rustom Mody <rustompmody@gmail.com> - 2015-09-11 00:39 -0700
      Re: Python handles globals badly. Steven D'Aprano <steve@pearwood.info> - 2015-09-11 18:42 +1000
        Re: Python handles globals badly. Chris Angelico <rosuav@gmail.com> - 2015-09-11 19:16 +1000
        Re: Python handles globals badly. Ian Kelly <ian.g.kelly@gmail.com> - 2015-09-11 09:03 -0600
          Re: Python handles globals badly. Steven D'Aprano <steve@pearwood.info> - 2015-09-12 17:00 +1000
        Re: Python handles globals badly. Chris Angelico <rosuav@gmail.com> - 2015-09-12 01:15 +1000
        Re: Python handles globals badly. Ian Kelly <ian.g.kelly@gmail.com> - 2015-09-11 09:27 -0600
        Re: Python handles globals badly. Chris Angelico <rosuav@gmail.com> - 2015-09-12 01:44 +1000
        Re: Python handles globals badly. Ian Kelly <ian.g.kelly@gmail.com> - 2015-09-11 09:49 -0600
        Re: Python handles globals badly. Chris Angelico <rosuav@gmail.com> - 2015-09-12 01:55 +1000
        Re: Python handles globals badly. random832@fastmail.us - 2015-09-11 11:57 -0400
          Re: Python handles globals badly. Rustom Mody <rustompmody@gmail.com> - 2015-09-11 09:08 -0700
        Re: Python handles globals badly. Chris Angelico <rosuav@gmail.com> - 2015-09-12 02:04 +1000
        Re: Python handles globals badly. Ian Kelly <ian.g.kelly@gmail.com> - 2015-09-11 10:27 -0600
        Re: Python handles globals badly. Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-09-12 03:51 +0100
    Re: Python handles globals badly. MRAB <python@mrabarnett.plus.com> - 2015-09-11 02:17 +0100
    Re: Python handles globals badly. Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-09-12 03:27 +0100

Page 1 of 2  [1] 2  Next page →


#96305 — Re: Python handles globals badly.

Fromtdev@freenet.de
Date2015-09-10 15:25 -0700
SubjectRe: Python handles globals badly.
Message-ID<cd7b7ffa-a217-4b62-bad2-9095b33a2bb6@googlegroups.com>
Some notes to the "global"-keyword and the other proposals.

It has been proposed to have these six enhancements

1. optional keyword "global"  
2. switch statement
3. less restrictive indentation 
4. universal scope 
5. goto label
6- "include" script statement


with following proofs uncommented:

Each sample provided would work without global 
(or you get runtime failure while try to write a global). 
So the compiler knows the distiction between global and local already. 
Otherwise you would have to write in every function this keyword 
But this is not the case.  You write it because you need write access.
And this is an over-regulation. So, NO need for an explicit global. 
Optional ok.


Another proof about identation:
The parser can recognise identation with tabs and spaces. 
Otherwise semcicolons or brackets would be needed.
It is correct that there have to be a decision for spaces or tabs.
But sure not necessarily the exact same indentation to the right for each block.
Jus more same inserter to the right and the context is clear.


Another proof is Python itself (from Tutorial):
"Python is an ... powerful programming language. It has ... and a simple but effective approach 
to object-oriented programming. Python's elegant syntax ... together with its interpreted nature, 
make it an ideal language for scripting ... .

The proposals are all made for structual programming enhancements 
This is nothing else than having structural programming, functional programming and OO
and many more features in parallel. Why that all?
For the same reason: 
For an another type of programmers - or say: nothing more than even more flexibility.

Read also here: https://en.wikipedia.org/wiki/History_of_Python
Especially sections: "incfluences from other languages"



But all proposals are more or less fully denied - for more or less no reasons.


The last statement against the proposals:
   
> "EVERYONE who suggests massive, sweeping changes says "hey, if you only
> make these changes, Python will actually become popular". It's almost
> mandatory."


Additionally, that proofs: that this is not a single meaning.
And also speaking from changes is wrong. 
Enhancements or extensions would be correct.



There is the big question:

Who is responding or has responded?  
Extreme Programmers, Python-Hardliner, Python-Evangelists, ... .
Presumably no core Python Programmers (wrting compiler and standard library stuff)

On Google groups you can currently read for this thread:
37 Authors. 152 posts. 443 views.

That is not that much for views (probably mostly from the writer's itself)

So, is this really the place where a PEP can be started?
When has a proposal to be accepted? If ten-thousands say yes?
Which ten-thousands? Who decides it?



Thanks.

[toc] | [next] | [standalone]


#96306

FromEmile van Sebille <emile@fenx.com>
Date2015-09-10 15:40 -0700
Message-ID<mailman.342.1441924847.8327.python-list@python.org>
In reply to#96305
On 9/10/2015 3:25 PM, tdev@freenet.de wrote:

 > Who decides it?

The BDFL or his delegate. It's simplest that way.

Emile

[toc] | [prev] | [next] | [standalone]


#96308

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-09-10 18:35 -0600
Message-ID<mailman.344.1441931751.8327.python-list@python.org>
In reply to#96305
On Thu, Sep 10, 2015 at 4:25 PM,  <tdev@freenet.de> wrote:
> with following proofs uncommented:

None of these are "proofs".

> Each sample provided would work without global
> (or you get runtime failure while try to write a global).

What samples? It would be easier to follow your messages if you would
include quotes from previous messages as context.

> So the compiler knows the distiction between global and local already.

As we've said before, it doesn't. The compiler's current rules are
fairly simple:

1) If it's in the function's argument list, it's an argument (and
therefore local).
2) If it's explicitly declared global, then it's global.
3) If it's never assigned within the function, then it's global.
4) Otherwise, it's local.

If you take out step 2, then the compiler has no way of distinguishing
whether a variable that is assigned to is local or global.

> Another proof about identation:
> The parser can recognise identation with tabs and spaces.

You can use tabs *or* spaces. If you want to mix the two, then there
would need to be some official decision made about how many spaces
compose a tab, and then everybody who wants to use tabs would have to
configure their editors to conform to that decision, or risk breaking
their code. Some people like to indent two spaces. Some people like to
indent four spaces. On the other hand, the de facto standard for
terminal tab width is eight spaces. However, virtually nobody prefers
eight spaces of indentation. So the question is which standard are you
going to adopt, and which groups are you going to upset?

I really doubt that you're going to gain any traction with this one,
because the decision that was made with Python 3 was to make the
compiler *more* rigid about not mixing tabs and spaces, not less.

> It is correct that there have to be a decision for spaces or tabs.
> But sure not necessarily the exact same indentation to the right for each block.
> Jus more same inserter to the right and the context is clear.

I don't understand what you're trying to say here.

> But all proposals are more or less fully denied - for more or less no reasons.

You've been given reasons. You seem unwilling to accept them.

> There is the big question:
>
> Who is responding or has responded?
> Extreme Programmers, Python-Hardliner, Python-Evangelists, ... .
> Presumably no core Python Programmers (wrting compiler and standard library stuff)

Ad hominem.

> On Google groups you can currently read for this thread:
> 37 Authors. 152 posts. 443 views.
>
> That is not that much for views (probably mostly from the writer's itself)

This is not a Google Group. This is the comp.lang.python newsgroup,
which is mirrored bidirectionally to the python.org python-list
mailing list. Google Groups provides another portal to the newsgroup.
There is no way to measure how many users have been reading this
thread in the newsgroup or the mailing list.

> So, is this really the place where a PEP can be started?

No, this list is for general Python discussion. The place to present a
PEP is the python-dev mailing list. It is generally considered
advisable to post the idea to the python-ideas mailing list first, to
find support for the idea and to hone it before going to the trouble
of writing a PEP.

If you do get to the point of writing a PEP, you will also need to
have a clear picture of how you plan to actually implement the idea.
It's not enough to just propose that "the global keyword should be
optional". Precisely how would scopes be determined? How would you
ensure backward compatibility? These are questions that would need
answers before anything could be implemented.

> When has a proposal to be accepted? If ten-thousands say yes?
> Which ten-thousands? Who decides it?

That's up to the BDFL.

[toc] | [prev] | [next] | [standalone]


#96318

FromMarko Rauhamaa <marko@pacujo.net>
Date2015-09-11 07:34 +0300
Message-ID<87h9n1o9q4.fsf@elektro.pacujo.net>
In reply to#96308
Ian Kelly <ian.g.kelly@gmail.com>:

> You can use tabs *or* spaces. If you want to mix the two, then there
> would need to be some official decision made about how many spaces
> compose a tab, and then everybody who wants to use tabs would have to
> configure their editors to conform to that decision, or risk breaking
> their code. Some people like to indent two spaces. Some people like to
> indent four spaces. On the other hand, the de facto standard for
> terminal tab width is eight spaces. However, virtually nobody prefers
> eight spaces of indentation. So the question is which standard are you
> going to adopt, and which groups are you going to upset?

Indentation preferences and the interpretation of TABs are two separate
things.

For example, in the default emacs configuration, the C indentation
levels go like this:

   SPC SPC
   SPC SPC SPC SPC
   SPC SPC SPC SPC SPC SPC
   TAB
   TAB SPC SPC

etc. The TAB *key* is a command that makes emacs indent with a mix of
spaces and TABs.


Marko

[toc] | [prev] | [next] | [standalone]


#96319

FromChris Angelico <rosuav@gmail.com>
Date2015-09-11 14:59 +1000
Message-ID<mailman.353.1441947579.8327.python-list@python.org>
In reply to#96318
On Fri, Sep 11, 2015 at 2:34 PM, Marko Rauhamaa <marko@pacujo.net> wrote:
> etc. The TAB *key* is a command that makes emacs indent with a mix of
> spaces and TABs.

I don't care how you key them in. If your tab key moves you to the
next position, that's good. If you convert a sequence of N spaces into
a tab character, though, that's bad, because then your file ends up
with a mix, and an inconsistent one. To make emacs safe for use with
Python code, you'll need to reconfigure it so the tab key inserts
either a tab character or spaces, but never switches between them.

Personally, I like to use tab characters for indentation. You can
choose how many pixels or ems or ens or spaces the actual visual shift
is, and if I disagree with your choice, it won't affect anything. As
long as tabs are used _exclusively_, Python won't be bothered by it
either.

ChrisA

[toc] | [prev] | [next] | [standalone]


#96321

FromMarko Rauhamaa <marko@pacujo.net>
Date2015-09-11 08:15 +0300
Message-ID<878u8do7u2.fsf@elektro.pacujo.net>
In reply to#96319
Chris Angelico <rosuav@gmail.com>:

> Personally, I like to use tab characters for indentation. You can
> choose how many pixels or ems or ens or spaces the actual visual shift
> is, and if I disagree with your choice, it won't affect anything. As
> long as tabs are used _exclusively_, Python won't be bothered by it
> either.

Your preferred, novel usage of TABs, which runs counter to the age-old
programming convention, has won enough supporters to make TABs unusable.

No harm done. TABs have been banished. They were a bad idea in the first
place.


Marko

[toc] | [prev] | [next] | [standalone]


#96322

FromChris Angelico <rosuav@gmail.com>
Date2015-09-11 15:25 +1000
Message-ID<mailman.355.1441949149.8327.python-list@python.org>
In reply to#96321
On Fri, Sep 11, 2015 at 3:15 PM, Marko Rauhamaa <marko@pacujo.net> wrote:
> Chris Angelico <rosuav@gmail.com>:
>
>> Personally, I like to use tab characters for indentation. You can
>> choose how many pixels or ems or ens or spaces the actual visual shift
>> is, and if I disagree with your choice, it won't affect anything. As
>> long as tabs are used _exclusively_, Python won't be bothered by it
>> either.
>
> Your preferred, novel usage of TABs, which runs counter to the age-old
> programming convention, has won enough supporters to make TABs unusable.
>
> No harm done. TABs have been banished. They were a bad idea in the first
> place.

I don't understand. How does that usage run counter to the old
conventions? A tab character, a press of the tab key, was a signal to
move to the next logical column - regardless of the exact width of a
column. It's also completely compatible with the stricter rule "a tab
is equivalent to eight spaces".

ChrisA

[toc] | [prev] | [next] | [standalone]


#96383

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2015-09-12 03:43 +0100
Message-ID<mailman.391.1442025833.8327.python-list@python.org>
In reply to#96321
On 11/09/2015 06:15, Marko Rauhamaa wrote:
> Chris Angelico <rosuav@gmail.com>:
>
>> Personally, I like to use tab characters for indentation. You can
>> choose how many pixels or ems or ens or spaces the actual visual shift
>> is, and if I disagree with your choice, it won't affect anything. As
>> long as tabs are used _exclusively_, Python won't be bothered by it
>> either.
>
> Your preferred, novel usage of TABs, which runs counter to the age-old
> programming convention, has won enough supporters to make TABs unusable.
>
> No harm done. TABs have been banished. They were a bad idea in the first
> place.
>
> Marko
>

TABs might have been banished from some places, but certainly not 
Python.  Of course you have to be careful or you run into problems with 
this:-

TabError - Raised when indentation contains an inconsistent use of tabs 
and spaces.

https://docs.python.org/3/library/exceptions.html#TabError

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#96320

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-09-10 23:07 -0600
Message-ID<mailman.354.1441948080.8327.python-list@python.org>
In reply to#96318
On Thu, Sep 10, 2015 at 10:34 PM, Marko Rauhamaa <marko@pacujo.net> wrote:
> Ian Kelly <ian.g.kelly@gmail.com>:
>
>> You can use tabs *or* spaces. If you want to mix the two, then there
>> would need to be some official decision made about how many spaces
>> compose a tab, and then everybody who wants to use tabs would have to
>> configure their editors to conform to that decision, or risk breaking
>> their code. Some people like to indent two spaces. Some people like to
>> indent four spaces. On the other hand, the de facto standard for
>> terminal tab width is eight spaces. However, virtually nobody prefers
>> eight spaces of indentation. So the question is which standard are you
>> going to adopt, and which groups are you going to upset?
>
> Indentation preferences and the interpretation of TABs are two separate
> things.
>
> For example, in the default emacs configuration, the C indentation
> levels go like this:
>
>    SPC SPC
>    SPC SPC SPC SPC
>    SPC SPC SPC SPC SPC SPC
>    TAB
>    TAB SPC SPC
>
> etc. The TAB *key* is a command that makes emacs indent with a mix of
> spaces and TABs.

That's all true but is tangential to my point. Emacs users with that
setup would probably want the Python compiler to interpret a tab as
eight spaces. On the other hand, the major benefit that is often
touted for indentation using tab characters is that the reader can set
their tab width and read the code with their preferred indentation
(this fails however when using mixed tabs and spaces as in that Emacs
scheme). Such users typically use one tab character as one level of
indentation and would presumably prefer to have those tab characters
interpreted as two or four spaces, not eight.

If we're forced to choose a canonical tab width, both groups can't
win. (Of course that Emacs indentation scheme already doesn't work for
Python, but then the only possible benefit I can see to using it is a
mild compression of the source code, an economy of disk space that
really isn't necessary in this day and age.)

[toc] | [prev] | [next] | [standalone]


#96323

FromMarko Rauhamaa <marko@pacujo.net>
Date2015-09-11 08:27 +0300
Message-ID<874mj1o78s.fsf@elektro.pacujo.net>
In reply to#96320
Ian Kelly <ian.g.kelly@gmail.com>:

> Emacs users with that setup would probably want the Python compiler to
> interpret a tab as eight spaces.

Which it does:

   Tabs are replaced (from left to right) by one to eight spaces such
   that the total number of characters up to and including the
   replacement is a multiple of eight (this is intended to be the same
   rule as used by Unix).

   <URL: https://docs.python.org/3/reference/lexical_analysis.html#lin
   e-structure>

although that definition has been rendered insignificant in Python 3 by
the footnote:

   Indentation is rejected as inconsistent if a source file mixes tabs
   and spaces in a way that makes the meaning dependent on the worth of
   a tab in spaces; a TabError is raised in that case.

> On the other hand, the major benefit that is often touted for
> indentation using tab characters is that the reader can set their tab
> width and read the code with their preferred indentation (this fails
> however when using mixed tabs and spaces as in that Emacs scheme).
> Such users typically use one tab character as one level of indentation
> and would presumably prefer to have those tab characters interpreted
> as two or four spaces, not eight.

That "innovation" has destroyed the TAB character. It won't be missed,
though.

> If we're forced to choose a canonical tab width, both groups can't
> win. (Of course that Emacs indentation scheme already doesn't work for
> Python, but then the only possible benefit I can see to using it is a
> mild compression of the source code, an economy of disk space that
> really isn't necessary in this day and age.)

Emacs didn't invent that scheme. That's how TABs worked in my childhood
across operating systems.

However, TABs were always problematic for other reasons. If you added
a space to the beginning of every line to shift everything to the right,
TABs caused a misalignment.


Marko

[toc] | [prev] | [next] | [standalone]


#96330

FromRustom Mody <rustompmody@gmail.com>
Date2015-09-11 00:39 -0700
Message-ID<452038d3-cdcb-4786-b4e0-45df34c56ab8@googlegroups.com>
In reply to#96318
On Friday, September 11, 2015 at 10:04:25 AM UTC+5:30, Marko Rauhamaa wrote:
> Ian Kelly :
> 
> > You can use tabs *or* spaces. If you want to mix the two, then there
> > would need to be some official decision made about how many spaces
> > compose a tab, and then everybody who wants to use tabs would have to
> > configure their editors to conform to that decision, or risk breaking
> > their code. Some people like to indent two spaces. Some people like to
> > indent four spaces. On the other hand, the de facto standard for
> > terminal tab width is eight spaces. However, virtually nobody prefers
> > eight spaces of indentation. So the question is which standard are you
> > going to adopt, and which groups are you going to upset?
> 
> Indentation preferences and the interpretation of TABs are two separate
> things.

Required reading
http://www.jwz.org/doc/tabs-vs-spaces.html

[toc] | [prev] | [next] | [standalone]


#96333

FromSteven D'Aprano <steve@pearwood.info>
Date2015-09-11 18:42 +1000
Message-ID<55f293da$0$1640$c3e8da3$5496439d@news.astraweb.com>
In reply to#96308
On Fri, 11 Sep 2015 10:35 am, Ian Kelly wrote:

> On Thu, Sep 10, 2015 at 4:25 PM,  <tdev@freenet.de> wrote:
[...]
>> So the compiler knows the distiction between global and local already.
> 
> As we've said before, it doesn't. The compiler's current rules are
> fairly simple:
> 
> 1) If it's in the function's argument list, it's an argument (and
> therefore local).
> 2) If it's explicitly declared global, then it's global.
> 3) If it's never assigned within the function, then it's global.

Almost. If it's never assigned within the function, then it is looked up
according to the non-local scoping rules:

- closures and enclosing functions (if any);
- globals;
- builtins;

in that order.


> 4) Otherwise, it's local.

"Otherwise" meaning "if it is assigned to", except that "del" counts as an
assignment. That is:

def spam():
    del x

makes x a local variable inside the function spam.


There's also a bunch of specialised and complicated rules for what happens
if you make a star import ("from module import *") inside a function, or
call eval or exec without specifying a namespace. Both of these things are
now illegal in Python 3.

And lastly, in Python 3 only, there is also a nonlocal declaration which
works like global except it applies only to closures and enclosing
functions.


>> Another proof about identation:
>> The parser can recognise identation with tabs and spaces.
> 
> You can use tabs *or* spaces. 

In Python 3.

In Python 2, you can mix tabs *and* spaces, and Python will try to guess
what you mean. This causes more trouble than it is worth, and is removed in
Python 3.


[...]
> I really doubt that you're going to gain any traction with this one,
> because the decision that was made with Python 3 was to make the
> compiler *more* rigid about not mixing tabs and spaces, not less.

Correct.

[...]
>> Who is responding or has responded?
>> Extreme Programmers, Python-Hardliner, Python-Evangelists, ... .
>> Presumably no core Python Programmers (wrting compiler and standard
>> library stuff)
> 
> Ad hominem.

For the record, I am the author of the statistics module in Python 3.4, and
Terry Reedy is the very active maintainer of IDLE. If I have missed anyone,
my apologies. So, yes, there are core developers here.

(Although not any of the senior core devs, as far as I know.)



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#96335

FromChris Angelico <rosuav@gmail.com>
Date2015-09-11 19:16 +1000
Message-ID<mailman.364.1441962969.8327.python-list@python.org>
In reply to#96333
On Fri, Sep 11, 2015 at 6:42 PM, Steven D'Aprano <steve@pearwood.info> wrote:
>>> Who is responding or has responded?
>>> Extreme Programmers, Python-Hardliner, Python-Evangelists, ... .
>>> Presumably no core Python Programmers (wrting compiler and standard
>>> library stuff)
>>
>> Ad hominem.
>
> For the record, I am the author of the statistics module in Python 3.4, and
> Terry Reedy is the very active maintainer of IDLE. If I have missed anyone,
> my apologies. So, yes, there are core developers here.
>
> (Although not any of the senior core devs, as far as I know.)

I don't know what the definition of "senior core dev" would be.
Checking the Experts List [1] shows you and Terry both, as does the
list of committers [2] (and it has me as well, although that's because
I wear a PEP Editor hat, so I don't count as even a non-senior core
dev). Is there an "inner circle" of people Guido trusts more than
"just ordinary core devs"? I rather suspect not, but maybe I'm wrong.

Hacking on CPython without core dev status is actually pretty easy.
I've done it. (Added a "while ... as name:" syntax, just to see how
hard it would be. Conclusion: It's not hard at all.) If anything,
that's a _lower_ bar to clear than "idiomatic Python programmer",
because anyone can hack on C code without understanding the goals and
beauties of the Python language. So I'm really not sure what the
original complaint was about, nor how to answer it.

ChrisA

[1] https://docs.python.org/devguide/experts.html#experts
[2] https://hg.python.org/committers.txt

[toc] | [prev] | [next] | [standalone]


#96345

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-09-11 09:03 -0600
Message-ID<mailman.370.1441983869.8327.python-list@python.org>
In reply to#96333
On Fri, Sep 11, 2015 at 2:42 AM, Steven D'Aprano <steve@pearwood.info> wrote:
> On Fri, 11 Sep 2015 10:35 am, Ian Kelly wrote:
>
>> On Thu, Sep 10, 2015 at 4:25 PM,  <tdev@freenet.de> wrote:
> [...]
>>> So the compiler knows the distiction between global and local already.
>>
>> As we've said before, it doesn't. The compiler's current rules are
>> fairly simple:
>>
>> 1) If it's in the function's argument list, it's an argument (and
>> therefore local).
>> 2) If it's explicitly declared global, then it's global.
>> 3) If it's never assigned within the function, then it's global.
>
> Almost. If it's never assigned within the function, then it is looked up
> according to the non-local scoping rules:
>
> - closures and enclosing functions (if any);
> - globals;
> - builtins;
>
> in that order.

I excluded non-locals intentionally, but if you want to be pedantic
about it, then that's still not quite right. Non-locals are indeed
identified by the compiler and compiled with the
LOAD_DEREF/STORE_DEREF opcodes (rather than the _GLOBAL and _FAST
variants used by globals and locals, respectively). The compiler
doesn't make any such distinction between globals and builtins
however, as that can only be determined at run-time.

> There's also a bunch of specialised and complicated rules for what happens
> if you make a star import ("from module import *") inside a function, or
> call eval or exec without specifying a namespace. Both of these things are
> now illegal in Python 3.

Huh?

>>> exec("x = 42")
>>> x
42
>>> exec("x = 43", None, None)
>>> x
43

That's in Python 3.4.0. Maybe I don't understand what you mean by
"without specifying a namespace".

[toc] | [prev] | [next] | [standalone]


#96418

FromSteven D'Aprano <steve@pearwood.info>
Date2015-09-12 17:00 +1000
Message-ID<55f3cd96$0$1655$c3e8da3$5496439d@news.astraweb.com>
In reply to#96345
On Sat, 12 Sep 2015 01:03 am, Ian Kelly wrote:

> On Fri, Sep 11, 2015 at 2:42 AM, Steven D'Aprano <steve@pearwood.info>
> wrote:
[...]
>> Almost. If it's never assigned within the function, then it is looked up
>> according to the non-local scoping rules:
>>
>> - closures and enclosing functions (if any);
>> - globals;
>> - builtins;
>>
>> in that order.
> 
> I excluded non-locals intentionally, but if you want to be pedantic
> about it, then that's still not quite right. Non-locals are indeed
> identified by the compiler and compiled with the
> LOAD_DEREF/STORE_DEREF opcodes (rather than the _GLOBAL and _FAST
> variants used by globals and locals, respectively). 

Ah, nice, yes I forgot about that, thanks for the correction.


> The compiler 
> doesn't make any such distinction between globals and builtins
> however, as that can only be determined at run-time.
> 
>> There's also a bunch of specialised and complicated rules for what
>> happens if you make a star import ("from module import *") inside a
>> function, or call eval or exec without specifying a namespace. Both of
>> these things are now illegal in Python 3.
> 
> Huh?
> 
>>>> exec("x = 42")
>>>> x
> 42
>>>> exec("x = 43", None, None)
>>>> x
> 43
> 
> That's in Python 3.4.0. Maybe I don't understand what you mean by
> "without specifying a namespace".

Inside a function star imports are illegal in Python 3:

py> def f():
...     from math import *
...
  File "<stdin>", line 1
SyntaxError: import * only allowed at module level


My recollection was incorrect about exec. You can still exec inside a
function, but it may have no effect:

py> def f():
...     x = 1
...     exec("x = 2")
...     return x
...
py> f()
1

You can specify locals, but it doesn't help:

py> def f():
...     x = 1
...     exec("x = 2", globals(), locals())
...     return x
...
py> f()
1


However, in Python 2, Python tried hard to make exec work:

py> def f():
...     x = 1
...     exec("x = 2")
...     return x
...
py> f()
2


I don't recall all the details, but in Python 2 functions could use two
different schemes for local variables: the regular, optimized one using
memory slots, and a dict-based one that came into play with exec. So we
have this:

py> def g():
...     a = 1
...     exec("b = 2")
...     return (a, b)
...
py> dis.dis(g)
  2           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (a)

  3           6 LOAD_CONST               2 ('b = 2')
              9 LOAD_CONST               0 (None)
             12 DUP_TOP
             13 EXEC_STMT

  4          14 LOAD_FAST                0 (a)
             17 LOAD_NAME                0 (b)
             20 BUILD_TUPLE              2
             23 RETURN_VALUE



`a` is a regular, optimized local looked up with LOAD_FAST; but `b` gets the
same old LOAD_NAME used for globals and built-ins.


In Python 3.3, that same function uses LOAD_GLOBAL for `b`, even though the
variable does actually exist:


py> dis.dis(g)
  2           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (a)

  3           6 LOAD_GLOBAL              0 (exec)
              9 LOAD_CONST               2 ('b = 2')
             12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             15 POP_TOP

  4          16 LOAD_FAST                0 (a)
             19 LOAD_GLOBAL              1 (b)
             22 BUILD_TUPLE              2
             25 RETURN_VALUE
py> g()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in g
NameError: global name 'b' is not defined



The conclusion I draw from all this is that the rules governing local
variables in Python are a mess :-)


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#96346

FromChris Angelico <rosuav@gmail.com>
Date2015-09-12 01:15 +1000
Message-ID<mailman.371.1441984523.8327.python-list@python.org>
In reply to#96333
On Sat, Sep 12, 2015 at 1:03 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>> There's also a bunch of specialised and complicated rules for what happens
>> if you make a star import ("from module import *") inside a function, or
>> call eval or exec without specifying a namespace. Both of these things are
>> now illegal in Python 3.
>
> Huh?
>
>>>> exec("x = 42")
>>>> x
> 42
>>>> exec("x = 43", None, None)
>>>> x
> 43
>
> That's in Python 3.4.0. Maybe I don't understand what you mean by
> "without specifying a namespace".

*inside a function*

>>> def f():
...    exec("x = 42")
...    print(x)
...
>>> x = 231
>>> f()
231

ChrisA

[toc] | [prev] | [next] | [standalone]


#96347

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-09-11 09:27 -0600
Message-ID<mailman.372.1441985273.8327.python-list@python.org>
In reply to#96333
On Fri, Sep 11, 2015 at 9:15 AM, Chris Angelico <rosuav@gmail.com> wrote:
> On Sat, Sep 12, 2015 at 1:03 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>>> There's also a bunch of specialised and complicated rules for what happens
>>> if you make a star import ("from module import *") inside a function, or
>>> call eval or exec without specifying a namespace. Both of these things are
>>> now illegal in Python 3.
>>
>> Huh?
>>
>>>>> exec("x = 42")
>>>>> x
>> 42
>>>>> exec("x = 43", None, None)
>>>>> x
>> 43
>>
>> That's in Python 3.4.0. Maybe I don't understand what you mean by
>> "without specifying a namespace".
>
> *inside a function*
>
>>>> def f():
> ...    exec("x = 42")
> ...    print(x)
> ...
>>>> x = 231
>>>> f()
> 231

Ah, I didn't parse the "inside a function" as applying to that clause,
but even so, I don't see in what way that is "now illegal". For
example:

>>> x = 231
>>> def f():
...   exec("print(x); x = 42; print(x)")
...   print(x)
...
>>> f()
231
42
231

The exec still happily runs; it's just using its own private locals namespace.

Tangent: does the help for exec need to be updated? It currently reads:

    The globals and locals are dictionaries, defaulting to the current
    globals and locals.  If only globals is given, locals defaults to it.

Which would seem to indicate that if called from within a function
with no globals or locals, the locals from the function would be used.

[toc] | [prev] | [next] | [standalone]


#96348

FromChris Angelico <rosuav@gmail.com>
Date2015-09-12 01:44 +1000
Message-ID<mailman.373.1441986260.8327.python-list@python.org>
In reply to#96333
On Sat, Sep 12, 2015 at 1:27 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> The exec still happily runs; it's just using its own private locals namespace.
>
> Tangent: does the help for exec need to be updated? It currently reads:
>
>     The globals and locals are dictionaries, defaulting to the current
>     globals and locals.  If only globals is given, locals defaults to it.
>
> Which would seem to indicate that if called from within a function
> with no globals or locals, the locals from the function would be used.

And that's the thing... I think. It's using locals(), which starts out
as a copy of the function's locals (in this example, empty), but
without assignment affecting anything. Which is more than a little
weird:

>>> def f():
...     x = [1]
...     exec("print(x); x[0] = 2; print(x); x = [3]; print(x)")
...     print(x)
...
>>> f()
[1]
[2]
[3]
[2]

It's kinda like how globals can shadow builtins, I think. Maybe.
Except that you can't del the name inside exec to unshadow and go back
to the outer version of it.

ChrisA

[toc] | [prev] | [next] | [standalone]


#96349

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-09-11 09:49 -0600
Message-ID<mailman.374.1441986629.8327.python-list@python.org>
In reply to#96333
On Fri, Sep 11, 2015 at 9:44 AM, Chris Angelico <rosuav@gmail.com> wrote:
> On Sat, Sep 12, 2015 at 1:27 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>> The exec still happily runs; it's just using its own private locals namespace.
>>
>> Tangent: does the help for exec need to be updated? It currently reads:
>>
>>     The globals and locals are dictionaries, defaulting to the current
>>     globals and locals.  If only globals is given, locals defaults to it.
>>
>> Which would seem to indicate that if called from within a function
>> with no globals or locals, the locals from the function would be used.
>
> And that's the thing... I think. It's using locals(), which starts out
> as a copy of the function's locals (in this example, empty), but
> without assignment affecting anything. Which is more than a little
> weird:
>
>>>> def f():
> ...     x = [1]
> ...     exec("print(x); x[0] = 2; print(x); x = [3]; print(x)")
> ...     print(x)
> ...
>>>> f()
> [1]
> [2]
> [3]
> [2]

Ah, that makes sense. It's writing into the dict that is created and
returned by locals(), but not actually updating the frame locals which
are the source of truth.

[toc] | [prev] | [next] | [standalone]


#96352

FromChris Angelico <rosuav@gmail.com>
Date2015-09-12 01:55 +1000
Message-ID<mailman.375.1441986932.8327.python-list@python.org>
In reply to#96333
On Sat, Sep 12, 2015 at 1:49 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
>> And that's the thing... I think. It's using locals(), which starts out
>> as a copy of the function's locals (in this example, empty), but
>> without assignment affecting anything. Which is more than a little
>> weird:
>>
>>>>> def f():
>> ...     x = [1]
>> ...     exec("print(x); x[0] = 2; print(x); x = [3]; print(x)")
>> ...     print(x)
>> ...
>>>>> f()
>> [1]
>> [2]
>> [3]
>> [2]
>
> Ah, that makes sense. It's writing into the dict that is created and
> returned by locals(), but not actually updating the frame locals which
> are the source of truth.

Yeah... but it only makes sense to people who understand the
implementation. It's certainly not a logical and sane behaviour that
would be worth documenting and using.

ChrisA

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.python


csiph-web