Re: Quirk difference between classes and functions

2019-02-27 Thread Peter J. Holzer
On 2019-02-27 12:34:37 -0500, Dennis Lee Bieber wrote:
> On Tue, 26 Feb 2019 19:15:16 -0800 (PST), jf...@ms4.hinet.net declaimed the
> following:
> 
> >So, may I say that the Python compiler is a multi-pass one?
> 
>   No... that is implementation dependent...

True, but

>   The common Python is a byte-code compiler pass (how many is undefined)
> which then feeds a byte-code INTERPRETER.

He's only talking about the byte-code compiler here, not the
interpreter.

> The compiler pass "sees" the local assignment, and creates a run-time
> data structure for the function which "holds" the local data.

Yup, but in

def foo():
print(bar)
bar = 1

the compiler sees the local assignment AFTER the print() call. So it
can't generate code to access the local variable for the print call
because it doesn't yet know that bar is a local variable.

The obvious way around this is a two pass compiler: In the first pass
you parse the whole function and convert it into an AST. While you do
this you can also collect local variables. In the second pass you
convert the AST to byte-code.

I think it should be possible to do it in a single pass, although at the
cost of generating less efficient code: For each variable access,
produce code to check for a local variable first, then a global one.
Collect information on local variables at the same time. When you are
done, generate the code to set up the local variables and arrange for it
to be executed before any other code in the function.

hp


-- 
   _  | Peter J. Holzer| we build much bigger, better disasters now
|_|_) || because we have much more sophisticated
| |   | h...@hjp.at | management tools.
__/   | http://www.hjp.at/ | -- Ross Anderson 


signature.asc
Description: PGP signature
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Quirk difference between classes and functions

2019-02-27 Thread jfong
jf...@ms4.hinet.net於 2019年2月26日星期二 UTC+8下午4時46分04秒寫道:
> ast於 2019年2月26日星期二 UTC+8上午12時25分40秒寫道:
> > Hello
> > 
> > I noticed a quirk difference between classes and functions
> > 
> >  >>> x=0
> >  >>>
> >  >>> class Test:
> >  x = x+1
> >  print(x)
> >  x = x+1
> >  print(x)
> > 
> > 1
> > 2
> >  >>> print(x)
> > 0
> > 
> > Previous code doesn't generate any errors.
> > x at the right of = in first "x = x+1" line is
> > the global one (x=0), then x becomes local
> > 
> > within a function, this is not allowed
> > 
> >  >>> x = 0
> >  >>>
> >  >>> def f():
> >  x = x+1
> > 
> >  >>> f()
> > UnboundLocalError: local variable 'x' referenced before assignment
> > 
> > Since x is written inside the function, it is considered as a local
> > variable and x in x+1 is undefined so this throw an exception
> > 
> > Any comment ?
> 
> May I say that the LEGB rule apply to run time, not compile time?

No. The LEGB apply to compile time where only name and scope are involved.

> 
> >>> x = 1
> >>> def f():
> ... print(x)
> ... print(locals())
> ...
> >>> f()
> 1
> {}
> >>> def g():
> ... print(x)
> ... x = 2
> ... print(locals())
> ...
> >>> g()
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "", line 2, in g
> UnboundLocalError: local variable 'x' referenced before assignment
> >>> class X:
> ... print(x)
> ... x = 2
> ...
> 1
> >>>
> The print(x) difference between class and function was caused by that one was 
> executed and the other was compiled. The LEGB rule must apply to run time to 
> make the language dynamic.

At run time, the binding between name and object can be changed. It's the word 
"dynamic" comes from. 

What happens in class X when print(x) was encountered? I have no idea how the 
LEGB involves there yet:-(

--Jach

> 
> Any comment:-)?
> 
> --Jach

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


Re: Quirk difference between classes and functions

2019-02-26 Thread jfong
Chris Angelico於 2019年2月27日星期三 UTC+8上午11時29分04秒寫道:
> On Wed, Feb 27, 2019 at 2:21 PM  wrote:
> >
> > Chris Angelico於 2019年2月27日星期三 UTC+8上午9時25分11秒寫道:
> > > On Wed, Feb 27, 2019 at 12:21 PM  wrote:
> > > >
> > > > Gregory Ewing at 2019/2/27 AM 5:26:49 wrote:
> > > > > Thomas Jollans wrote:
> > > > > > I imagine there's a justification for the difference in behaviour 
> > > > > > to do
> > > > > > with the fact that the body of a class is only ever executed once, 
> > > > > > while
> > > > > > the body of a function is executed multiple times.
> > > > >
> > > > > I suspect there isn't any deep reason for it, rather it's just
> > > > > something that fell out of the implementation, in particular
> > > > > the decision to optimise local variable access in functions
> > > > > but not other scopes.
> > > > >
> > > > > When compiling a function, the compiler needs to know which
> > > > > variables are local so that it can allocate slots for them in
> > > > > the stack frame. But when executing a class body, the locals
> > > > > are kept in a dict and are looked up dynamically.
> > > >
> > > > If the compiler can do any decision on the variable's name, when it 
> > > > goes to line of print, how it handle it?
> > > >
> > > > x = 0
> > > > def f():
> > > > print(x)
> > > >
> > > > def g():
> > > > print(x)
> > > > x = 1
> > > > print(y)
> > > >
> > >
> > > Not sure what you mean by "decision", but the definition is that since
> > > x is assigned to in g(), it is local to g(). It's not local to f(), so
> > > the global is visible.
> >
> > So, may I say that the Python compiler is a multi-pass one?
> >
> 
> At this point, you're veering away from "Python-the-language" and
> towards "CPython-the-implementation" (or whichever other
> implementation you want to explore). 

Yes, it's a little away:-) I was curious about how the compiled print(x) can be 
influenced by x = 1 after it. Anyway, thank you for your confirmation.

--Jach

> But I would say that, yes, most
> or all Python implementations will use multi-pass compilation. It's
> the easiest way to guarantee correct behaviour. For instance, when you
> reach a "try" statement, you don't know whether there'll be an
> "except" block after it (there might just be a "finally"); the
> bytecode that CPython produces is different for setting up a
> finally-only block than for setting up a try/except. Easiest to find
> out that sort of thing by running multiple passes.
> 
> Plus, depending on how you define "pass", there are additional steps
> such as constant folding and peephole optimization that can be done
> after everything else. So, yeah, it's highly unlikely that there are
> any performant implementations of Python that run a single compilation
> pass.
> 
> ChrisA

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


Re: Quirk difference between classes and functions

2019-02-26 Thread Chris Angelico
On Wed, Feb 27, 2019 at 2:21 PM  wrote:
>
> Chris Angelico於 2019年2月27日星期三 UTC+8上午9時25分11秒寫道:
> > On Wed, Feb 27, 2019 at 12:21 PM  wrote:
> > >
> > > Gregory Ewing at 2019/2/27 AM 5:26:49 wrote:
> > > > Thomas Jollans wrote:
> > > > > I imagine there's a justification for the difference in behaviour to 
> > > > > do
> > > > > with the fact that the body of a class is only ever executed once, 
> > > > > while
> > > > > the body of a function is executed multiple times.
> > > >
> > > > I suspect there isn't any deep reason for it, rather it's just
> > > > something that fell out of the implementation, in particular
> > > > the decision to optimise local variable access in functions
> > > > but not other scopes.
> > > >
> > > > When compiling a function, the compiler needs to know which
> > > > variables are local so that it can allocate slots for them in
> > > > the stack frame. But when executing a class body, the locals
> > > > are kept in a dict and are looked up dynamically.
> > >
> > > If the compiler can do any decision on the variable's name, when it goes 
> > > to line of print, how it handle it?
> > >
> > > x = 0
> > > def f():
> > > print(x)
> > >
> > > def g():
> > > print(x)
> > > x = 1
> > > print(y)
> > >
> >
> > Not sure what you mean by "decision", but the definition is that since
> > x is assigned to in g(), it is local to g(). It's not local to f(), so
> > the global is visible.
>
> So, may I say that the Python compiler is a multi-pass one?
>

At this point, you're veering away from "Python-the-language" and
towards "CPython-the-implementation" (or whichever other
implementation you want to explore). But I would say that, yes, most
or all Python implementations will use multi-pass compilation. It's
the easiest way to guarantee correct behaviour. For instance, when you
reach a "try" statement, you don't know whether there'll be an
"except" block after it (there might just be a "finally"); the
bytecode that CPython produces is different for setting up a
finally-only block than for setting up a try/except. Easiest to find
out that sort of thing by running multiple passes.

Plus, depending on how you define "pass", there are additional steps
such as constant folding and peephole optimization that can be done
after everything else. So, yeah, it's highly unlikely that there are
any performant implementations of Python that run a single compilation
pass.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Quirk difference between classes and functions

2019-02-26 Thread jfong
Chris Angelico於 2019年2月27日星期三 UTC+8上午9時25分11秒寫道:
> On Wed, Feb 27, 2019 at 12:21 PM  wrote:
> >
> > Gregory Ewing at 2019/2/27 AM 5:26:49 wrote:
> > > Thomas Jollans wrote:
> > > > I imagine there's a justification for the difference in behaviour to do
> > > > with the fact that the body of a class is only ever executed once, while
> > > > the body of a function is executed multiple times.
> > >
> > > I suspect there isn't any deep reason for it, rather it's just
> > > something that fell out of the implementation, in particular
> > > the decision to optimise local variable access in functions
> > > but not other scopes.
> > >
> > > When compiling a function, the compiler needs to know which
> > > variables are local so that it can allocate slots for them in
> > > the stack frame. But when executing a class body, the locals
> > > are kept in a dict and are looked up dynamically.
> >
> > If the compiler can do any decision on the variable's name, when it goes to 
> > line of print, how it handle it?
> >
> > x = 0
> > def f():
> > print(x)
> >
> > def g():
> > print(x)
> > x = 1
> > print(y)
> >
> 
> Not sure what you mean by "decision", but the definition is that since
> x is assigned to in g(), it is local to g(). It's not local to f(), so
> the global is visible.

So, may I say that the Python compiler is a multi-pass one?

--Jach
> 
> (Incidentally, "print" is handled exactly the same way. Since neither
> function assigns to print, it's not local, so the built-in is found.)
> 
> ChrisA

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


Re: Quirk difference between classes and functions

2019-02-26 Thread Chris Angelico
On Wed, Feb 27, 2019 at 12:21 PM  wrote:
>
> Gregory Ewing at 2019/2/27 AM 5:26:49 wrote:
> > Thomas Jollans wrote:
> > > I imagine there's a justification for the difference in behaviour to do
> > > with the fact that the body of a class is only ever executed once, while
> > > the body of a function is executed multiple times.
> >
> > I suspect there isn't any deep reason for it, rather it's just
> > something that fell out of the implementation, in particular
> > the decision to optimise local variable access in functions
> > but not other scopes.
> >
> > When compiling a function, the compiler needs to know which
> > variables are local so that it can allocate slots for them in
> > the stack frame. But when executing a class body, the locals
> > are kept in a dict and are looked up dynamically.
>
> If the compiler can do any decision on the variable's name, when it goes to 
> line of print, how it handle it?
>
> x = 0
> def f():
> print(x)
>
> def g():
> print(x)
> x = 1
> print(y)
>

Not sure what you mean by "decision", but the definition is that since
x is assigned to in g(), it is local to g(). It's not local to f(), so
the global is visible.

(Incidentally, "print" is handled exactly the same way. Since neither
function assigns to print, it's not local, so the built-in is found.)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Quirk difference between classes and functions

2019-02-26 Thread eryk sun
On 2/26/19, Gregory Ewing  wrote:
> Thomas Jollans wrote:
>> I imagine there's a justification for the difference in behaviour to do
>> with the fact that the body of a class is only ever executed once, while
>> the body of a function is executed multiple times.
>
> I suspect there isn't any deep reason for it, rather it's just
> something that fell out of the implementation, in particular
> the decision to optimise local variable access in functions
> but not other scopes.

At the module level, this goes unnoticed since globals and locals are
the same dict, but we can observe it in an exec() call if we use
separate globals and locals . For example:

>>> x = 0
>>> locals = {}
>>> exec('x = x + 1', globals(), locals)
>>> x
0
>>> locals
{'x': 1}

In terms of implementation, the LOAD_NAME instruction that's used in
unoptimized code looks in the locals, globals, and builtins scopes, in
that order. The intent is to allow locals to shadow globals and
builtins, and globals to shadow builtins. It also allows for temporary
shadowing. Optimized code supports the former (via LOAD_GLOBAL), but
not the latter. For example:

unoptimized:

>>> exec(r'''
... len = lambda x: 42
... print(len('spam'))
... del len
... print(len('spam'))
... ''')
42
4

optimized:

>>> def f():
... len = lambda x: 42
... print(len('spam'))
... del len
... print(len('spam'))
...
>>> f()
42
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 5, in f
UnboundLocalError: local variable 'len' referenced before assignment
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Quirk difference between classes and functions

2019-02-26 Thread jfong
Gregory Ewing at 2019/2/27 AM 5:26:49 wrote:
> Thomas Jollans wrote:
> > I imagine there's a justification for the difference in behaviour to do
> > with the fact that the body of a class is only ever executed once, while
> > the body of a function is executed multiple times.
> 
> I suspect there isn't any deep reason for it, rather it's just
> something that fell out of the implementation, in particular
> the decision to optimise local variable access in functions
> but not other scopes.
> 
> When compiling a function, the compiler needs to know which
> variables are local so that it can allocate slots for them in
> the stack frame. But when executing a class body, the locals
> are kept in a dict and are looked up dynamically.

If the compiler can do any decision on the variable's name, when it goes to 
line of print, how it handle it?

x = 0
def f():
print(x)

def g():
print(x)
x = 1
print(y)

--Jach

> The compiler *could* be made to treat class bodies the same
> way as functions in this regard, but it would be extra work
> for little or no benefit. Most code in class bodies just
> defines new names without referring to anything else in the
> same scope.
> 
> -- 
> Greg

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


RE: Quirk difference between classes and functions

2019-02-26 Thread Steve
I have been a silent reader on this and am interested in understanding more
about the scope of variables in Python.  They do not seem to behave as I
have experienced in other programming languages.

I have used functions in python but was not aware of class.
It would benefit me very well if someone could post a simple example of each
on which I might experiment.
Steve




Footnote:
There's 99 bugs in the code, in the code.
99 bugs in the code.
Take one down and patch it all around.
Now there's 117 bugs in the code.

-Original Message-
From: Python-list  On
Behalf Of Gregory Ewing
Sent: Tuesday, February 26, 2019 4:27 PM
To: python-list@python.org
Subject: Re: Quirk difference between classes and functions

Thomas Jollans wrote:
> I imagine there's a justification for the difference in behaviour to 
> do with the fact that the body of a class is only ever executed once, 
> while the body of a function is executed multiple times.

I suspect there isn't any deep reason for it, rather it's just something
that fell out of the implementation, in particular the decision to optimise
local variable access in functions but not other scopes.

When compiling a function, the compiler needs to know which variables are
local so that it can allocate slots for them in the stack frame. But when
executing a class body, the locals are kept in a dict and are looked up
dynamically.

The compiler *could* be made to treat class bodies the same way as functions
in this regard, but it would be extra work for little or no benefit. Most
code in class bodies just defines new names without referring to anything
else in the same scope.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list

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


Re: Quirk difference between classes and functions

2019-02-26 Thread Gregory Ewing

Thomas Jollans wrote:

I imagine there's a justification for the difference in behaviour to do
with the fact that the body of a class is only ever executed once, while
the body of a function is executed multiple times.


I suspect there isn't any deep reason for it, rather it's just
something that fell out of the implementation, in particular
the decision to optimise local variable access in functions
but not other scopes.

When compiling a function, the compiler needs to know which
variables are local so that it can allocate slots for them in
the stack frame. But when executing a class body, the locals
are kept in a dict and are looked up dynamically.

The compiler *could* be made to treat class bodies the same
way as functions in this regard, but it would be extra work
for little or no benefit. Most code in class bodies just
defines new names without referring to anything else in the
same scope.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Quirk difference between classes and functions

2019-02-26 Thread Thomas Jollans
On 25/02/2019 21.15, Chris Angelico wrote:
> On Tue, Feb 26, 2019 at 6:58 AM DL Neil  
> wrote:
>>
>> On 26/02/19 5:25 AM, ast wrote:
>>> I noticed a quirk difference between classes and functions
>>>  >>> x=0
>>>  >>> class Test:
>>>  x = x+1
>>>  print(x)
>>>  x = x+1
>>>  print(x)
>> ...
>>
>>> Previous code doesn't generate any errors.
>>> x at the right of = in first "x = x+1" line is
>>> the global one (x=0), then x becomes local
>>> within a function, this is not allowed
>>>  >>> x = 0
>>>  >>> def f():
>>>  x = x+1
>>>  >>> f()
>>> UnboundLocalError: local variable 'x' referenced before assignment
>>> Since x is written inside the function, it is considered as a local
>>> variable and x in x+1 is undefined so this throw an exception
>>> Any comment ?
>>
>>
>> At first I misunderstood the question, and even now I'm slightly mystified:-
>>
>> Is the observation to do with the principles of "closure" (being applied
>> to the function) compared with the differences between class and
>> instance variables?
> 
> Classes and functions behave differently. Inside a function, a name is
> local if it's ever assigned to; but in a class, this is not the case.
> (Honestly, I'm not sure why this is, but it's hardly ever significant;
> metaprogramming seldom runs into this kind of thing.)

I imagine there's a justification for the difference in behaviour to do
with the fact that the body of a class is only ever executed once, while
the body of a function is executed multiple times. But I don't quite see it.




> 
>> A question from me: (I'm not an O-O 'native' having taken to it long
>> after first learning 'programming') I've used class attributes to hold
>> 'constants', eg
>>
>> MAXIMUM_WEIGHT = 100
>>
>> Thus only an assignment to which reference/assertions will be made 'later'.
>>
>> I have initialised a counter to zero and then incremented within the
>> instantiated object's __init__(), ie keeping track of how many of 'these
>> objects' have been instantiated.
> 
> Once you're inside a method, you would reference it with a dot -
> either "self.MAXIMUM_WEIGHT" or "cls.MAXIMUM_WEIGHT". So it's now an
> attribute, not a local name.
> 
>> So, I can imagine taking a value from outside the class' namespace,
>> modifying it in some way (per the first "x = x+1") and then retaining
>> the result as a class attribute (a calculation performed once - when the
>> class code is compiled).
> 
> Yes, this is perfectly legitimate. Not common but legit.
> 
>> However, (after that first calculation/definition of the class
>> attribute) why would one (normally) want to redefine the same class
>> attribute (the second x = x+1), at the 'class level'?
>> (perhaps just done for its amusement value?)
> 
> That would not be common either. If you're redefining a variable
> multiple times within a class block, you probably don't also have it
> at top level. (For instance, you can put a "for" loop inside a class
> statement to create attributes/methods, but the loop variable is
> unlikely to also be a global.)
> 
> But hey! It's fun! :)
> 
> ChrisA
> 
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Quirk difference between classes and functions

2019-02-26 Thread jfong
ast於 2019年2月26日星期二 UTC+8上午12時25分40秒寫道:
> Hello
> 
> I noticed a quirk difference between classes and functions
> 
>  >>> x=0
>  >>>
>  >>> class Test:
>  x = x+1
>  print(x)
>  x = x+1
>  print(x)
> 
> 1
> 2
>  >>> print(x)
> 0
> 
> Previous code doesn't generate any errors.
> x at the right of = in first "x = x+1" line is
> the global one (x=0), then x becomes local
> 
> within a function, this is not allowed
> 
>  >>> x = 0
>  >>>
>  >>> def f():
>  x = x+1
> 
>  >>> f()
> UnboundLocalError: local variable 'x' referenced before assignment
> 
> Since x is written inside the function, it is considered as a local
> variable and x in x+1 is undefined so this throw an exception
> 
> Any comment ?

May I say that the LEGB rule apply to run time, not compile time?

>>> x = 1
>>> def f():
... print(x)
... print(locals())
...
>>> f()
1
{}
>>> def g():
... print(x)
... x = 2
... print(locals())
...
>>> g()
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in g
UnboundLocalError: local variable 'x' referenced before assignment
>>> class X:
... print(x)
... x = 2
...
1
>>>
The print(x) difference between class and function was caused by that one was 
executed and the other was compiled. The LEGB rule must apply to run time to 
make the language dynamic.

Any comment:-)?

--Jach

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


Re: Quirk difference between classes and functions

2019-02-25 Thread Chris Angelico
On Tue, Feb 26, 2019 at 5:06 PM Gregory Ewing
 wrote:
>
> Chris Angelico wrote:
> > Classes and functions behave differently. Inside a function, a name is
> > local if it's ever assigned to; but in a class, this is not the case.
>
> Actually, it is. Assigning to a name in a class body makes it part
> of the class namespace, which is the local namespace at the time
> the class body is executed.

The significant part here is "ever". Consider:

>>> x = 1
>>> def f():
...print(x)
...x = 2
...print(x)
...
>>> f()
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in f
UnboundLocalError: local variable 'x' referenced before assignment
>>> class X:
...print(x)
...x = 2
...print(x)
...
1
2
>>>

In the function, since x *is* assigned to at some point, it is deemed
a local name, which means that referencing it bombs. In the class,
that isn't the case; until it is actually assigned to, it isn't part
of the class's namespace, so the global is visible.

So, yes, it's a difference between function namespaces and other
namespaces (modules work the same way as classes).

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Quirk difference between classes and functions

2019-02-25 Thread Gregory Ewing

Chris Angelico wrote:

Classes and functions behave differently. Inside a function, a name is
local if it's ever assigned to; but in a class, this is not the case.


Actually, it is. Assigning to a name in a class body makes it part
of the class namespace, which is the local namespace at the time
the class body is executed.

The unusual thing about a class namespace is that it doesn't
form part of the scope of closures created within the class.
So methods, for example, can't directy see attributes of the
class they're defined in.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Quirk difference between classes and functions

2019-02-25 Thread Chris Angelico
On Tue, Feb 26, 2019 at 6:58 AM DL Neil  wrote:
>
> On 26/02/19 5:25 AM, ast wrote:
> > I noticed a quirk difference between classes and functions
> >  >>> x=0
> >  >>> class Test:
> >  x = x+1
> >  print(x)
> >  x = x+1
> >  print(x)
> ...
>
> > Previous code doesn't generate any errors.
> > x at the right of = in first "x = x+1" line is
> > the global one (x=0), then x becomes local
> > within a function, this is not allowed
> >  >>> x = 0
> >  >>> def f():
> >  x = x+1
> >  >>> f()
> > UnboundLocalError: local variable 'x' referenced before assignment
> > Since x is written inside the function, it is considered as a local
> > variable and x in x+1 is undefined so this throw an exception
> > Any comment ?
>
>
> At first I misunderstood the question, and even now I'm slightly mystified:-
>
> Is the observation to do with the principles of "closure" (being applied
> to the function) compared with the differences between class and
> instance variables?

Classes and functions behave differently. Inside a function, a name is
local if it's ever assigned to; but in a class, this is not the case.
(Honestly, I'm not sure why this is, but it's hardly ever significant;
metaprogramming seldom runs into this kind of thing.)

> A question from me: (I'm not an O-O 'native' having taken to it long
> after first learning 'programming') I've used class attributes to hold
> 'constants', eg
>
> MAXIMUM_WEIGHT = 100
>
> Thus only an assignment to which reference/assertions will be made 'later'.
>
> I have initialised a counter to zero and then incremented within the
> instantiated object's __init__(), ie keeping track of how many of 'these
> objects' have been instantiated.

Once you're inside a method, you would reference it with a dot -
either "self.MAXIMUM_WEIGHT" or "cls.MAXIMUM_WEIGHT". So it's now an
attribute, not a local name.

> So, I can imagine taking a value from outside the class' namespace,
> modifying it in some way (per the first "x = x+1") and then retaining
> the result as a class attribute (a calculation performed once - when the
> class code is compiled).

Yes, this is perfectly legitimate. Not common but legit.

> However, (after that first calculation/definition of the class
> attribute) why would one (normally) want to redefine the same class
> attribute (the second x = x+1), at the 'class level'?
> (perhaps just done for its amusement value?)

That would not be common either. If you're redefining a variable
multiple times within a class block, you probably don't also have it
at top level. (For instance, you can put a "for" loop inside a class
statement to create attributes/methods, but the loop variable is
unlikely to also be a global.)

But hey! It's fun! :)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Quirk difference between classes and functions

2019-02-25 Thread DL Neil

On 26/02/19 5:25 AM, ast wrote:

I noticed a quirk difference between classes and functions
 >>> x=0
 >>> class Test:
     x = x+1
     print(x)
     x = x+1
     print(x)

...


Previous code doesn't generate any errors.
x at the right of = in first "x = x+1" line is
the global one (x=0), then x becomes local
within a function, this is not allowed
 >>> x = 0
 >>> def f():
     x = x+1
 >>> f()
UnboundLocalError: local variable 'x' referenced before assignment
Since x is written inside the function, it is considered as a local
variable and x in x+1 is undefined so this throw an exception
Any comment ?



At first I misunderstood the question, and even now I'm slightly mystified:-

Is the observation to do with the principles of "closure" (being applied 
to the function) compared with the differences between class and 
instance variables?


For a little more fun, try expanding Test with:
def __init__( self ):
self.x = "something else"

What happens when you look at Test.__dict__?

What happens after instantiation:

t = Test()
print( t.__dict__ )

For extra credit: how does this change if we try modifying attributes 
from 'outside' the class definition?


t.x = 3.33

Are they all 'the same' or 'all different'?


A question from me: (I'm not an O-O 'native' having taken to it long 
after first learning 'programming') I've used class attributes to hold 
'constants', eg


MAXIMUM_WEIGHT = 100

Thus only an assignment to which reference/assertions will be made 'later'.

I have initialised a counter to zero and then incremented within the 
instantiated object's __init__(), ie keeping track of how many of 'these 
objects' have been instantiated.


So, I can imagine taking a value from outside the class' namespace, 
modifying it in some way (per the first "x = x+1") and then retaining 
the result as a class attribute (a calculation performed once - when the 
class code is compiled).


However, (after that first calculation/definition of the class 
attribute) why would one (normally) want to redefine the same class 
attribute (the second x = x+1), at the 'class level'?

(perhaps just done for its amusement value?)

--
Regards =dn
--
https://mail.python.org/mailman/listinfo/python-list


Quirk difference between classes and functions

2019-02-25 Thread ast

Hello

I noticed a quirk difference between classes and functions

>>> x=0
>>>
>>> class Test:
x = x+1
print(x)
x = x+1
print(x)

1
2
>>> print(x)
0

Previous code doesn't generate any errors.
x at the right of = in first "x = x+1" line is
the global one (x=0), then x becomes local

within a function, this is not allowed

>>> x = 0
>>>
>>> def f():
x = x+1

>>> f()
UnboundLocalError: local variable 'x' referenced before assignment

Since x is written inside the function, it is considered as a local
variable and x in x+1 is undefined so this throw an exception

Any comment ?
--
https://mail.python.org/mailman/listinfo/python-list