Class Variable Access and Assignment

S

Steve Holden

Paul said:
Do you seriously think the number is larger than zero? Do you think
that's any good way to write code?
Well it would break the Medusa asyncore/asynchat-based server software,
so I can confidently predict the number would be greater than zero, yes.

Several fine programmers have relied on the (documented) behavior, I
suspect, as it's a convenient way to install per-instance defaults, for
example.
Examples of the weirdness have already been given. My favorite is the
one where b.a is a list instead of an integer, in which case the class
variable gets updated instead of an instance variable getting created.
If you don't find the inconsistency to be weird, then ducky for you.

Ho, hum.
 
S

Steven D'Aprano

And again this argument. Like it or leave it, as if one can't in general
like the language, without being blind for a number of shortcomings.

It is this kind of recations that make me think a number of people is
blindly devoted to the language to the point that any criticism of
the language becomes intollerable.

There are good usage cases for the current inheritance behaviour. I asked
before what usage case or cases you have for your desired behaviour, and
you haven't answered. Perhaps you missed the question? Perhaps you haven't
had a chance to reply yet? Or perhaps you have no usage case for the
behaviour you want.

Some things are a matter of taste: should CPython prefer <> or != for not
equal? Some things are a matter of objective fact: should CPython use a
byte-code compiler and virtual machine, or a 1970s style interpreter that
interprets the source code directly?

The behaviour you are calling "insane" is partly a matter of taste, but it
is mostly a matter of objective fact. I believe that the standard
model for inheritance that you call insane is rational because it is
useful in far more potential and actual pieces of code than the behaviour
you prefer -- and the designers of (almost?) all OO languages seem to
agree with me.

The standard behaviour makes it easy for code to do the right thing in
more cases, without the developer taking any special steps, and in the
few cases where it doesn't do the right thing (e.g. when the behaviour you
want is for all instances to share state) it is easy to work around. By
contrast, the behaviour you want seems to be of very limited usefulness,
and it makes it difficult to do the expected thing in almost all cases,
and work-arounds are complex and easy to get wrong.

The standard behaviour makes it easy for objects to inherit state, and
easy for them to over-ride defaults. The behaviour(s) you and Graham want
have awkward side-effects: your proposed behaviour would mean that class
attributes would mask instance attributes, or vice versa, meaning that
the programmer would have to jump through hoops to get common types of
behaviour like inheriting state.

The behaviour you want would make it too easy to inadvertently have
instances share state. Normally we want instances to share behaviour but
have unique states -- you would change that. Why? If it is just a matter
of taste, you are welcome to your opinion. But you don't say that the
standard behaviour is "ugly", you say it is "insane", that is, irrational,
and that the behaviour you want is rational.

That's an objective claim: please explain what makes your behaviour more
rational than the standard behaviour. Is your behaviour more useful? Does
it make code easier to write? Does it result in more compact code? What
usage cases?

Or is it just a subjective judgement on your part that it would be neater?
 
S

Steve Holden

Antoon said:
Op 2005-11-04, Steve Holden schreef <[email protected]>: [...]
I suppose ultimately I'm just more pragmatic than you.


It has nothing to do with being more pragmatic. Being pragmatic
is about how you handle things with real life projects. It has
little to do with the degree in which you agree with the design
of the tool you have to work with. I would say I am more pragmatic
than most defenders of python, because when it comes done to
do my work, I just use python as best as I can, while a lot
of people here seem to think that every little criticism I have
is enough to go and look for a different language.
No, being pragmatic is to do with accepting what is rather than wasting
time wishing it were otherwise, particularly when the "insane" behavior
was actually a deliberate design choice. Which is why it doesn't work
the same as non-local references in nested scopes.
So, people can probably say that about any language they started with.
That a language suits a certain persons brain, may say more about
the person than about the language.
I wasn't trying to make a point about the language. I was merely (and I
thought charitably) trying to explain why I appear to be blind to the
"insanity" you see all around you.

regards
Steve
 
A

Antoon Pardon

Op 2005-11-04 said:
There are good usage cases for the current inheritance behaviour. I asked
before what usage case or cases you have for your desired behaviour, and
you haven't answered. Perhaps you missed the question? Perhaps you haven't
had a chance to reply yet? Or perhaps you have no usage case for the
behaviour you want.

There are good use cases for a lot of things python doesn't provide.
There are good use cases for writable closures, but python doesn't
provide it, shrug, I can live with that. Use cases is a red herring
here.
Some things are a matter of taste: should CPython prefer <> or != for not
equal? Some things are a matter of objective fact: should CPython use a
byte-code compiler and virtual machine, or a 1970s style interpreter that
interprets the source code directly?

The behaviour you are calling "insane" is partly a matter of taste, but it
is mostly a matter of objective fact. I believe that the standard
model for inheritance that you call insane is rational because it is
useful in far more potential and actual pieces of code than the behaviour
you prefer -- and the designers of (almost?) all OO languages seem to
agree with me.

I didn't call the model for inheritance insane.
The standard behaviour makes it easy for code to do the right thing in
more cases, without the developer taking any special steps, and in the
few cases where it doesn't do the right thing (e.g. when the behaviour you
want is for all instances to share state) it is easy to work around. By
contrast, the behaviour you want seems to be of very limited usefulness,
and it makes it difficult to do the expected thing in almost all cases,
and work-arounds are complex and easy to get wrong.

Please don't make this about what I *want*. I don't want anything.
I just noted that one and the same reference can be processed
multiple times by the python machinery, resulting in that same
reference referencing differnt variables at the same time and
stated that that was unsane behaviour.
The standard behaviour makes it easy for objects to inherit state, and
easy for them to over-ride defaults. The behaviour(s) you and Graham want
have awkward side-effects: your proposed behaviour would mean that class
attributes would mask instance attributes, or vice versa, meaning that
the programmer would have to jump through hoops to get common types of
behaviour like inheriting state.

You don't know what I want. You only know that I have my criticism of
particular behaviour. You seem to have your idea about what the
alternative would be like, and project that to what I would want.
The behaviour you want would make it too easy to inadvertently have
instances share state. Normally we want instances to share behaviour but
have unique states -- you would change that. Why? If it is just a matter
of taste, you are welcome to your opinion. But you don't say that the
standard behaviour is "ugly", you say it is "insane", that is, irrational,
and that the behaviour you want is rational.

I called it unsane, not insane. I think I paid enough attention to never
use the word "insane", yes I once used "madness" but that was after you
were already all over me for this.

Even should I have used the word insane, I used it for a lot less than
you are implying.
That's an objective claim: please explain what makes your behaviour more
rational than the standard behaviour. Is your behaviour more useful? Does
it make code easier to write? Does it result in more compact code? What
usage cases?

What my behaviour? I don't need to specify alternative behaviour in
order to judge specific behaviour.
 
A

Antoon Pardon

Op 2005-11-04 said:
Antoon said:
Op 2005-11-04, Steve Holden schreef <[email protected]>: [...]
I suppose ultimately I'm just more pragmatic than you.


It has nothing to do with being more pragmatic. Being pragmatic
is about how you handle things with real life projects. It has
little to do with the degree in which you agree with the design
of the tool you have to work with. I would say I am more pragmatic
than most defenders of python, because when it comes done to
do my work, I just use python as best as I can, while a lot
of people here seem to think that every little criticism I have
is enough to go and look for a different language.
No, being pragmatic is to do with accepting what is rather than wasting
time wishing it were otherwise,

Just accepting what is, is not pragmatic. Not much progress would have
been made if we just accepted what is.
particularly when the "insane" behavior
was actually a deliberate design choice. Which is why it doesn't work
the same as non-local references in nested scopes.

That b.a = b.a + 2

works as a result of a design choice, that I can accept.

But IMO b.a += 2, working as it does, is more the result of
earlier design and implementation decisions than it was
a deliberate design decision.
 
P

Paul Rubin

Steven D'Aprano said:
There are good usage cases for the current inheritance behaviour.

Can you name one? Any code that relies on it seems extremely dangerous to me.
 
M

Magnus Lycka

Antoon said:
Would it be too much to ask that in a line like.

x = x + 1.

both x's would resolve to the same namespace?

They always do Antoon. There is no such issue for
local (or global) varibles. The issue has to do
with c.x = c.x + 1. In this case it's clearly
designed and documented that this corresponds to:

setattr(c, 'x', getattr(c, 'x') + 1)

The result of these operations depends on e.g.
how the __setattr__ and __getattr__ methods in
the class in question are defined.

You need to understand that the dot-operaterator
always involves a lookup-operation that can be
implemented in various ways.

It's well defined that you can do things like:
.... c=0
.... def __call__(self):
.... self.c+=1
.... def __str__(self):
.... return str(self.c)
........ c=5
....6

Of course, you could design a language, say Pythoon
or Parthon, where this is illegal, and you force the
programmer to do something longer such as:
.... c=0
.... def __init__(self):
.... self.c = self.__class__.c
.... def __call__(self):
.... self.c+=1
.... def __str__(self):
.... return str(self.c)
....

I don't see this as an improvement though...
 
A

Antoon Pardon

Op 2005-11-04 said:
They always do Antoon. There is no such issue for
local (or global) varibles.

I meant those 'x' do be any general expression
that refers to an object. Like

a.b[c.f] = a.b[c.f] + 1
The issue has to do
with c.x = c.x + 1. In this case it's clearly
designed and documented that this corresponds to:

setattr(c, 'x', getattr(c, 'x') + 1)

The issue is with c.x += 1

Sure I find the fact that the same reference two
times in the same line can reference variable
in two different namespaces ugly.

But that one single reference refers to two
variables in two different namespaces that is
IMO more than ugly.

Suppose I have the following:

class I:
def __init__(self):
self.v = 0
def __call__(self):
t = self.v
self.v += 1
return t

i = I()
lst = range(10)
lst[i()] += 20

Nobody seems to find that this should be treated
exactly the same as
lst[i()] = lst[i()] + 20

People seem to think since lst[i()] only occurs
once, it should be only refering to one entity.

Well I think the same kind of reasoning can apply
to c.x += 1.
The result of these operations depends on e.g.
how the __setattr__ and __getattr__ methods in
the class in question are defined.

You need to understand that the dot-operaterator
always involves a lookup-operation that can be
implemented in various ways.

But there is no reason that two dot-operator are
executed when only one dot-operator is in the text.

Just as there is no reason that two i() calls
should be made when only one call is in the text.
It's well defined that you can do things like:

... c=0
... def __call__(self):
... self.c+=1
... def __str__(self):
... return str(self.c)
...
... c=5
...
6

Of course, you could design a language, say Pythoon
or Parthon, where this is illegal, and you force the
programmer to do something longer such as:

... c=0
... def __init__(self):
... self.c = self.__class__.c
... def __call__(self):
... self.c+=1
... def __str__(self):
... return str(self.c)
...

I don't see this as an improvement though...

Well I thought in python explicit was better than
implicit.
 
C

Christopher Subich

Antoon said:
And again this argument. Like it or leave it, as if one can't in general
like the language, without being blind for a number of shortcomings.

It is this kind of recations that make me think a number of people is
blindly devoted to the language to the point that any criticism of
the language becomes intollerable.

No, it's just that a goodly number of people actually -like- the
relatively simple conceputal model of Python.

Why /shouldn't/

correspond exactly to

Similarly, why shouldn't

correspond exactly to

With that in mind, the logical action for

and since

is equal to

why shouldn't this translate into

Looking at it this way, it's obvious that the setattr and getattr may do
different things, if the programmer understands that "instances (can)
look up object attributes, and (always) set instance attributes." In
fact, it is always the case (so far as I can quickly check) that += ends
up setting an instance attribute. Consider this code:
>>> class foo:
>>> x = [5]
>>> a = foo()
>>> a += [6]
>>> a.x [5,6]
>>> foo.x [5,6]
>>> foo.x = [7]
>>> a.x
[5,6]

In truth, this all does make perfect sense -- if you consider class
variables mostly good for "setting defaults" on instances.
 
C

Christopher Subich

Steven said:
Because b.a += 2 expands to b.a = b.a + 2. Why would you want b.a =
<something> to correspond to b.__class__.a = <something>?

Small correction, it expands to b.a = B.a.__class__.__iadd__(b.a,2),
assuming all relevant quantities are defined. For integers, you're
perfectly right.
 
A

Antoon Pardon

Op 2005-11-04 said:
No, it's just that a goodly number of people actually -like- the
relatively simple conceputal model of Python.

Why /shouldn't/


correspond exactly to


Similarly, why shouldn't


correspond exactly to


With that in mind, the logical action for


and since


is equal to


why shouldn't this translate into

Well maybe because as far as I understand the same kind of logic
can be applied to something like

lst[f()] += foo

In order to decide that this should be equivallent to

lst[f()] = lst[f()] + foo.

But that isn't the case.

So it seems applying augmented operators is not a matter of just
substituting straight translations to get the right result.

Looking at it this way, it's obvious that the setattr and getattr may do
different things, if the programmer understands that "instances (can)
look up object attributes, and (always) set instance attributes." In
fact, it is always the case (so far as I can quickly check) that += ends
up setting an instance attribute. Consider this code:

Looking at lists in a similar way, it would be obvious that the
__setitem__ and __getitem__ can do different things and so we
should expect lst[f()] += foo to behave exactly as lst[f()] = lst[f()] +
foo.
 
A

Antoon Pardon

Op 2005-11-04 said:
Antoon said:
Op 2005-11-03 said:
The model makes sense in my opinion. If you don't like it then there are
plenty of other languages to choose from that have decided to implement
things differently.
class foo:
x = [5]
a = foo()
a += [6]
a.x [5,6]
foo.x [5,6]
foo.x = [7]
a.x
[5,6]

In truth, this all does make perfect sense -- if you consider class
variables mostly good for "setting defaults" on instances.

Except when your default is a list

class foo:
x = [] # default

a = foo()
a.x += [3]

b = foo()
b.x

This results in [3]. So in this case using a class variable x to
provide a default empty list doesn't work out in combination
with augmented operators.

This however would work:

class foo:
x = [] # default

a = foo()
a.x = a.x + [3]

b = foo()
b.x

This results in []
 
M

Magnus Lycka

Graham said:
My question remains however, i suppose i'm not familiar with how this
functions in
other languages, but what is the common way of referring to a class
variable.

is <class>.<var> the norm?
or <instance>.<var> the norm.

It's not always that easy, due to inheritance. You might want
the <var> defined in the class where a method you define now
is implemented (A.<var> if we're in a method defined in class A),
or you might want <var> in the class of the instance object
(which could be a subclass of A). You can get that through
self.__class__.<var>, so I guess you could always manage without
Python searching in the class scope after searching the instance
scope, if it wasn't for the problem below...
I just seems to me that <instance>.<var> shouldn't defer to the class
variable if
an instance variable of the same name does not exists, it should, at
least how i
understand it raise an exception.

So, you want this:
.... def f(self):
.... print 'Hello'
....Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: A instance has no attribute 'f'

A bit boring that we need to make method calls
with a.__class__.f(a) in your Python...

Python is more consistent than you have thought...
You know, it could be that we want to assign the
method to another variable, as in:

o = A()
o_f = o.f # This might look as I'm getting a normal
# attribute, but f is a method
for i in range(gazillion):
o_f() # This is slightly faster than o.f()

Or, we might want to do:
o.f=len
o.f('Hello')

Here, o.f is no longer a method in o's class hierarchy, but
it's still callable.

If you think about it, you'll understand that in such a dynamic
language as Python, there is no way that the interpreter can
know before lookup whether it will find a method or a simple
attribute. If it's going to look in different places depending
on what it will find when it has looked...we have a Catch 22.

Normal methods in Python are defined in the scope of the class,
and they are passed the instance object as their first argument
when they are called. The call (where the instance object is
implicitly called in case of a bound method) is something that
comes after the lookup, as you can see in the a_f() example.

Python is *very* dynamic. The behaviour of the class can change
after the instance has been created.
.... def f(self):
.... print 'Hello'
....Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: A instance has no attribute 'f'

How would this work if 'a.f' doesn't cause a lookup in A if it's
missing in a? Do you want a.f to first search the instance a, then
the class A, and if it finds f in A, issue an AttributeError if it
turns out that f isn't a method?
 
S

Steven D'Aprano

Since AFAICT there is no single reference to the __len__ attribute that
will be resolved to two different namespace I don't see the relevance.

Compare:

b.a += 2

Before the assignment, instance b does not have an attribute "a", so class
attribute "a" is accessed. You seem to be objecting to this inheritance.

len(L) => L.__len__()

Instance L also does not have an attribute "__len__", so class attribute
"__len__" is accessed. You don't appear to object to this inheritance.

Why object to one and not the other?

If you object to b.a resolving to b.__class__.a, why don't you object to
L.__len__ resolving to L.__class__.__len__ also?

Perhaps you don't object to that half of the problem. Perhaps you object
to the assignment: you expect that assigning to b.a should assign to
b.__class__.a instead.

Should assigning to L[0] assign to L.__class__[0] also, so that all
lists share not only the same behaviour, but also the same data?


[snip]
But some namespaces take great care not to allow a rebinding that would
result in the same name being resolved to a different namespace during
this namespace's lifetime.

And some take great care to allow such a rebinding, because that is the
right thing to do to make inheritance work correctly.

An other implementation detail. b.a is a name search of 'a' in the
namespace b.

Factually incorrect. b.a is the name search for 'a' in the namespaces
[note plural] of b, b.__class__, and any superclasses of b, *in that order*.

Do you object to import searching multiple directories?

Why do you object to attribute resolution searching multiple namespaces?


[snip]
I don't see the relevance of these pieces of code. In none of them is
there an occurence of an attribute lookup of the same attribute that
resolves to different namespaces.

Look a little more closely. In all three pieces of code, you have a
conflict between the class attribute 'ls' and an instance attribute 'ls'.

In the first scenario, that conflict is resolved by insisting that
instances explicitly define an attribute, in other words, by making
instance attribute ONLY search the instance namespace and not the class
namespace.

In the second scenario, that conflict is resolved by insisting that
instance.name assigns to instance.__class__.name, just as you asked for.

The third scenario is the way Python actually operates.
 
C

Christopher Subich

Antoon said:
You are now talking implementation details. I don't care about whatever
explanation you give in terms of implementation details. I don't think
it is sane that in a language multiple occurence of something like b.a
in the same line can refer to different objects

This isn't an implementation detail; to leading order, anything that
impacts the values of objects attached to names is a specification issue.

An implementation detail is something like when garbage collection
actually happens; what happens to:

b.a += 2

is very much within the language specification. Indeed, the language
specification dictates that an instance variable b.a is created if one
didn't exist before; this is true no matter if type(b.a) == int, or if
b.a is some esoteric mutable object that just happens to define
__iadd__(self,type(other) == int).
 
C

Christopher Subich

Antoon said:
Well I wonder. Would the following code be considered a name binding
operation:

b.a = 5

Try it, it's not.

Python 2.2.3 (#1, Nov 12 2004, 13:02:04)
[GCC 3.2.3 20030502 (Red Hat Linux 3.2.3-42)] on linux2
Type "help", "copyright", "credits" or "license" for more information.Traceback (most recent call last):
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'object' object has no attribute 'a'

Once it's attached to an object, it's an attribute, not a base name.
The distinction is subtle and possibly something that could (should?) be
unified for Py3k, but in cases like this the distinction is important.
 
M

Magnus Lycka

Antoon said:
> I have looked and didn't find it in the language reference.

This is what I have found:

An augmented assignment expression like x += 1 can be rewritten
as x = x + 1 to achieve a similar, but not exactly equal effect.

It's just a little further down. I'll post the quote once more (but
this is the last time ;^):

"""For targets which are attribute references, the initial value is
retrieved with a getattr() and the result is assigned with a setattr().
Notice that the two methods do not necessarily refer to the same
variable. When getattr() refers to a class variable, setattr() still
writes to an instance variable. For example:

class A:
x = 3 # class variable
a = A()
a.x += 1 # writes a.x as 4 leaving A.x as 3"""

I'd say it's documented...
That doesn't change the fact that the current behaviour is
on occasions awkward or whatever you want to call it.

I fear that this has to do with the way reality works. Perhaps
it's due to Gödel's incompleteness theorems... :)

Sure, Python has evolved and grown for about 15 years, and
backward compatibility has always been an issue, but the
management and development of Python is dynamic and fairly
open-minded. If there had been an obvious way to change this
in a way that solved more problems than it caused, I suspect
that change would have happened already.
I also find that people underestimate the magic that
is going on in python. But just because you are familiar with
the magic, doesn't make it less magic. IMO python shows its
history a little.

If Guido would design a new language today, that was aiming at
the kind of tasks Python solves, I'm sure it wouldn't be identical
to the current Python. The languages I'm most experienced in besides
Python are C++ and SQL. Compared to those beasts, Python is a wonder
in clarity and consistency. I don't think a single vendor has managed
to fully implement the SQL standard, and it's known that the standard
contains bugs, inconsitencies and gaps, even though (or because) it's
been worked on for more than 20 years. The C++ spec is marginally
better. Of course, there isn't a formal specification for Python. I
don't know if the language reference is so complete that someone
could actually write another really compatible Python implementation
based on just the reference manual. Still the difference is drastic.
I suspect that only few people in the SQL standard committee fully
understand the spec (maybe C.J. Date and Hugh Darwen does) and all
the things happening under the hood in C++ is staggering, considering
that this language is really just a fancy assmbler that can't even
manage memory for the programmer!
I'm after nothing particular. The only thing I'm frustrated about
is the way in which some people seem willing to defend python
just because it is python. If the only reaction I would have
gotten would have been something like: Yeah that seems a bit
awkward but fixing this would break more than it would cure,
I would have left it as it is.

That's probably what most people think, but we're not entirely
rational. We're human. An emotional posting will probably attract
equally emotional responses.
I have rarely indicated I wanted things to be fixed. Sure I would
like it if some things were different, but I recognize that there
are more important things that needs to be resolved.

Does that mean I shouldn't mention things that IMO could have been
better or that I should only mention them in the softest of
language that certainly can't be interpreted as emotional language.

Personally, I want comp.lang.python to work as a way for me to learn
new things about Python, to get help if I'm stuck with something, and
as a way for me to inform others about Python stuff. It's also a part
of the Python community--an arena where I communicate with other
Pythonistas. This is something important for me, both professionally
and personally. I try to think an extra time before I post messages.
It this message meaningful? Does it add anything of value? Am I just
repeating what is already said? Is this message likely to have some
kind of positive impact or will it just be ignored? Might I hurt
someone? Am I building useful relationships?

When it works as it should, people you've never met before will buy
you beer or lunch when you happen to be in their neighbourhood. At
least they might come up to you and chat if you go to a Python
conference. They might also offer you jobs or contracts etc. This
is really nice and valuable. Something to handle with care.
 
C

Christopher Subich

Antoon said:
Except when your default is a list

class foo:
x = [] # default

a = foo()
a.x += [3]

b = foo()
b.x

This results in [3]. So in this case using a class variable x to
provide a default empty list doesn't work out in combination
with augmented operators.

This has nothing to do with namespacing at all, it's the Python
idiosyncracy about operations on mutable types. In this case, +=
mutates an object, while + returns a new one -- as by definition, for
mutables.
 
C

Christopher Subich

Antoon said:
Well maybe because as far as I understand the same kind of logic
can be applied to something like

lst[f()] += foo

In order to decide that this should be equivallent to

lst[f()] = lst[f()] + foo.

But that isn't the case.

Because, surprisingly enough, Python tends to evaluate expressions only
once each time they're invoked.

In this case, [] is being used to get an item and set an item --
therefore, it /has/ to be invoked twice -- once for __getitem__, and
once for __setitem__.

Likewises, lst appears once, and it is used once -- the name gets looked
up once (which leads to a += 1 problems if a is in an outer scope).

f() also appears once -- so to evaluate it more trhan one time is odd,
at best.

If you know very much about modern lisps, it's similar to the difference
between a defun and a defmacro.
 
S

Steve Holden

Antoon said:
Op 2005-11-04 said:
Antoon said:
Op 2005-11-04, Steve Holden schreef <[email protected]>:
[...]

I suppose ultimately I'm just more pragmatic than you.


It has nothing to do with being more pragmatic. Being pragmatic
is about how you handle things with real life projects. It has
little to do with the degree in which you agree with the design
of the tool you have to work with. I would say I am more pragmatic
than most defenders of python, because when it comes done to
do my work, I just use python as best as I can, while a lot
of people here seem to think that every little criticism I have
is enough to go and look for a different language.

No, being pragmatic is to do with accepting what is rather than wasting
time wishing it were otherwise,


Just accepting what is, is not pragmatic. Not much progress would have
been made if we just accepted what is.
Pragmatically, I accept that whatever I say you are likely to respond
with a nit-picking argument. Pragmatically I accept this situation for
what it is. This does not stop me imagining a world where our dialogues
are about meaningful issues rather than whether a particular facet of
Python's design is "unsane". Pragmatically I accept that such a world is
likely to exist only in my imagination.
That b.a = b.a + 2

works as a result of a design choice, that I can accept.

But IMO b.a += 2, working as it does, is more the result of
earlier design and implementation decisions than it was
a deliberate design decision.
You are wrong.

regards
Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,219
Latest member
KristieKoh

Latest Threads

Top