I would expect a result consistent with the fact that both times
b.a would refer to the same object.
class RedList(list):
colour = "red"
L = RedList(())
What behaviour would you expect from len(L), given that L doesn't have a
__len__ attribute?
It seems to me that you do.
You didn't appear to be objecting to a line like x = b.a assigning the
value of 1 to x (although perhaps you do). If that was the case, then it
is perfectly reasonable to expect b.a = x + 2 to store 3 into b.a, while
leaving b.__class__.a untouched.
Of course, if you object to inheritance, then you will object to x = b.a
as well.
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
That's an implementation detail only in the sense that "while condition"
is a loop is an implementation detail. It is a *design* detail.
b is a name, and any reference to b (in the same namespace) will refer
to the same object. At least until you rebind it to another object.
But b.a is not a name, it is an attribute lookup, and by Python's rules of
inheritance that lookup will look up attributes in the instance, the
class, and finally any superclasses.
If you persist in thinking of b.a as a name referring to a single object,
of course you will be confused by the behaviour. But that's not what
attribute lookup does.
On the right hand side of an assignment, it will return the first existing
of b.__dict__['a'] or b.__class__.__dict__['a']. On the left hand of an
assignment, it will store into b.__dict__['a'].
I think it even less sane, if the same occurce of b.a refers to two
different objects, like in b.a += 2
Then it seems to me you have some serious design problems. Which would you
prefer to happen?
# Scenario 1
# imaginary pseudo-Python code with no inheritance:
class Paragraph:
ls = '\n' # line separator
para = Paragraph()
para.ls
=> AttributeError - instance has no attribute 'ls'
# Scenario 2
# imaginary pseudo-Python code with special inheritance:
class Paragraph:
ls = '\n' # line separator
linux_para = Paragraph()
windows_para = Paragraph()
windows_para.ls = '\n\r' # magically assigns to the class attribute
linux_para.ls
=> prints '\n\r'
# Scenario 3
# Python code with standard inheritance:
class Paragraph:
ls = '\n' # line separator
linux_para = Paragraph()
windows_para = Paragraph()
windows_para.ls = '\n\r'
linux_para.ls
=> prints '\n'