Mailing List Archive

Re: Class Definitions
ram@zedat.fu-berlin.de (Stefan Ram) writes:

I expected this solution:

class Main:
def __init__( self ):
self.value = 0
def count( self ):
self.value += 1

but a student turned in the following solution:

class Main:
value = 0
def count(self):
self.value += 1

I thought that the solution of the student had a shortcoming
but I was not able to put my finger on it. Can you?

Not exactly a shortcoming, but the fact that it works as a solution to
your problem may cause the student to someday write something like:

class Main:
value = []
def add(self, x):
self.value += [x]

and be suprised by the resulting behavior.

--
Alan Bawden
--
https://mail.python.org/mailman/listinfo/python-list
Re: Class Definitions [ In reply to ]
On 13/11/2020 08:47, Alan Bawden wrote:
> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>
> I expected this solution:
>
> class Main:
> def __init__( self ):
> self.value = 0
> def count( self ):
> self.value += 1
>
> but a student turned in the following solution:
>
> class Main:
> value = 0
> def count(self):
> self.value += 1
>
> I thought that the solution of the student had a shortcoming
> but I was not able to put my finger on it. Can you?
>
> Not exactly a shortcoming, but the fact that it works as a solution to
> your problem may cause the student to someday write something like:
>
> class Main:
> value = []
> def add(self, x):
> self.value += [x]
>
> and be suprised by the resulting behavior.


You are right to be concerned - although largely because the differences
between class-variables and instance-variables is (sadly) one of those
topics poorly-understood by many, and thus best avoided simply to
prevent confusion. (I'll be the first to concur that this not a good
reason, and particularly not for someone in education/training, but
that's life ["as we know it, Jim"])

A worthwhile read is: https://docs.python.org/3/tutorial/classes.html

(including @Alan's most-pertinent warning of the subtleties introduced
by mutable data-structures)


On the other hand, Python has long?always had an aversion to the
object-induced 'boiler-plate' required in other languages - and I have
to say, even building Python classes with __init__(), __str__(), and
__repr__() etc "magic methods", can seem a slog for low return-value.

AFTER teaching/learning about the 'classic form', you may like to
consider DataClasses (Python 3.7+). These look very similar to your
student's submission. One of their objectives is to cut-through a load
of the boiler-plate - in many circumstances.
https://www.python.org/dev/peps/pep-0557/
https://docs.python.org/3/library/dataclasses.html

See also Counter Objects:
https://docs.python.org/3/library/collections.html#counter-objects
--
Regards =dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: Class Definitions [ In reply to ]
On 11 Nov 2020 19:21:57 GMT
ram@zedat.fu-berlin.de (Stefan Ram) wrote:

> In my Python course I gave the assignment to define a
> counter class "Main" so that
>
> counter0 = Main()
> counter1 = Main()
> counter1.count(); counter1.count(); counter1.count()
> counter1.count(); counter1.count()
> print( counter0.value )
> print( counter1.value )
>
> would print
>
> 0
> 5
>
> .
>
> I expected this solution:
>
> class Main:
> def __init__( self ):
> self.value = 0
> def count( self ):
> self.value += 1
>
> but a student turned in the following solution:
>
> class Main:
> value = 0
> def count(self):
> self.value += 1
>
> .

I am still a Python beginner and didn't even believe that the student's
solution would work. I had expected an error as the instance variable
self.value was not initialized.


--
Manfred


--
https://mail.python.org/mailman/listinfo/python-list
Re: Class Definitions [ In reply to ]
On 2020-11-14 at 10:09:32 +0100,
Manfred Lotz <ml_news@posteo.de> wrote:

> On 11 Nov 2020 19:21:57 GMT
> ram@zedat.fu-berlin.de (Stefan Ram) wrote:
>
> > In my Python course I gave the assignment to define a
> > counter class "Main" so that
> >
> > counter0 = Main()
> > counter1 = Main()
> > counter1.count(); counter1.count(); counter1.count()
> > counter1.count(); counter1.count()
> > print( counter0.value )
> > print( counter1.value )
> >
> > would print
> >
> > 0
> > 5
> >
> > .
> >
> > I expected this solution:
> >
> > class Main:
> > def __init__( self ):
> > self.value = 0
> > def count( self ):
> > self.value += 1
> >
> > but a student turned in the following solution:
> >
> > class Main:
> > value = 0
> > def count(self):
> > self.value += 1
> >
> > .
>
> I am still a Python beginner and didn't even believe that the student's
> solution would work. I had expected an error as the instance variable
> self.value was not initialized.

Remember: (1) x += 1 behaves like x = x + 1, and (2) bindings created
inside a class statement but outside any method create class attributes.

So after counter0 = Main(), Main (the class) has an attribute called
"value" whose value is 0, and counter0.value refers to that attribute.

Then counter0.count() executes self.value += 1, which behaves like
self.value = self.value + 1. The right side of that assignment
evaluates to 1 (the value of the class attribute plus the constant 1),
and then the assignment statement initializes self.value to *that*
value.

There's nothing special about initializing instance attributes in
__init__. An instance attribute can be created/initialized anywhere.

HTH,
Dan
--
https://mail.python.org/mailman/listinfo/python-list
Re: Class Definitions [ In reply to ]
On 11/14/2020 4:09 AM, Manfred Lotz wrote:
> On 11 Nov 2020 19:21:57 GMT
> ram@zedat.fu-berlin.de (Stefan Ram) wrote:
>
>> In my Python course I gave the assignment to define a
>> counter class "Main" so that
>>
>> counter0 = Main()
>> counter1 = Main()
>> counter1.count(); counter1.count(); counter1.count()
>> counter1.count(); counter1.count()
>> print( counter0.value )
>> print( counter1.value )
>>
>> would print
>>
>> 0
>> 5
>>
>> .
>>
>> I expected this solution:
>>
>> class Main:
>> def __init__( self ):
>> self.value = 0
>> def count( self ):
>> self.value += 1
>>
>> but a student turned in the following solution:
>>
>> class Main:
>> value = 0
>> def count(self):
>> self.value += 1
>>
>> .
>
> I am still a Python beginner and didn't even believe that the student's
> solution would work. I had expected an error as the instance variable
> self.value was not initialized.

It was not. But self.x as a value, rather than a target, first looks
for instance x, then class x, then superclass x, up to object.x. Such
lookup is routine for methods, much rarer for data.

self.value += 1 is roughly equivalent to
self.value = self.value +1 where the right self.value is Main.value.
'self' is only looked up once, but apparently the value attribute is
looked up twice, in spite of what one might think from the doc, so that
the first assignment to self.value initializes an instance value rather
than overwriting the class value.

--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list
Re: Class Definitions [ In reply to ]
On Sat, 14 Nov 2020 05:08:07 -0600
2QdxY4RzWzUUiLuE@potatochowder.com wrote:

> On 2020-11-14 at 10:09:32 +0100,
> Manfred Lotz <ml_news@posteo.de> wrote:
>
> > On 11 Nov 2020 19:21:57 GMT
> > ram@zedat.fu-berlin.de (Stefan Ram) wrote:
> >
> > > In my Python course I gave the assignment to define a
> > > counter class "Main" so that
> > >
> > > counter0 = Main()
> > > counter1 = Main()
> > > counter1.count(); counter1.count(); counter1.count()
> > > counter1.count(); counter1.count()
> > > print( counter0.value )
> > > print( counter1.value )
> > >
> > > would print
> > >
> > > 0
> > > 5
> > >
> > > .
> > >
> > > I expected this solution:
> > >
> > > class Main:
> > > def __init__( self ):
> > > self.value = 0
> > > def count( self ):
> > > self.value += 1
> > >
> > > but a student turned in the following solution:
> > >
> > > class Main:
> > > value = 0
> > > def count(self):
> > > self.value += 1
> > >
> > > .
> >
> > I am still a Python beginner and didn't even believe that the
> > student's solution would work. I had expected an error as the
> > instance variable self.value was not initialized.
>
> Remember: (1) x += 1 behaves like x = x + 1, and (2) bindings created
> inside a class statement but outside any method create class
> attributes.
>
> So after counter0 = Main(), Main (the class) has an attribute called
> "value" whose value is 0, and counter0.value refers to that attribute.
>
> Then counter0.count() executes self.value += 1, which behaves like
> self.value = self.value + 1. The right side of that assignment
> evaluates to 1 (the value of the class attribute plus the constant 1),
> and then the assignment statement initializes self.value to *that*
> value.
>
> There's nothing special about initializing instance attributes in
> __init__. An instance attribute can be created/initialized anywhere.
>
>

Thanks to you and Stefan.


I did not know that if an instance variable doesn't exist the same
name is searched for as a class variable.


--
Manfred

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