[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Quirk difference between classes and functions

On 25/02/2019 21.15, Chris Angelico wrote:
> On Tue, Feb 26, 2019 at 6:58 AM DL Neil <PythonList at danceswithmice.info> 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