Re: Class Variable Access and Assignment

2005-11-08 Thread Magnus Lycka
Antoon Pardon wrote:
 Fine that goes both ways. I don't mind not being taken serious by people
 I have trouble taking serious my self. No doubt that goes for you too.

You know Antoon, these internet communities aren't really like
Speaker Corner in Hyde Park. You earn respect based on your merits,
not from the stubborn persistence in you arguments.

Steve has written a very good book on Python, he's worked a lot
with Python conferences, and helped people on comp.lang.python
for years etc. He has earned his respect.

You are fighting wind mills, bickering about things that you
don't have any solutions for. It's possible that you have just
not realized how Python handles objects, names and classes, but I
can't understand what you are trying to accomplish. What can you
possibly try to convey that you haven't already stated? It's
as if you've got stuck in this thread. In the real world, I
haven't heard of anyone ever having had problems with this.

Isn't it better to let it go and to spend your time on something
constructive?

I recently heard a priest say, that the difference between the
saint and the fanatic is that the fanatic tries to remove the
evil in the world, while the saint tries to remove the evil in
himself.

Just as introspection is useful both in fighting evil and in
Python programming, I think it's useful when we get into heated
discussions. I've always loved heated discussions, but over time,
I've come to realize that the best thing that can happen in such
a discussion is to realize that I was wrong. Then I've learnt
something! If I don't change my mind, I'm just standing still.
In that case, it might be useful for someone else, if she or he
learnt something from it, but the best thing is if I learn
something.

This thread is all to infected to lead to good things. Hopefully
you'll learn something about communication from it, but the price
has been higher than you might be aware of right now.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-08 Thread Antoon Pardon
Op 2005-11-08, Magnus Lycka schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 Fine that goes both ways. I don't mind not being taken serious by people
 I have trouble taking serious my self. No doubt that goes for you too.

 You know Antoon, these internet communities aren't really like
 Speaker Corner in Hyde Park. You earn respect based on your merits,
 not from the stubborn persistence in you arguments.

 Steve has written a very good book on Python, he's worked a lot
 with Python conferences, and helped people on comp.lang.python
 for years etc. He has earned his respect.

So? Steve can be very good at explaining what python is and
how it behaves and at the same time have poor arguments why
this would be good langauge design.

So although he may have earned his respect in the first,
that doesn't mean I have to take him seriously in the
other.

 You are fighting wind mills, bickering about things that you
 don't have any solutions for.

People should know what they want. If one dares to propose
an alternative here, chances are that you get told to
search a language that behaves as you want, if you don't
you get blamed you don't have a solution.

The only acceptable behaviour, seems to keep quiet about
things where one thinks python could be improved.

 It's possible that you have just
 not realized how Python handles objects, names and classes, but I
 can't understand what you are trying to accomplish. What can you
 possibly try to convey that you haven't already stated? It's
 as if you've got stuck in this thread. In the real world, I
 haven't heard of anyone ever having had problems with this.

Well in the real world nobody seemed to have problems with
the lack of a condtional expression either. Each time someone
brought it up, they were told it wasn't necessary anyway and
how you could simulate it, with some caveat, by using 'and'
and 'or'.

Until it seems one of the developers got bitten by an elusive
bug caused by such a caveat and suddenly there will be a
condional expression in the next version.

So, that we haven't heard of anyone ever having a problem
with it doesn't contradict, that it may one day be the
cause of a very elusive bug.

 This thread is all to infected to lead to good things. Hopefully
 you'll learn something about communication from it, but the price
 has been higher than you might be aware of right now.

Shrug, this is usenet, not my social life.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-04, Christopher Subich schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:

 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,

Yes it has.

 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.

It is the combination of the two.

If python had chosen for an approach like function namespaces, the
problem wouldn't have occured either. What would have happened then
is that the compilor would have noticed the a.x on the right hand
side and based on that fact would then have deciced that all a.x
references should be instance reference (at least in that function
block). The a.x += ... would then result in an AttributeError being raised. 

You may prefer the current behaviour over this, but that is not the
point. The point is that resolution of name spaces does play its
role in this problem.


It also has little to do with mutable vs immutable types.
Someone could implement an immutable type, but take advantage
of some implemtation details to change the value inplace
in the __iadd__ method. Such an immutable type would show
the same problems.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-04, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Fri, 04 Nov 2005 09:03:56 +, Antoon Pardon wrote:

 Op 2005-11-03, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Thu, 03 Nov 2005 13:01:40 +, Antoon Pardon wrote:

 Seems perfectly sane to me. 

 What would you expect to get if you wrote b.a = b.a + 2?
 
 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?
 
 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.

I object to the inheritance in a scope where b.a also refers to the
instance.

If there is no problem that a reference can refer to different objects
in the same scope, then the following should work too.

a = 0
def f():
  a += 2

One can reason just the same that before the assignment f doesn't have
a local variable yet, so the global should be accessed. People who
don't agree don't want functions to have access to outer scope
variables.

 Do you object to import searching multiple directories?

 Why do you object to attribute resolution searching multiple namespaces?

I don't.

 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'.

No you look a little more clearly.

 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.

No it isn't. You seem unable to make a difference between a resolution
in general, and a resolution in a scope where an assignment has been
made.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-04, Christopher Subich schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 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.
  a
 Traceback (most recent call last):
File stdin, line 1, in ?
 NameError: name 'a' is not defined
  b = object()
  b.a
 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. 

So? It is still a name and it gets bound to an object. Sure the name
is bound within a specific namespace but that is IMO a detail.

 unified for Py3k, but in cases like this the distinction is important.

But part of this dicussion is about the sanity of making these kind
of distinctions. Since they apparantly plan to get rid of them in
Py3k, I guess I'm not the only one questioning that.

-- 
Antoon Pardon

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


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-04, Magnus Lycka schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
   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 ;^):

I appreciate you quoting the documentation. But I would appreciate
a URL even more. It isn't necessary now any more but it would have
been usefull the first time you quoted this material.

 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...

Well then I guess they have documented awkward behaviour.

 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.

Fine I can live with that. 

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-04, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Fri, 04 Nov 2005 08:08:42 +, Antoon Pardon wrote:

 One other way, to implement the += and likewise operators would be
 something like the following.
 
 Assume a getnsattr, which would work like getattr, but would also
 return the namespace where the name was found. The implementation
 of b.a += 2 could then be something like:
 
   ns, t = getnsattr(b, 'a')
   t = t + 2
   setattr(ns, 'a')
 
 
 I'm not arguing that this is how it should be implemented. Just
 showing the implication doesn't follow.

 Follow the logical implications of this proposed behaviour.

 class Game:
 current_level = 1
 # by default, games start at level one  
 
 def advance(self):
 self.current_level += 1


 py antoon_game = Game()
 py steve_game = Game()
 py steve_game.advance()
 py steve_game.advance()
 py print steve_game.level
 3
 py print antoon_game.level

 What will it print?

 Hint: your scheme means that class attributes mask instance attributes.

So? This proposal was not meant to replace the current behaviour.
It was meant to contradict your assertion that some particular
behaviour implied mutable numbers.

My proposal was an example that showed the particular behaviour and
didn't require mutable numbers, so it showed your assertion false.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-04, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Fri, 04 Nov 2005 09:07:38 +, Antoon Pardon wrote:

 Now the b.a on the right hand side refers to A.a the first time through
 the loop but not the next times. I don't think it is sane that which
 object is refered to depends on how many times you already went through
 the loop.

 [snip]

 Look at that: the object which is referred to depends on how many times
 you've already been through the loop. How nuts is that?
 
 It is each time the 'x' from the same name space. In the code above the
 'a' is not each time from the same namespace.
 
 I also think you new very well what I meant.

 I'm supposed to be a mindreader now? After you've spent multiple posts
 ranting that, quote, I don't think it is sane that which object is
 refered to depends on how many times you already went through the loop,
 I'm supposed to magically read your mind and know that you don't actually
 object to what you say you object to, but to something completely
 different?

No I meant object when I wrote object. But it is not about the object,
it is about the being refered to. And how do you refer to objects,
by names in namespace or variables.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-04, Christopher Subich schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 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.

Well but once can consider b.a as an expression too. An expression
that gets evaluated twice in case of

b.a += 2

 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__.

But we are here questioning language design. One could question a design
where it is necessary to invoke the [] operator twice, even when it
is only mentioned once in the code.

 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 than one time is odd, 
 at best.

No more or less than [] or . is to be invoked twice. 

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-06, Steve Holden schreef [EMAIL PROTECTED]:
 Steven D'Aprano wrote:
 [...]
 
 But I can't understand the position of folks who want inheritance but
 don't want the behaviour that Python currently exhibits.
 instance.attribute sometimes reading from the class attribute is a feature
 of inheritance; instance.attribute always writing to the instance is a
 feature of OOP; instance.attribute sometimes writing to the instance and
 sometimes writing to the class would be, in my opinion, not just a wart
 but a full-blown misfeature.
 
 I ask and I ask and I ask for some use of this proposed behaviour, and
 nobody is either willing or able to tell me where how or why it would be
 useful. What should I conclude from this?
 
 

 You should conclude that some readers of this group are happier 
 designing languages with theoretical purity completely disconnected from 
 users' needs. But of course we pragmatists know that practicality beats 
 purity :-)

But explicit is better than implicit.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-04, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Fri, 04 Nov 2005 10:48:54 +, Antoon Pardon wrote:

 Please explain why this is illegal.
 
 x = 1
 def f():
   x += 1

 Because names in function namespaces don't have inheritance.

Your quibling about words. This certainly works. 

x = 1
def f():
  a = x + 1

So you could say that function namespaces do inherit from
outer scopes.

Whether you want to name it inheritance or not, is not the
issue.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-05, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Fri, 04 Nov 2005 12:10:11 +, Antoon Pardon wrote:

 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.

 Is that a round-about way of saying that you really have no idea of
 whether, how or when your proposed behaviour would be useful?

I am not proposing specific behaviour. Because if I do, you will
just try to argue how much worst my proposed behaviour is.

Whether or not I can come up with a better proposal is irrelevant
to how sane the current behaviour is.

 Personally, I think that when you are proposing a major change to a
 language that would break the way inheritance works, there should be more
 benefits to the new way than the old way. 

How many times do I have to repeat myself. I'm not proposing a change
to the language. 

 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.

 Antoon, I've been pedanted at by experts, and you ain't one. The behaviour
 which you repeatedly described as not sane implements the model for
 inheritance. The fact that you never explicitly said the standard OO
 model of inheritance cuts no ice with me, not when you've written
 multiple posts saying that the behaviour of that standard inheritance
 model is not sane.

I haven't written that once. You may think that you can imply it from
what I wrote, but then that is your inferance and not my words.

 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.

 Unsane now?

 Heaven forbid that I should criticise people for inventing new words, but
 how precisely is unsane different from insane? In standard English,
 something which is not sane is insane.

Well maybe English works differently from dutch, but I thought there
were a whole lot of gradation between sane and insane. And not being
sane IMO just means not being at one end of the extreme while being
insane meant to be at the other end of the extreme.

So when something doesn't make complete sense, instead of it making
no sense at all, I would think that wording it as unsane instead of
insane resembles best what I intended to mean.

 If you're just trolling, you've done a great job of it because you fooled
 me well and good. But if you are serious in your criticism about the
 behaviour, then stop mucking about and tell us what the behaviour should
 be. Otherwise your criticism isn't going to have any practical effect on
 the language at all.

I wasn't trolling. I just threw in an off hand remark. That you got so
heated up about that remark is not my responsibility. I'm not trolling
because I'm willing to defend my remark and I don't intend to get
people to get heated up about it. I just don't hold back because
people may get heated up about it.

 If you are serious about wanting the behaviour changed, and not just
 whining, then somebody has to come up with an alternative behaviour that
 is better.

If I would be whining I would want the behaviour changed. I would just
keep complaining about it until someone else would have changed it.

Sure I would prefer it changed, but it is not that I *want* it to
change. I'll happily continue with python if it doesn't change.

Maybe when someone 

Re: Class Variable Access and Assignment

2005-11-07 Thread Magnus Lycka
First of all, I've still not heard any sensible suggestions
about a saner behaviour for augmented assignment or for the
way Python searches the class scope after the instance scope.

What do you suggest?

Today, x += n acts just as x = x + n if x is immutable.
Do you suggest that this should change?

Today, instance.var will look for var in the class
scope if it didn't find it in the instance scope. Do
you propose to change this?

Or, do you propose that we should have some second order
effect that makes the combination of instance.var += n
work in such a way that these features are no longer
orthogonal?

Paul Rubin wrote:
 Steven D'Aprano [EMAIL PROTECTED] writes:
 
A basic usage case:

class Paper:
size = A4
def __init__(self, contents):
# it makes no sense to have class contents,
# so contents go straight into the instance
self.contents = contents
 
 
 So add:
 
  self.size = Paper.size
 
 and you've removed the weirdness.  What do you gain here by inheriting?

class LetterPaper(Paper):
 size = Letter

class LegalPaper(Paper):
 size = Legal

This is what you gain. Subclassing it extremely simple, if all
you want is that the subclass differs in data. You could also
have __init__ pick up the class variable and set an instance
variable, but why make things difficult if it's trivial now?

Considering how __init__ works in Python class hierachies,
where you need to manually call __init__ in ancestor classes
if you've overridden them, the fact that a simple self.size
picks up a class variable is particularly useful if you use
MI. For instance I could imagine a FirstPageMixin class in
this case, and a FancyFirstPageMixin that subclasses that.
There, we might want to pick up certain margin values or
other positions etc.

The spirit of Python is to make it easy to do things right,
not make it difficult to make mistakes. If you want a language
that tries to prevent you from making mistakes, use Ada.

When developing code in a dynamic language such as Python,
it's really important to have a decent set of automated tests.
If you have, you'll hopefully notice bugs like these. Making
changes in the language that forces you to write more code
will in general not reduce the total number of bugs, but
rather increase them.

I've been involved with high reliability design long enough to
know the problems involved fairly well. I mainly worked with
electronic design then, but the problem is the same: The more
safety gadgets you add, the more stuff you have that can break.
The details are a bit difference, but in principle the problem
is the same.

Ever wondered why Russian and Chinese rocket launchers have a
better reliability than the American? Simply put, they're simpler.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Steve Holden
Antoon Pardon wrote:
 Op 2005-11-05, Steven D'Aprano schreef [EMAIL PROTECTED]:
 
On Fri, 04 Nov 2005 12:10:11 +, Antoon Pardon wrote:


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.

Is that a round-about way of saying that you really have no idea of
whether, how or when your proposed behaviour would be useful?
 
 
 I am not proposing specific behaviour. Because if I do, you will
 just try to argue how much worst my proposed behaviour is.
 
 Whether or not I can come up with a better proposal is irrelevant
 to how sane the current behaviour is.
 
If you can't provide a superior alternative then you have little right 
to be questioning the present behavior. Honestly, you are like a child 
with a whistle who keeps blowing the whistle to the annoyance of all 
around it simply because it likes being able to make the noise, and 
causing the annoyance.
 
Personally, I think that when you are proposing a major change to a
language that would break the way inheritance works, there should be more
benefits to the new way than the old way. 
 
 
 How many times do I have to repeat myself. I'm not proposing a change
 to the language. 
 
So you have a clear impression that Python's current behavior is 
unsatisfactory enough to be called unsane which, when challenged, you 
insist simply means not at the extreme end of some imaginary sanity 
scale you have constructed for the purpose if bending English to your 
will. And you refuse to propose anything further towards the sane end of 
the scale because people will try to argue that your proposal would be 
worse than the existing behavior. Good grief, I though I was dealing 
with an adult here, but I must be mistaken.
 
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.

Well you are repeatedly call one aspect of the Python inheritance model 
insane. You appear to feel that repetition of an argument will make it 
more true, which is sadly not the case.

Antoon, I've been pedanted at by experts, and you ain't one. The behaviour
which you repeatedly described as not sane implements the model for
inheritance. The fact that you never explicitly said the standard OO
model of inheritance cuts no ice with me, not when you've written
multiple posts saying that the behaviour of that standard inheritance
model is not sane.
 
 
 I haven't written that once. You may think that you can imply it from
 what I wrote, but then that is your inferance and not my words.
 
Nonsense.
 
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.

But you clearly don't perceive this as being related to Python's 
inheritance mechanism, presumably because you aren't prepared to accept 
that an instance inherits names from its class just like a class 
inherits names from its superclass.

Unsane now?

Heaven forbid that I should criticise people for inventing new words, but
how precisely is unsane different from insane? In standard English,
something which is not sane is insane.
 
 
 Well maybe English works differently from dutch, but I thought there
 were a whole lot of gradation between sane and insane. And not being
 sane IMO just means not being at one end of the extreme while being
 insane meant to be at the 

Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-07, Steve Holden schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 Op 2005-11-05, Steven D'Aprano schreef [EMAIL PROTECTED]:
 
On Fri, 04 Nov 2005 12:10:11 +, Antoon Pardon wrote:


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.

Is that a round-about way of saying that you really have no idea of
whether, how or when your proposed behaviour would be useful?
 
 
 I am not proposing specific behaviour. Because if I do, you will
 just try to argue how much worst my proposed behaviour is.
 
 Whether or not I can come up with a better proposal is irrelevant
 to how sane the current behaviour is.
 
 If you can't provide a superior alternative then you have little right 
 to be questioning the present behavior.

Nonesense. Unable to produce a superior alternative doesn't make
one unable to evaluate.

Personally, I think that when you are proposing a major change to a
language that would break the way inheritance works, there should be more
benefits to the new way than the old way. 
 
 
 How many times do I have to repeat myself. I'm not proposing a change
 to the language. 
 
 So you have a clear impression that Python's current behavior is 
 unsatisfactory enough to be called unsane which,

You are generalizing my words to the point they no longer 
reasonably resemble what I wrote. 

 
If you're just trolling, you've done a great job of it because you fooled
me well and good. But if you are serious in your criticism about the
behaviour, then stop mucking about and tell us what the behaviour should
be. Otherwise your criticism isn't going to have any practical effect on
the language at all.
 
 I wasn't trolling. I just threw in an off hand remark. That you got so
 heated up about that remark is not my responsibility. I'm not trolling
 because I'm willing to defend my remark and I don't intend to get
 people to get heated up about it. I just don't hold back because
 people may get heated up about it.
 
 The defense of your original remark implies very strongly that it wasn't 
 offhand, and that you are indeed trolling. Hence the reduction in the 
 frequency of my replies. You make it more and more difficult to take you 
 seriously.

Fine that goes both ways. I don't mind not being taken serious by people
I have trouble taking serious my self. No doubt that goes for you too.

So I propose we don't react to each other any longer, since there
would be very little purpose in it.

 Particularly since you have now resorted to a defense which 
 involves refusing to define a non-existent word in any but the vaguest 
 terms - you are trying to specify a position on the imaginary continuum 
 of sanity, but you don't say how close to which end you are trying to 
 specify. This puts you somewhere between barmy and crackpot on my 
 own personal scale.
 
If you are serious about wanting the behaviour changed, and not just
whining, then somebody has to come up with an alternative behaviour that
is better.
 
 
 If I would be whining I would want the behaviour changed. I would just
 keep complaining about it until someone else would have changed it.
 
 Instead you just keep complaining about it, full stop.

No I don't keep complaining about. I just defend my claim.

 Since we are all 
 now fully aware of your opinions, couldn't you just shut up, or do we 
 have to send you to your room without any supper? Whine, whine, whine.

Well since you are aware of my opinion, why don't you just ignore
any new articles of mine in this thread and go on, instead of whining
about the fact that I care to defend what I wrote but won't put
more fuel on the fire by starting my idea about superior behaviour
which would only make this thread live longer without any chance
of coming to a shared conclusion.

 Every time I reply to you my spell checker looks at your name and shows 
 me a dialog with an ignore all button on it. I have this increasing 
 suspicion that it's trying to tell me something.

Well maybe you should listen to it. It seems damn obvious neither of
us has anything interresting to say to the other.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Bengt Richter
On Mon, 07 Nov 2005 12:05:40 +0100, Magnus Lycka [EMAIL PROTECTED] wrote:

First of all, I've still not heard any sensible suggestions
about a saner behaviour for augmented assignment or for the
way Python searches the class scope after the instance scope.
A nit, but a sizeable one: For new-style classes, the class scope
is searched first for a descriptor that may trump the instance logic.

What do you suggest?

Today, x += n acts just as x = x + n if x is immutable.
Do you suggest that this should change?
A descriptor allows you to make it do as you like, so it's
a matter of discussing default behavior, not what you
are locked into (although costs re optimization could be a topic).



Today, instance.var will look for var in the class
scope if it didn't find it in the instance scope. Do
you propose to change this?
It is already changed, for new-style classes. It is only if
a data descriptor is NOT found in the class hierarchy that
an existing instance variable is accessed as usual.


Or, do you propose that we should have some second order
effect that makes the combination of instance.var += n
work in such a way that these features are no longer
orthogonal?
I don't think he is proposing anything, just defending against
what he considers misinterpretations of what he is saying.
Given how hard it is to say ANYTHING and be understood EXACTLY,
this tends towards a pursuit of quantum nits ;-)
I suspect we all experience the emotions relevant to being misunderstood;
we just stop at different nit granularities (modulo horn locking ;-)

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Bengt Richter
On 7 Nov 2005 08:38:49 GMT, Antoon Pardon [EMAIL PROTECTED] wrote:

Op 2005-11-04, Magnus Lycka schreef [EMAIL PROTECTED]:

[...]
 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.

Fine I can live with that. 

Amen ;-)

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Christopher Subich
Antoon Pardon wrote:
 Op 2005-11-04, Christopher Subich schreef [EMAIL PROTECTED]:
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.
 
 
 It is the combination of the two.
 
 If python had chosen for an approach like function namespaces, the
 problem wouldn't have occured either. What would have happened then
 is that the compilor would have noticed the a.x on the right hand
 side and based on that fact would then have deciced that all a.x
 references should be instance reference (at least in that function
 block). The a.x += ... would then result in an AttributeError being raised. 

Problem:

class B:
x = 1
classx = b()
instx = b()
instx.x = 5

def addtox(o):
o.x += 1

addtox(instx)
print B.x # 1
print instx.x # 6; we both agree on this one
addtox(classx) # You argue this should AttributeError
print B.x # ?! -- 1 currently, you argue 2 if no error
print class.x # we both agree 2, if no error


a.x is /not/ a namespace issue at all; it's an attribute issue.

.x is not a name, it is an attribute.  Python namespaces are lexically 
scoped, not dynamically scoped; if, as you argue, .x should be a name in 
a namespace, then you argue above that addtox in the above should work 
on instx but fail on classx.  But this /cannot be determined at compile 
time/, because the attribute space is attached to the object passed in 
as the parameter.

I repeat: this is not a name issue at all, it is an attribute issue. 
Python's behaviour is counterintuitive from some angles, but it is the 
only behaviour that is consistent with attributes in general, given the 
signature of __iadd__ as-is.

 
 You may prefer the current behaviour over this, but that is not the
 point. The point is that resolution of name spaces does play its
 role in this problem.

There are no name spaces.

 
 
 It also has little to do with mutable vs immutable types.
 Someone could implement an immutable type, but take advantage
 of some implemtation details to change the value inplace
 in the __iadd__ method. Such an immutable type would show
 the same problems.

Immutable? I do not think that word means what you think it means.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-07 Thread Antoon Pardon
Op 2005-11-07, Christopher Subich schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 Op 2005-11-04, Christopher Subich schreef [EMAIL PROTECTED]:
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.
 
 
 It is the combination of the two.
 
 If python had chosen for an approach like function namespaces, the
 problem wouldn't have occured either. What would have happened then
 is that the compilor would have noticed the a.x on the right hand
 side and based on that fact would then have deciced that all a.x
 references should be instance reference (at least in that function
 block). The a.x += ... would then result in an AttributeError being raised. 

 Problem:
 
 class B:
 x = 1
 classx = b()
 instx = b()
 instx.x = 5

 def addtox(o):
 o.x += 1

 addtox(instx)
 print B.x # 1
 print instx.x # 6; we both agree on this one
 addtox(classx) # You argue this should AttributeError
 print B.x # ?! -- 1 currently, you argue 2 if no error
 print class.x # we both agree 2, if no error
 

 a.x is /not/ a namespace issue at all; it's an attribute issue.

 .x is not a name, it is an attribute.

This may be a meaningfull distinction in the current implementation
but IMO it is less meaningfull to make such a distinction conceptually.

x is a name and proceeding it with a. is just a way of deciding in
which namespace the x is to be searched.

 Python namespaces are lexically 
 scoped, not dynamically scoped; if, as you argue, .x should be a name in 
 a namespace, then you argue above that addtox in the above should work 
 on instx but fail on classx.  But this /cannot be determined at compile 
 time/, because the attribute space is attached to the object passed in 
 as the parameter.

That depends on what you allow in the langauge. Allowing declarations
in the language could take care of that. 

You could also decide scope per scope what is to be happend. If
somewhere in the scope there is a line a.x = ..., then within that
scope all 'a.x' refer to the object. In other scope a.x is decide
as it is now.

 I repeat: this is not a name issue at all, it is an attribute issue. 

Why make such a big distinction between the two?

 Python's behaviour is counterintuitive from some angles, but it is the 
 only behaviour that is consistent with attributes in general, given the 
 signature of __iadd__ as-is.

If you mean the only behaviour that is consistent with the current
python attribute implementation. I can accept that. But as you have
worded it, it seems way to general, almost claiming that any language
that does it differently is not consistent. Maybe I misunderstood.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-06 Thread Bengt Richter
On Sun, 06 Nov 2005 15:17:18 +1100, Steven D'Aprano [EMAIL PROTECTED] wrote:

On Sat, 05 Nov 2005 18:14:03 -0800, Paul Rubin wrote:

 instance.attribute sometimes reading from the class attribute is a feature
 of inheritance; instance.attribute always writing to the instance is a
 feature of OOP; instance.attribute sometimes writing to the instance and
 sometimes writing to the class would be, in my opinion, not just a wart
 but a full-blown misfeature.
 
 But that is what you're advocating: x.y+=1 writes to the instance or
 the class depending on whether x.y is mutable or not.

Scenario 1:

Pre-conditions: class.a exists; instance.a exists.
Post-conditions: class.a unchanged; instance.a modified.

I give that a big thumbs up, expected and proper behaviour.

Scenario 2:

Pre-conditions: class.a exists and is immutable; instance.a does not
exist.
Post-conditions: class.a unchanged; instance.a exists.

Again, expected and proper behaviour.

(Note: this is the scenario that Antoon's proposed behaviour would change
to class.a modified; instance.a does not exist.)

Scenario 3:

Pre-conditions: class.a exists and is mutable; instance.a exists.
Post-conditions: class.a unchanged; instance.a is modified.

Again, expected and proper behaviour.

Scenario 4:

Pre-conditions: class.a exists and is mutable; instance.a does
not exist.
Post-conditions: class.a modified; instance.a does not exist.

Are you saying the above is what happens or what should happen or not happen?
It's not what happens. Post-conditions are that class.a is modified AND
instance.a gets a _separate_ reference to the same result. Note:

 Python 2.4b1 (#56, Nov  3 2004, 01:47:27)
 [GCC 3.2.3 (mingw special 20030504-1)] on win32
 Type help, copyright, credits or license for more information.
  class A(object):
 ... a = []
 ...
  b=A()
  id(A.__dict__['a'])
 49230700
  b.a += [123]
  id(A.__dict__['a'])
 49230700
  id(b.__dict__['a'])
 49230700
  (b.__dict__['a'])
 [123]
  (A.__dict__['a'])
 [123]

Let's eliminate the inheritable class variable A.a:

  del A.a
  b.a
 [123]
  id(b.__dict__['a'])
 49230700
  vars(b)
 {'a': [123]}

Make sure we did eliminate A.a
  vars(A)
 dictproxy object at 0x02E817AC
  vars(A).keys()
 ['__dict__', '__module__', '__weakref__', '__doc__']

Is that the wart you were thinking of, or are you actually happier? ;-)

Well, that is a wart. It is the same wart, and for the same reasons, as
the behaviour of:

def function(value=[]):
value.append(None)
IMO that's not a wart at all, that's a direct design decision, and it's
different from the dual referencing that happens in Scenario 4.


I can live with that. It is a familiar wart, and keeps inheritance of
attributes working the right way. And who knows? If your attributes are
mutable, AND you want Antoon's behaviour, then you get it for free just by
using b.a += 1 instead of b.a = b.a + 1.
Not quite, because there is no way to avoid the binding of the __iadd__
return value to b.a by effective setattr (unless you make type(b).a
a descriptor that intercepts the attempt -- see another post for example).

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-06 Thread Steven D'Aprano
On Sun, 06 Nov 2005 08:40:00 +, Bengt Richter wrote:

Pre-conditions: class.a exists and is mutable; instance.a does
not exist.
Post-conditions: class.a modified; instance.a does not exist.

 Are you saying the above is what happens or what should happen or not happen?

Er, it's what I thought was happening without actually checking it...

 It's not what happens. Post-conditions are that class.a is modified AND
 instance.a gets a _separate_ reference to the same result. Note:

[snip demonstration]
 
 Is that the wart you were thinking of, or are you actually happier?
 ;-)

In other words, the post-condition for all four scenarios includes that
the instance attribute now exists. I'm actually happier. My brain was full
of people talking about __iadd__ modifying mutables in place and I wasn't
thinking straight.


Well, that is a wart. It is the same wart, and for the same reasons, as
the behaviour of:

def function(value=[]):
value.append(None)
 IMO that's not a wart at all, that's a direct design decision, and it's
 different from the dual referencing that happens in Scenario 4.

Okay, perhaps wart is not quite the right word... but it is certainly
unexpected if you haven't come across it before, or thought *deeply* about
what is going on. A gotcha perhaps.


-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-06 Thread Christopher Subich
Bengt Richter wrote:
 On Fri, 04 Nov 2005 10:28:52 -0500, Christopher Subich [EMAIL PROTECTED] 
 wrote:

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).
 
 But if it is an esoteric descriptor (or even a simple property, which is
 a descriptor), the behaviour will depend on the descriptor, and an instance
 variable can be created or not, as desired, along with any side effect you 
 like.

Right, and that's also language-specification.  Voodoo, yes, but 
language specification nonetheless. :)
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-06 Thread Bengt Richter
On Sun, 06 Nov 2005 12:23:02 -0500, Christopher Subich [EMAIL PROTECTED] 
wrote:

Bengt Richter wrote:
 On Fri, 04 Nov 2005 10:28:52 -0500, Christopher Subich [EMAIL PROTECTED] 
 wrote:

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).
 
 But if it is an esoteric descriptor (or even a simple property, which is
 a descriptor), the behaviour will depend on the descriptor, and an instance
 variable can be created or not, as desired, along with any side effect you 
 like.

Right, and that's also language-specification.  Voodoo, yes, but 
language specification nonetheless. :)

I guess http://docs.python.org/ref/augassign.html is the spec.
I notice its example at the end uses an old-style class, so maybe
it's understandable that when it talks about getattr/setattr, it doesn't
mention the possible role of descriptors, nor narrow the meaning of
evaluate once for a.x to exclude type(a).x in the setattr phase of execution.

I.e., if x is a descriptor, evaluate apparently means only

type(a).x.__get__(a, type(a))

since that is semantically getting the value behind x, and so both of the .xs 
in

type(a).x.__set__(a, type(a).x.__get__(a, type(a)).__add__(1)) # (or 
__iadd__ if defined, I think ;-)

don't count as evaluation of the target x, even though it means that a.x 
got evaluated twice
(via getattr and setattr, to get the same descriptor object (which was used two 
different ways)).

I think the normal, non-descriptor case still results in (optimized) probes for 
type(a).x.__get__
and type(a).x.__set__ before using a.__dict__['x'].

ISTM also that it's not clear that defining __iadd__ does _not_ prevent the 
setattr phase from going ahead.
I.e., a successful __iadd__ in-place mutation does not happen instead of the 
setattr.

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-05 Thread Bengt Richter
On Fri, 04 Nov 2005 21:14:17 -0500, Mike Meyer [EMAIL PROTECTED] wrote:

[EMAIL PROTECTED] (Bengt Richter) writes:
 On Thu, 03 Nov 2005 13:37:08 -0500, Mike Meyer [EMAIL PROTECTED] wrote:
 [...]
 I think it even less sane, if the same occurce of b.a refers to two
 different objects, like in b.a += 2

That's a wart in +=, nothing less. The fix to that is to remove +=
from the language, but it's a bit late for that.

 Hm, the fix? Why wouldn't e.g. treating augassign as shorthand for a 
 source transformation
 (i.e., asstgt op= expr  becomes by simple text substitution asstgt = 
 asstgt op expr)
 be as good a fix? Then we could discuss what

 b.a = b.a + 2

 should mean ;-)

The problem with += is how it behaves, not how you treat it. But you
can't treat it as a simple text substitution, because that would imply
that asstgt gets evaluated twice, which doesn't happen.
I meant that it would _make_ that happen, and no one would wonder ;-)

BTW, if b.a is evaluated once each for __get__ and __set__, does that not
count as getting evaluated twice?

  class shared(object):
 ... def __init__(self, v=0): self.v=v
 ... def __get__(self, *any): print '__get__'; return self.v
 ... def __set__(self, _, v): print '__set__'; self.v = v
 ...
  class B(object):
 ... a = shared(1)
 ...
  b=B()
  b.a
 __get__
 1
  b.a += 2
 __get__
 __set__
  B.a
 __get__
 3

Same number of get/sets:

  b.a = b.a + 10
 __get__
 __set__
  b.a
 __get__
 13

I posted the disassembly in another part of the thread, but I'll repeat:

  def foo():
 ... a.b += 2
 ... a.b = a.b + 2
 ...
  import dis
  dis.dis(foo)
   2   0 LOAD_GLOBAL  0 (a)
   3 DUP_TOP
   4 LOAD_ATTR1 (b)
   7 LOAD_CONST   1 (2)
  10 INPLACE_ADD
  11 ROT_TWO
  12 STORE_ATTR   1 (b)

   3  15 LOAD_GLOBAL  0 (a)
  18 LOAD_ATTR1 (b)
  21 LOAD_CONST   1 (2)
  24 BINARY_ADD
  25 LOAD_GLOBAL  0 (a)
  28 STORE_ATTR   1 (b)
  31 LOAD_CONST   0 (None)
  34 RETURN_VALUE

It looks like the thing that's done only once for += is the LOAD_GLOBAL (a)
but DUP_TOP provides the two copies of the reference which are
used either way with LOAD_ATTR followed by STORE_ATTR, which UIAM
lead to the loading of the (descriptor above) attribute twice -- once each
for the __GET__ and __SET__ calls respectively logged either way above.


 OTOH, we could discuss how you can confuse yourself with the results of b.a 
 += 2
 after defining a class variable a as an instance of a class defining 
 __iadd__ ;-)

You may confuse yourself that way, I don't have any problems with it
per se.
I should have said one can confuse oneself, sorry ;-)
Anyway, I wondered about the semantics of defining __iadd__, since it seems to 
work just
like __add__ except for allowing you to know what source got you there. So 
whatever you
return (unless you otherwise intercept instance attribute binding) will get 
bound to the
instance, even though you internally mutated the target and return None by 
default (which
gives me the idea of returning NotImplemented, but (see below) even that gets 
bound :-(

BTW, semantically does/should not __iadd__ really implement a _statement_ and 
therefore
have no business returning any expression value to bind anywhere?

  class DoIadd(object):
 ... def __init__(self, v=0, **kw):
 ... self.v = v
 ... self.kw = kw
 ... def __iadd__(self, other):
 ... print '__iadd__(%r, %r) = '%(self, other),
 ... self.v += other
 ... retv = self.kw.get('retv', self.v)
 ... print repr(retv)
 ... return retv
 ...
  class B(object):
 ... a = DoIadd(1)
 ...
  b=B()
  b.a
 __main__.DoIadd object at 0x02EF374C
  b.a.v
 1

The normal(?) mutating way:
  b.a += 2
 __iadd__(__main__.DoIadd object at 0x02EF374C, 2) =  3
  vars(b)
 {'a': 3}
  B.a
 __main__.DoIadd object at 0x02EF374C
  B.a.v
 3

Now fake attempt to mutate self without returning anything (= None)
  B.a = DoIadd(1, retv=None) # naive default
  b.a
 3
Oops, remove instance attr
  del b.a
  b.a
 __main__.DoIadd object at 0x02EF3D6C
  b.a.v
 1
Ok, now try it
  b.a +=2
 __iadd__(__main__.DoIadd object at 0x02EF3D6C, 2) =  None
  vars(b)
 {'a': None}
Returned value None still got bound to instance
  B.a.v
 3
Mutation did happen as planned

Now let's try NotImplemented as a return
  B.a = DoIadd(1, retv=NotImplemented) # mutate but probably do __add__ too
  del b.a
  b.a
 __main__.DoIadd object at 0x02EF374C
  b.a.v
 1
  b.a +=2
 __iadd__(__main__.DoIadd object at 0x02EF374C, 2) =  NotImplemented
 __iadd__(__main__.DoIadd object at 0x02EF374C, 2) =  NotImplemented
  vars(b)
 {'a': NotImplemented}
  B.a.v
 5

No problem with that? ;-)

I'd say it looks like someone got tired of 

Re: Class Variable Access and Assignment

2005-11-05 Thread Bengt Richter
On Sat, 05 Nov 2005 14:37:19 +1100, Steven D'Aprano [EMAIL PROTECTED] wrote:

On Sat, 05 Nov 2005 00:25:34 +, Bengt Richter wrote:

 On Fri, 04 Nov 2005 02:59:35 +1100, Steven D'Aprano [EMAIL PROTECTED] 
 wrote:
 
On Thu, 03 Nov 2005 14:13:13 +, Antoon Pardon wrote:

 Fine, we have the code:
 
   b.a += 2
 
 We found the class variable, because there is no instance variable,
 then why is the class variable not incremented by two now?
 Because the class variable doesn't define a self-mutating __iadd__
 (which is because it's an immutable int, of course). If you want
 b.__dict__['a'] += 2 or b.__class__.__dict__['a'] += 2 you can
 always write it that way ;-)
 
 (Of course, you can use a descriptor to define pretty much whatever semantics
 you want, when it comes to attributes).
 

Because b.a += 2 expands to b.a = b.a + 2. Why would you want b.a =
 
 No, it doesn't expand like that. (Although, BTW, a custom import could
 make it so by transforming the AST before compiling it ;-)
 
 Note BINARY_ADD is not INPLACE_ADD:

Think about *what* b.a += 2 does, not *how* it does it. Perhaps for some
what it does, or what in the abstract it was intended to do? (which we need
BDFL channeling to know for sure ;-)

It looks like it means, add two to whatever b.a is. I think Antoon
is unhappy that whatever b.a is is not determined once for the one b.a
expression in the statement. I sympathize, though it's a matter of defining
what b.a += 2 is really intended to mean. 
The parses are certainly distinguishable:

  import compiler
  compiler.parse('b.a +=2','exec').node
 Stmt([AugAssign(Getattr(Name('b'), 'a'), '+=', Const(2))])
  compiler.parse('b.a = b.a + 2','exec').node
 Stmt([Assign([AssAttr(Name('b'), 'a', 'OP_ASSIGN')], Add((Getattr(Name('b'), 
'a'), Const(2])

Which I think leads to the different (BINARY_ADD vs INPLACE_ADD) code, which 
probably really
ought to have a conditional STORE_ATTR for the result of INPLACE_ADD, so that 
if __iadd__
was defined, it would be assumed that the object took care of everything 
(normally mutating itself)
and no STORE_ATTR should be done. But that's not the way it works now. (See 
also my reply to Mike).

Perhaps all types that want to be usable with inplace ops ought to inherit from 
some base providing
that, and there should never be a return value. This would be tricky for 
immutables though, since
re-binding is necessary, and the __iadd__ method would have to be passed the 
necessary binding context
and methods. Probably too much of a rewrite to be practical.

other data type it would make a difference whether the mechanism was
BINARY_ADD (__add__) or INPLACE_ADD (__iadd__), but in this case it does
not. Both of them do the same thing.
Unfortunately you seem to be right in this case.

Actually, no perhaps about it -- we've already discussed the case of
lists.
Well, custom objects have to be considered too. And where attribute access
is involved, descriptors.


Sometimes implementation makes a difference. I assume BINARY_ADD and
INPLACE_ADD work significantly differently for lists, because their
results are significantly (but subtly) different:

py L = [1,2,3]; id(L)
-151501076
py L += [4,5]; id(L)
-151501076
py L = L + []; id(L)
-151501428

Yes.

But all of this is irrelevant to the discussion about binding b.a
differently on the left and right sides of the equals sign. We have
discussed that the behaviour is different with mutable objects, because
they are mutable -- if I recall correctly, I was the first one in this
thread to bring up the different behaviour when you append to a list
rather than reassign, that is, modify the class attribute in place.

I'll admit that my choice of terminology was not the best, but it wasn't
misleading. b.a += 2 can not modify ints in place, and so the
effect of b.a += 2 is the same as b.a = b.a + 2, regardless of what
byte-codes are used, or even what C code eventually implements that
add-and-store.
It is so currently, but that doesn't mean that it couldn't be otherwise.
I think there is some sense to the idea that b.a should be re-bound in
the same namespace where it was found with the single apparent evaluation
of b.a in b.a += 2 (which incidentally is Antoon's point, I think).
This is just for augassign, of course.

OTOH, this would be find-and-rebind logic for attributes when augassigned,
and that would enable some tricky name-collision bugs for typos, and code
that used instance.attr += incr depending on current behavior would break.


In the case of lists, setting Class.a = [] and then calling instance.a +=
[1] would not exhibit the behaviour Antoon does not like, because the
addition is done in place. But calling instance.a = instance.a + [1]
would.

My question still stands: why would you want instance.a = something
to operate as instance.__class__.a = something?

Because in the case of instance.a += increment, instance.a
is a short spelling for instance.__class__.a (in the limited case we are 
discussing),
and that 

Re: Class Variable Access and Assignment

2005-11-05 Thread Steven D'Aprano
On Sat, 05 Nov 2005 21:26:22 +, Bengt Richter wrote:

 BTW, semantically does/should not __iadd__ really implement a _statement_ and 
 therefore
 have no business returning any expression value to bind anywhere?

We get to practicality versus purity here.

Consider x += y for some object type x. If x is a mutable object, then
__iadd__ could be a statement, because it can/should/must modify x in
place. That is the pure solution.

But do you want x += y to work for immutable objects as well? Then
__iadd__ cannot be a statement, because x can't be modified in place.
Our pure add in place solution fails in practice, unless we needlessly
restrict what can use it, or have the same syntactical expression (x +=
y) bind to two different methods (__iadd__ statement, and __riadd__
function, r for return). Either pure solution is yucky. (That's a
technical term for it sucks.) So for practical reasons, __iadd__ can't
be a statement, it needs to return an object which gets bound to x.

Fortunately, that behaviour works for mutables as well, because __iadd__
simply returns self, which gets re-bound to x.

While I am enjoying the hoops people are jumping through to modify the
language so that b.a += 2 assigns b.a in the same scope as it was
accessed, I'm still rather perplexed as to why you would want that
behaviour. It seems to me like spending many hours building a wonderfully
polished, ornate, exquisite device for building hiking boots for mountain
goats.


-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-05 Thread Steven D'Aprano
On Fri, 04 Nov 2005 22:19:39 -0800, Paul Rubin wrote:

 Steven D'Aprano [EMAIL PROTECTED] writes:
  Next you get some performance gain by using gmpy to handle the long int 
  arithmetic,
 
 Then whatever happens next will be my own stupid fault for prematurely 
 optimising code.
 
 Huh?  There's nothing premature about using gmpy if you need better long int 
 performance.
 It was written for a reason, after all.

Sure, but I would be willing to bet that incrementing a counter isn't it.


 What exactly is your point? That bugs can happen if the behaviour of your
 underlying libraries changes? 
 
 That your initialization scheme is brittle--the idea of data
 abstraction is being able to change object behaviors -without- making
 surprising bugs like that one.  You don't even need the contrived gmpy
 example.  You might replace the level number with, say, a list of
 levels that have been visited.

Do you expect level += 1 to still work when you change level to a list of
levels?

The problem with data abstraction is if you take it seriously, it means
You should be able to do anything with anything. If I change
object.__dict__ to None, attribute lookup should work, yes? No? Then
Python isn't sufficiently abstract.

As soon as you accept that there are some things you can't do with some
data, you have to stop abstracting. *Prematurely* locking yourself into
one *specific* data structure is bad: as a basic principle, data
abstraction is very valuable -- but in practice there comes a time where
you have to say Look, just choose a damn design and live with it. If you
choose sensibly, then it won't matter if your counter is an int or a long
or a float or a rational -- but you can't sensibly expect to change your
counter to a binary tree without a major redesign of your code.

I've watched developers with an obsession with data abstraction in
practice. I've watched one comp sci graduate, the ink on his diploma not
even dry yet, spend an hour mapping out state diagrams for a factorial
function.

Hello McFly? The customer is paying for this you know. Get a move on. I've
written five different implementations of factorial in ten minutes, and
while none of them worked with symbolic algebra I didn't need symbolic
algebra support, so I lost nothing by not supporting it.

So I hope you'll understand why I get a bad taste in my mouth when people
start talking about data abstraction.


 
 I don't think the culprit is the mutable/immutable distinction +=
 uses, though that is certainly somewhat odd.  I think Antoon is on the
 right track: namespaces in Python live in sort of a ghetto unbecoming
 of how the Zen list describes them as a honking great idea.  These
 things we call variables are boxed objects where the namespace is the
 box.  So having x+=y resolve x to a slot in a namespace before
 incrementing that same slot by y, maybe better uses the notion of
 namespaces than what happens now.

Perhaps it does, but it breaks inheritance, which is more important than
purity of namespace resolution. Practicality beats purity.


 I'm too sleepy to see for sure
 whether it gets rid of the mutable/immutable weirdness.

What weirdness? What would be weird is if mutable and immutable objects
worked the same as each other. They behave differently because they are
different. If you fail to see that, you are guilty of excessive data
abstraction.


-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-05 Thread Paul Rubin
Steven D'Aprano [EMAIL PROTECTED] writes:
 But do you want x += y to work for immutable objects as well? Then
 __iadd__ cannot be a statement, because x can't be modified in place.

It never occurred to me that immutable objects could implement __iadd__.
If they can, I'm puzzled as to why.  

 While I am enjoying the hoops people are jumping through to modify the
 language so that b.a += 2 assigns b.a in the same scope as it was
 accessed, I'm still rather perplexed as to why you would want that
 behaviour.

Weren't you the one saying += acting differently for mutables and
immutables was a wart?  If it's such a wart, why are do you find it so
important to be able to rely on the more bizarre consequences of the
wartiness?  Warts should be (if not fixed) avoided, not relied on.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-05 Thread Steven D'Aprano
On Sat, 05 Nov 2005 16:27:00 -0800, Paul Rubin wrote:

 Steven D'Aprano [EMAIL PROTECTED] writes:
 But do you want x += y to work for immutable objects as well? Then
 __iadd__ cannot be a statement, because x can't be modified in place.
 
 It never occurred to me that immutable objects could implement __iadd__.
 If they can, I'm puzzled as to why.  

???

The classic += idiom comes from C, where you typically use it on ints and
pointers.

In C, ints aren't objects, they are just bytes, so you can modify them
in place. I'm surprised that it never occurred to you that people might
want to do something like x = 1; x += 1 in Python, especially as the
lack of such a feature (as I recall) was one of the biggest complaints
from C programmers crossing over to Python.

Personally, I'm not fussed about +=. Now that it is in the language, I'll
use it, but I never missed it when it wasn't in the language.

 While I am enjoying the hoops people are jumping through to modify the
 language so that b.a += 2 assigns b.a in the same scope as it was
 accessed, I'm still rather perplexed as to why you would want that
 behaviour.
 
 Weren't you the one saying += acting differently for mutables and
 immutables was a wart?  

Nope, not me.

 If it's such a wart, why are do you find it so
 important to be able to rely on the more bizarre consequences of the
 wartiness?  Warts should be (if not fixed) avoided, not relied on.

The consequences of instance.attribute += 1 may be unexpected for those
who haven't thought it through, or read the documentation, but they aren't
bizarre. Whether that makes it a feature or a wart depends on whether you
think non-method attributes should be inherited or not. I think they
should be.

I can respect the position of somebody who says that only methods
should be inherited -- somebody, I think it was you, suggested that there
is at least one existing OO language that doesn't allow inheritance for
attributes, but never responded to my asking what language it was.
Personally, I would not like an OO language that didn't inherit
attributes, but at least that is consistent. (At least, if you don't
consider methods to be a particular sort of attribute.)

But I can't understand the position of folks who want inheritance but
don't want the behaviour that Python currently exhibits.
instance.attribute sometimes reading from the class attribute is a feature
of inheritance; instance.attribute always writing to the instance is a
feature of OOP; instance.attribute sometimes writing to the instance and
sometimes writing to the class would be, in my opinion, not just a wart
but a full-blown misfeature.

I ask and I ask and I ask for some use of this proposed behaviour, and
nobody is either willing or able to tell me where how or why it would be
useful. What should I conclude from this?


-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-05 Thread Paul Rubin
Steven D'Aprano [EMAIL PROTECTED] writes:
  It never occurred to me that immutable objects could implement __iadd__.
  If they can, I'm puzzled as to why.  

 I'm surprised that it never occurred to you that people might
 want to do something like x = 1; x += 1 in Python,

But I wouldn't expect that to mean that ints implement __iadd__.  I'd expect
the x+=1 to just use __add__.  I haven't checked the spec though.

 I can respect the position of somebody who says that only methods
 should be inherited -- somebody, I think it was you, suggested that there
 is at least one existing OO language that doesn't allow inheritance for
 attributes, but never responded to my asking what language it was.

I was thinking of Flavors.  You use a special function (send) to do method
calls.  But people generally felt that was kludgy and CLOS eliminated it.
I'm not sure what happens in Smalltalk.

 instance.attribute sometimes reading from the class attribute is a feature
 of inheritance; instance.attribute always writing to the instance is a
 feature of OOP; instance.attribute sometimes writing to the instance and
 sometimes writing to the class would be, in my opinion, not just a wart
 but a full-blown misfeature.

But that is what you're advocating: x.y+=1 writes to the instance or
the class depending on whether x.y is mutable or not.  Say you have an
immutable class with a mutable subclass or vice versa.  You'd like to
be able to replace a class instance with a subclass instance and not
have the behavior change (Liskov substitution principle), etc.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-05 Thread Steve Holden
Steven D'Aprano wrote:
[...]
 
 But I can't understand the position of folks who want inheritance but
 don't want the behaviour that Python currently exhibits.
 instance.attribute sometimes reading from the class attribute is a feature
 of inheritance; instance.attribute always writing to the instance is a
 feature of OOP; instance.attribute sometimes writing to the instance and
 sometimes writing to the class would be, in my opinion, not just a wart
 but a full-blown misfeature.
 
 I ask and I ask and I ask for some use of this proposed behaviour, and
 nobody is either willing or able to tell me where how or why it would be
 useful. What should I conclude from this?
 
 

You should conclude that some readers of this group are happier 
designing languages with theoretical purity completely disconnected from 
users' needs. But of course we pragmatists know that practicality beats 
purity :-)

regards
  Steve
-- 
Steve Holden   +44 150 684 7255  +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006  www.python.org/pycon/

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


Re: Class Variable Access and Assignment

2005-11-05 Thread Steven D'Aprano
On Sat, 05 Nov 2005 18:14:03 -0800, Paul Rubin wrote:

 instance.attribute sometimes reading from the class attribute is a feature
 of inheritance; instance.attribute always writing to the instance is a
 feature of OOP; instance.attribute sometimes writing to the instance and
 sometimes writing to the class would be, in my opinion, not just a wart
 but a full-blown misfeature.
 
 But that is what you're advocating: x.y+=1 writes to the instance or
 the class depending on whether x.y is mutable or not.

Scenario 1:

Pre-conditions: class.a exists; instance.a exists.
Post-conditions: class.a unchanged; instance.a modified.

I give that a big thumbs up, expected and proper behaviour.

Scenario 2:

Pre-conditions: class.a exists and is immutable; instance.a does not
exist.
Post-conditions: class.a unchanged; instance.a exists.

Again, expected and proper behaviour.

(Note: this is the scenario that Antoon's proposed behaviour would change
to class.a modified; instance.a does not exist.)

Scenario 3:

Pre-conditions: class.a exists and is mutable; instance.a exists.
Post-conditions: class.a unchanged; instance.a is modified.

Again, expected and proper behaviour.

Scenario 4:

Pre-conditions: class.a exists and is mutable; instance.a does
not exist.
Post-conditions: class.a modified; instance.a does not exist.

Well, that is a wart. It is the same wart, and for the same reasons, as
the behaviour of:

def function(value=[]):
value.append(None)

I can live with that. It is a familiar wart, and keeps inheritance of
attributes working the right way. And who knows? If your attributes are
mutable, AND you want Antoon's behaviour, then you get it for free just by
using b.a += 1 instead of b.a = b.a + 1.


 Say you have an
 immutable class with a mutable subclass or vice versa.  You'd like to
 be able to replace a class instance with a subclass instance and not
 have the behavior change (Liskov substitution principle), etc.

That's easy. You just have to make sure that the subclass implements
__iadd__ the same way that the immutable parent class does. 

You can't expect a class that performs += in place to act the
same as a class that doesn't perform += in place. Excessive data
abstraction, remember? 

L = list(Liskov substitution principle)
L.sort()  # sorts in place
print L   # prints the sorted list

class immutable_list(list):
# __init__ not shown, but does the right thing
def sort(self):
tmp = list(self)
tmp.sort()
return immutable_list(tmp)

L = immutable_list(Liskov substitution principle)
L.sort()  # throws the sorted list away
print L   # prints the unsorted list

The only way the Liskov substitution principle works is if everything
works the same way, which means that all subclasses, all *possible*
subclasses, must have no more functionality than the subclass that does
the absolute least. Since the least is nothing, well, you work it out.

-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Steve Holden schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 Op 2005-11-03, Stefan Arentz schreef [EMAIL PROTECTED]:
 [...]
It is all according to how things have been in Python for a long time.
 
 Unsane behaviour for a long time is still unsane behaviour.
 
 As your continued contributions on this newsgroup so adequately 
 demonstrate :-).

 Sorry, I *couldn't* resist. You asked for it. It was hanging there (in a 
 containing namespace?) waiting to be posted. If I hadn't said it someone 
 else would have. And other justifications for what I hope doesn't seem 
 like too unpleasant a personal attack.

Well I would argue that a lot of the defenders of python are not
reacting very sane. My impression is that a lot of them react like
zealots, blindly devoted to the language, rather intollerant of
every criticism and prepared to defend anything as long as it happens
to be a current characteristic of the language and where any such
criticism sooner or later is met with something like: If you don't
like it, use a different language, as if only those who are 100%
perfectly happy with the language as it is, should use it.

The real issue here is that you should propery name class variables so
that there can't be any confusion about class or instance scope. I use
all uppercase identifiers for class variables for example.
 
 
 The fact that this can be regarded as unwise coding, doesn't imply
 it is sane behaviour of python. Variable shadowing happens. I don't
 consider it sane behaviour if the same reference in a line gets
 resolved in different name spaces
 
 Well I'm sure Guido will be happy to know you think his design is 
 insane. Now who's calling who names?

I'm not calling anyone names. I'm just pointing to one specific
behaviour in python and call that behaviour unsane. If you want
to interpret that as me calling his (entire) design insane, I
suggest you are two defensive with regards to python.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-03, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Thu, 03 Nov 2005 04:30:09 -0800, Paul Rubin wrote:

 Steve Holden [EMAIL PROTECTED] writes:
  class A:
a = 1
  b = A()
  b.a += 2
  print b.a
  print A.a
  Which results in
  3
  1
 
 I don't suppose you'd care to enlighten us on what you'd regard as the
 superior outcome?
 
 class A:
   a = []
 b = A()
 b.append(3)
 print b.a
 print a.a
 
 Compare and contrast.


 I take it then that you believe that ints like 1 should be mutable like
 lists? Because that is what the suggested behaviour implies.

No it isn't.

One other way, to implement the += and likewise operators would be
something like the following.

Assume a getnsattr, which would work like getattr, but would also
return the namespace where the name was found. The implementation
of b.a += 2 could then be something like:

  ns, t = getnsattr(b, 'a')
  t = t + 2
  setattr(ns, 'a')


I'm not arguing that this is how it should be implemented. Just
showing the implication doesn't follow.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-03, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Thu, 03 Nov 2005 12:53:37 +, Antoon Pardon wrote:

 I don't suppose you'd care to enlighten us on what you'd regard as the 
 superior outcome?
 
 No. I don't think a superior outcome is necessary to see that this is
 not sane behaviour. I don't care that much on how it gets fixed.

 It isn't broken, there is nothing to fix. The code does precisely what the
 inheritance model promises to do.

That is not a contra argument. Delivering what is promissed says nothing
about the sanity of what is promissed. It is even possible that a number
of things that are sane in itself, produce something unsane when
combined or in certain circumstances.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Stefan Arentz
Antoon Pardon [EMAIL PROTECTED] writes:

...

  Ah yes. Well, good luck with that. You seem to have decided that it is not
  sane and who am I to argue with that. It depends on your state of mind :-)
 
 I can just say the opposite, that you seem to have decided that it is
 sane.

I have. I like the Python model.

  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.
 
 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.

Personally I don't see it as a shortcoming.

 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 not at all. Just look at all the PEPs and the changes in the language
that have been made in the past. Python is very much community driven and
that shows in it's progress.

You on the other hand keep talking about emo things like 'sane' and
'madness' without giving any technical backing about these problems
that you are having with the language.

Snap out of that, make it a real discussion and maybe something good
will happen. Or not :-)

 S.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-03, Magnus Lycka schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 There is no instance variable at that point. How can it add 2, to
 something that doesn't exist at the moment.

 Because 'a += 1' is only a shorthand for 'a = a + 1' if a is an
 immutable object? Anyway, the behaviour is well documented.

 http://docs.python.org/ref/augassign.html says:

 An augmented assignment expression like x += 1 can be rewritten as x = x 
 + 1 to achieve a similar, but not exactly equal effect. In the augmented 
 version, x is only evaluated once.

Then couldn't we expect that the namespace resolution is also done
only once?

I say that if the introduction on += like operators implied that the
same mentioning of a name would in some circumstances be resolved to
two different namespaces, then such an introduction would better have
not occured.

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

  x = x + 1.

both x's would resolve to the same namespace?

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-03, Magnus Lycka schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 Op 2005-11-03, Steven D'Aprano schreef [EMAIL PROTECTED]:
 
 
There are two possible fixes, either by prohibiting instance variables
with the same name as class variables, which would allow any reference
to an instance of the class assign/read the value of the variable. Or
to only allow class variables to be accessed via the class name itself.

There is also a third fix: understand Python's OO model, especially
inheritance, so that normal behaviour no longer surprises you.
 
 
 No matter wat the OO model is, I don't think the following code
 exhibits sane behaviour:
 
 class A:
   a = 1
 
 b = A()
 b.a += 2
 print b.a
 print A.a
 
 Which results in
 
 3
 1

 On the other hand:

  class C:
 ... a = [1]
 ...
  b=C()
  b.a += [2]
  b.a
 [1, 2]
  C.a
 [1, 2]

 I can understand that Guido was a bit reluctant to introduce
 += etc into Python, and it's important to understand that they
 typically behave differently for immutable and mutable objects.

All fine by me. I won't be using python any less because of this,
because I use class variable very little and you can avoid this
problem by avoiding instance that shadow class variables and
always refer to class variables by class name.

But that doesn't mean we should consider this kind of behaviour
as it should be, just because it is in python.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-03, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Thu, 03 Nov 2005 13:35:35 +, Antoon Pardon wrote:

 Suppose I have code like this:
 
   for i in xrange(1,11):
 b.a = b.a + i
 
 Now the b.a on the right hand side refers to A.a the first time through
 the loop but not the next times. I don't think it is sane that which
 object is refered to depends on how many times you already went through
 the loop.

 Well, then you must think this code is *completely* insane too:

 py x = 0
 py for i in range(1, 5):
 ... x += i
 ... print id(x)
 ... 
 140838200
 140840184
 140843160
 140847128

 Look at that: the object which is referred to depends on how many times
 you've already been through the loop. How nuts is that?

It is each time the 'x' from the same name space. In the code above
the 'a' is not each time from the same namespace.

I also think you new very well what I meant.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-03, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Thu, 03 Nov 2005 13:01:40 +, Antoon Pardon wrote:

 Seems perfectly sane to me. 

 What would you expect to get if you wrote b.a = b.a + 2?
 
 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?

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.

 Why do you expect
 b.a += 2 to give a different result?
 
 I didn't know I did.

 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.

What I object to is that the mentioning of one instance gets resolved
to two different namespaces.

 Since ints are immutable objects, you shouldn't expect the value of b.a
 to be modified in place, and so there is an assignment to b.a, not A.a.
 
 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 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.

 But b.a is not a name, it is an attribute lookup,

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

 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'].

That holly python does it this way, doesn't imply it is reasonable to
do it this way or that all consequences of doing it this way are
reasonable.

 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'


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.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-03, Mike Meyer schreef [EMAIL PROTECTED]:
 Antoon Pardon [EMAIL PROTECTED] writes:
 What would you expect to get if you wrote b.a = b.a + 2?
 I would expect a result consistent with the fact that both times
 b.a would refer to the same object.

 Except they *don't*. This happens in any language that resolves
 references at run time.

Python doesn't resolve references at run time. If it did the following
should work.

a = 1
def f():
  a = a + 1

f()

But letting that aside. There is still a difference between resolving
reference at run time and having the same reference resolved twice
with each resolution a different result.

 Changing that would be changing a fundamental
 - and *important* - feature of Python. Arbitrary restrictions to
 prevent a single case of this from doing something people who aren't
 used to suvh behavior are kludges, and would constitute a wart on the
 language, pure and simple.

Python already has its warts. If you want to argue that fixing this
would make a bigger wart then the wart it is now. Fine I will accept
that.

 If you think this is bad, you should consider Jensen's device. It uses
 call-by-name, which Python doesn't have.

Actually, I would have thought it very interesting should python 
have provided some choice in parameter semantics.


 I think it even less sane, if the same occurce of b.a refers to two
 different objects, like in b.a += 2

 That's a wart in +=, nothing less. The fix to that is to remove +=
 from the language, but it's a bit late for that.

  mike

Well we agree that there is a wart somewhere.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Steve Holden schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 Op 2005-11-03, Stefan Arentz schreef [EMAIL PROTECTED]:
 
Antoon Pardon [EMAIL PROTECTED] writes:

...


No matter wat the OO model is, I don't think the following code
exhibits sane behaviour:

class A:
  a = 1

b = A()
b.a += 2
print b.a
print A.a

Which results in

3
1

I find it confusing at first, but I do understand what happens :-)

I understand what happens too, that doesn't make it sane behaviour.


But really, what should be done different here?

I don't care what should be different. But a line with only one
referent to an object in it, shouldn't be referring to two different
objects.

It doesn't.
 
 
 Yes it does. If the b.a refers to the instance variable, then an
 AttributeError should be raised, because the instance variable doesn't
 exist yet, so you can't add two to it.
 
 Excuse me. The statement

  a += 2

 causes a to refer to a different object after the assignment than it did 
 before. So does the statement

But the 'a' is both times in the same namespace.

  self.a += 2

In this case the 'a' is not necessarily both times in the same
name space.

 So why are you so concerned that the pre-assignment reference comes from 
 a different scope to the post-assignment reference? The fact remains 
 that after both assignments the rebound name can no longer (ever) be 
 used to refer to its former referent without a further rebinding taking 
 place.

I concerned with the a refering to different variables. A variable being
a name in a specific namespace.

 If the b.a refers to the class variable then two should be added to it.
 
 Wring, wring, wring. (Sorry, got that wrong :-)

 Neither happens instead we get some hybrid in which an instance varible
 is created that gets the value of class variable incrented by two.
 
 Yes. So does this mean you also have a problem with

  def f(x):
  x += 2

  g = 3
  print f(g)

 When the function call executes, the name x is bound to an object in the 
 call's containing scope. Is it then your contention that the augmented 
 assignment in the function should add two to that object, changing the 
 value of g?

Whether I have a problem with this specific behaviour or not is
irrelevant. In this case we have only one namespace with an 'x'.
So searching for 'x' will not result in different variables being
found.

 It doesn't, it simply proceeds along the lines of all Python assignments 
 and resolves the name as a reference to a specific object. It then 
 computes a new value from the referenced object and the augmented 
 assignment operator's right operand, and rebinds the name to the 
 newly-computed value.

 Please stop talking about variables.

No I think variable is the right term here. It refers to a name
in a specific namespace.

 Although augmented assignment operators have the *option* of updating 
 objects in place, surely not even you can require that they do so when 
 they are bound to an immutable object such as an integer.

No but I can require that the namespace to which a name is resolved,
doesn't change during the operation.

It doesn't touch the *class variable* A.a which is still 1.
 
 Why should it? Why, why, why? And gain, just for good measure, why? 
 Augmented assignment to a function argument doesn't modify the passed 
 object when immutable, and you have no problem with that (I know as I 
 write that this is just asking for trouble, and it will turn out that 
 you also find that behavior deeply controversial ...)

 
 But it accesses the class variable.
 
 Repeat after me: Python assignment binds values to names.

But not just to a name, it binds a name in a specific namespace.

 When I write

  class something:
  a = 1
  def __init__(self, val=None):
  if val:
  self.a += val

 then in the last statement the augmented assignment rebinds self.a 
 from the class variable to a newly-created instance variable. I am 
 of course using the word variable here in a Pythonic sense, rather 
 than in the sense that, say, a C programmer would use. In Python I 
 prefer to talk about binding names because talking of variables leads 
 people to expect that a name is bound to an area of memory whose value 
 is modified by assignment, but this is in fact not so.

 The initial access to self.a uses the defined name resolution order to 
 locate a value that was bound to the name a in class scope. So what? 
 This is a long-documented fact of Python life. It's *supposed* to be 
 that way, dammit.

That it is documented, doesn't make it sane behaviour. Otherwise
all companies had to do was to document there bugs.

In a line like b.a += 2, you only have one reference to a name
to be resolved in a spefied namespace (hierarchy). Since there
is only one reference I don't think it is sane that two resolutions
are done with two different variables as a result.

 I fail to understand why this is such a problem for 

Re: Class Variable Access and Assignment

2005-11-04 Thread Stefan Arentz
Antoon Pardon [EMAIL PROTECTED] writes:

...

 Would it be too much to ask that in a line like.
 
   x = x + 1.
 
 both x's would resolve to the same namespace?

This is starting to look more like a nagging contest than a real
discussion imo.

Consider changing the semantics of what you are proposing and
think about all those Python projects that will break because they
depend on the above behaviour and even take advantage of it.

So in short: yes, it would be too much to ask :-)

But, you can fix it in your own code. Simply make sure that your
class variables have different names or a prefix.

 S.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Stefan Arentz
Antoon Pardon [EMAIL PROTECTED] writes:

 Op 2005-11-03, Mike Meyer schreef [EMAIL PROTECTED]:
  Antoon Pardon [EMAIL PROTECTED] writes:
  What would you expect to get if you wrote b.a = b.a + 2?
  I would expect a result consistent with the fact that both times
  b.a would refer to the same object.
 
  Except they *don't*. This happens in any language that resolves
  references at run time.
 
 Python doesn't resolve references at run time. If it did the following
 should work.
 
 a = 1
 def f():
   a = a + 1
 
 f()

No that has nothing to do with resolving things at runtime. Your example
does not work because the language is very specific about looking up
global variables. Your programming error, not Python's shortcoming.

 S.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Stefan Arentz schreef [EMAIL PROTECTED]:
 Antoon Pardon [EMAIL PROTECTED] writes:

 ...

  Ah yes. Well, good luck with that. You seem to have decided that it is not
  sane and who am I to argue with that. It depends on your state of mind :-)
 
 I can just say the opposite, that you seem to have decided that it is
 sane.

 I have. I like the Python model.

Fine good for you.

  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.
 
 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.

 Personally I don't see it as a shortcoming.

Which isn't the point.

 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 not at all. Just look at all the PEPs and the changes in the language
 that have been made in the past. Python is very much community driven and
 that shows in it's progress.

 You on the other hand keep talking about emo things like 'sane' and
 'madness' without giving any technical backing about these problems
 that you are having with the language.

That you took those emotionally, is not my responsibility. Would you
prefered it, had I called it a wart? As far as I see it, any negative
comment on python is reacted to in pretty much the same way. So
don't blame it on me using emotional language.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Paul Rubin
Stefan Arentz [EMAIL PROTECTED] writes:
  Would it be too much to ask that in a line like.
x = x + 1.
  both x's would resolve to the same namespace?
 ...
 Consider changing the semantics of what you are proposing and
 think about all those Python projects that will break because they
 depend on the above behaviour and even take advantage of it.

Are you seriously saying there's lots of Python projects that would
break if this particular weirdness were fixed?
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Stefan Arentz
Paul Rubin http://[EMAIL PROTECTED] writes:

 Stefan Arentz [EMAIL PROTECTED] writes:
   Would it be too much to ask that in a line like.
 x = x + 1.
   both x's would resolve to the same namespace?
  ...
  Consider changing the semantics of what you are proposing and
  think about all those Python projects that will break because they
  depend on the above behaviour and even take advantage of it.
 
 Are you seriously saying there's lots of Python projects that would
 break if this particular weirdness were fixed?

I have no numbers of course. But, why is this a weirdness? 

 S.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Magnus Lycka
Antoon Pardon wrote:
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?
 
 
 That is an implemantation detail. The only answer that you are given
 means nothing more than: because it is implemented that way.

Something that is written in the language reference is not
an implementation detail. Every implementation that aims to
be Python must follow this. It's a design decision.

Whether you like it or not, you will find out that the behaviour
of Python is largely based on an idea of an underlying structure.
A lot of the syntax is basically just convenient ways to access
this structure, and there is a strong tradition to avoid magic.

The explicit use of self might be the most obvious example of that,
but you can find a lot of other things in Python that shows you
this, __dict__ for instance.

I agree that the behaviour you are questioning isn't completely
unsurprising for someone who stumbles over it the first time, but
considering how things work in Python classes, where the class
scope is searched if a name isn't found in the instance scope
(self.__dict__), any other solution would involve more magic, and
be more surprising to someone who actually knows what is going on.

It's possible that a oldie like me, who started coding Python in
1996 is just blind to the warts in Python by now, but no language
is perfect, and whatever design decisions you make, they will have
both positive and negative consequences.

I frankly don't understand what you are after Antoon. Just to
vent your frustrations? If you want to use Python in an effective
way, try to learn how to use the language that actually exists.

Asking questions in this forum is clearly a part of that, but
your confrontational style, and idea that everything that bothers
you is a language bug that needs to be fixed is not the most
constructive approach. I'm pretty sure that it doesn't really solve
your coding problems, instead it leads the discussion away from the
practical solutions.

If you really want to improve the Python language, your approach
is completely off target. First of all, this isn't really the right
forum for that, and secondly, improvements to Python requires a
lot of cooperation and substantial contributions of work, not just
complaints, even if you might have a point now and then.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Mike Meyer
Antoon Pardon [EMAIL PROTECTED] writes:
 Op 2005-11-03, Mike Meyer schreef [EMAIL PROTECTED]:
 Antoon Pardon [EMAIL PROTECTED] writes:
 What would you expect to get if you wrote b.a = b.a + 2?
 I would expect a result consistent with the fact that both times
 b.a would refer to the same object.
 Except they *don't*. This happens in any language that resolves
 references at run time.
 Python doesn't resolve references at run time. If it did the following
 should work.

You left out a key word: all.

 a = 1
 def f():
   a = a + 1

 f()

If Python didn't resolve references at run time, the following
wouldn't work:

 def f():
...  global a
...  a = a + 1
... 
 a = 1
 f()
 

 But letting that aside. There is still a difference between resolving
 reference at run time and having the same reference resolved twice
 with each resolution a different result.

The second is a direct result of the first. The environment can change
between the references, so they resolve to different results.





 Changing that would be changing a fundamental
 - and *important* - feature of Python. Arbitrary restrictions to
 prevent a single case of this from doing something people who aren't
 used to suvh behavior are kludges, and would constitute a wart on the
 language, pure and simple.
 Python already has its warts. If you want to argue that fixing this
 would make a bigger wart then the wart it is now. Fine I will accept
 that.

I've already argued that the kludges suggested to solve this problem
create worse problems than this. This is a simple case of something
being unexpected to those used to less dynamic languages. The other
solutions break useful functionality, and require adding special cases
to the language - which aren't special enough to break the rules.

mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Mike Meyer

 Would it be too much to ask that in a line like.
 
   x = x + 1.
 
 both x's would resolve to the same namespace?

Yes. That's to much bondage for programmers who've become accustomed
to freedom. Explain why this should be illegal:

 class C:
...  def __getattr__(self, name):
...   x = 1
...   return locals()[name]
...  def __setattr__(self, name, value):
...   globals()[name] = value
... 
 o = C()
 o.x = o.x + 1
 x
2
 


mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Paul Rubin
Stefan Arentz [EMAIL PROTECTED] writes:
  Are you seriously saying there's lots of Python projects that would
  break if this particular weirdness were fixed?
 
 I have no numbers of course. But, why is this a weirdness? 

Do you seriously think the number is larger than zero?  Do you think
that's any good way to write code?

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.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Magnus Lycka schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
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?
 
 
 That is an implemantation detail. The only answer that you are given
 means nothing more than: because it is implemented that way.

 Something that is written in the language reference is not
 an implementation detail. Every implementation that aims to
 be Python must follow this. It's a design decision.

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.

I think one could argue that in the case of b.a += 1 and a
being a class variable that incrementing the class variable
was a similar effect in this case.

But I can be and maybe a more strict definition is available
that I looked over. Do happen to know one?

 Whether you like it or not, you will find out that the behaviour
 of Python is largely based on an idea of an underlying structure.
 A lot of the syntax is basically just convenient ways to access
 this structure, and there is a strong tradition to avoid magic.

Fine. I already wrote that if people think that changing this
behaviour would cause more problems than it solved or that
solving it would cause more problems than it is worth, I would
have no problem with that.

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

 The explicit use of self might be the most obvious example of that,
 but you can find a lot of other things in Python that shows you
 this, __dict__ for instance.

 I agree that the behaviour you are questioning isn't completely
 unsurprising for someone who stumbles over it the first time, but
 considering how things work in Python classes, where the class
 scope is searched if a name isn't found in the instance scope
 (self.__dict__), any other solution would involve more magic, and
 be more surprising to someone who actually knows what is going on.

It would be more suprising to someone depending on what is now
going on. 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. 

 It's possible that a oldie like me, who started coding Python in
 1996 is just blind to the warts in Python by now, but no language
 is perfect, and whatever design decisions you make, they will have
 both positive and negative consequences.

I completely agree. Personnaly I find python has withstood
its changes remarkebly well and I find the design in general
still very consistent despite the changes it underwent.

 I frankly don't understand what you are after Antoon. Just to
 vent your frustrations? If you want to use Python in an effective
 way, try to learn how to use the language that actually exists.

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.

 Asking questions in this forum is clearly a part of that, but
 your confrontational style, and idea that everything that bothers
 you is a language bug that needs to be fixed is not the most
 constructive approach.

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.

-- 
Antoon pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Mike Meyer schreef [EMAIL PROTECTED]:

 Would it be too much to ask that in a line like.
 
   x = x + 1.
 
 both x's would resolve to the same namespace?

 Yes. That's to much bondage for programmers who've become accustomed
 to freedom. Explain why this should be illegal:

 class C:
 ...  def __getattr__(self, name):
 ...   x = 1
 ...   return locals()[name]
 ...  def __setattr__(self, name, value):
 ...   globals()[name] = value
 ... 
 o = C()
 o.x = o.x + 1
 x
 2

I'll answer with a contra question.

Please explain why this is illegal.

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

f()

IMO your example and mine are essentially the same issue. A name in one
namespace shadowing a name in a different namespace.

So please explain how the same kind of bondage is no problem in the
function but is too much for those who've become accustomed to
freedom in the case of objects with class variables?

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Stefan Arentz schreef [EMAIL PROTECTED]:
 Antoon Pardon [EMAIL PROTECTED] writes:

 Op 2005-11-03, Mike Meyer schreef [EMAIL PROTECTED]:
  Antoon Pardon [EMAIL PROTECTED] writes:
  What would you expect to get if you wrote b.a = b.a + 2?
  I would expect a result consistent with the fact that both times
  b.a would refer to the same object.
 
  Except they *don't*. This happens in any language that resolves
  references at run time.
 
 Python doesn't resolve references at run time. If it did the following
 should work.
 
 a = 1
 def f():
   a = a + 1
 
 f()

 No that has nothing to do with resolving things at runtime. Your example
 does not work because the language is very specific about looking up
 global variables. Your programming error, not Python's shortcoming.

It has nothing to do with global variables, the same thing happens
with nested scopes.

def f():
  a = 1
  def g():
a = a + 1

  g()

f()
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Paul Rubin
Mike Meyer [EMAIL PROTECTED] writes:
 I've already argued that the kludges suggested to solve this problem
 create worse problems than this.

The most obvious solution is to permit (or even require) the
programmer to list the instance variables as part of the class
definition.  Anything not in the list is not an instance variable,
i.e. they don't get created dynamically.  That's what most other
languages I can think of do.  Some Python users incorrectly think this
is what __slots__ does, and try to use __slots__ that way.  That they
try to do that suggests that the approach makes some sense.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Mike Meyer schreef [EMAIL PROTECTED]:
 Antoon Pardon [EMAIL PROTECTED] writes:
 Op 2005-11-03, Mike Meyer schreef [EMAIL PROTECTED]:
 Antoon Pardon [EMAIL PROTECTED] writes:
 What would you expect to get if you wrote b.a = b.a + 2?
 I would expect a result consistent with the fact that both times
 b.a would refer to the same object.
 Except they *don't*. This happens in any language that resolves
 references at run time.
 Python doesn't resolve references at run time. If it did the following
 should work.

 You left out a key word: all.

 a = 1
 def f():
   a = a + 1

 f()

 If Python didn't resolve references at run time, the following
 wouldn't work:

 def f():
 ...  global a
 ...  a = a + 1
 ... 
 a = 1
 f()
 

Why do you think so? I see nothing here that couldn't work with
a reference resolved during compile time.

 But letting that aside. There is still a difference between resolving
 reference at run time and having the same reference resolved twice
 with each resolution a different result.

 The second is a direct result of the first. The environment can change
 between the references, so they resolve to different results.

No the second is not a direct result of the first. Since there is
only one reference, I see nothing wrong with the environment
remebering the reference and reusing it if it needs the reference
a second time.

Take the code:

  lst[f()] += 1

Now let f be a function with a side effect, that in succession
produces the positive integers starting with one.

What do you think this should be equivallent to:

  t = f()
  lst[t] = lst[t] + 1

or

  lst[f()] = lst[f()] + 1

If you think the environment can change between references then I
suppose you prefer the second approach.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Graham schreef [EMAIL PROTECTED]:
 Once again, many thanks, your explainations are very detailed and i
 think i'm in full understanding of the what/when/why of it all.

 And with further introspection i can see why its done this way from a
 language processing point of view rather than programming one. I also
 now realize that instance.classvarname is there so that you dont
 have to type instance.__class__.varname all the time.

You still have to if you want to change the class variable.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Steven D'Aprano
On Fri, 04 Nov 2005 07:31:46 +, Antoon Pardon wrote:

 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.
 
 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?


-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Steve Holden
Antoon Pardon wrote:
 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.

 
Plus I started 
using Icon, whose assignment semantics are very similar, back in the 
1970's, so Python's way of doing things fits my brain quite nicely, 
thank you.
 
 
 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
-- 
Steve Holden   +44 150 684 7255  +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006  www.python.org/pycon/

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Steve Holden
Paul Rubin wrote:
 Stefan Arentz [EMAIL PROTECTED] writes:
 
Are you seriously saying there's lots of Python projects that would
break if this particular weirdness were fixed?

I have no numbers of course. But, why is this a weirdness? 
 
 
 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.
-- 
Steve Holden   +44 150 684 7255  +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006  www.python.org/pycon/

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Steve Holden schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 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.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Paul Rubin
Steven D'Aprano [EMAIL PROTECTED] writes:
 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.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Fri, 04 Nov 2005 07:31:46 +, Antoon Pardon wrote:

 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.
 
 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.

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.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Magnus Lycka
Antoon Pardon wrote:
 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:

  class Counter:
... c=0
... def __call__(self):
... self.c+=1
... def __str__(self):
... return str(self.c)
...
  c=Counter()
  c()
  print c
1
  c()
  print c
2
  class C5(Counter):
... c=5
...
  c5=C5()
  c5()
  print c5
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:

  class APCounter:
... 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...
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Magnus Lycka schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 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.

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:

  class Counter:
 ... c=0
 ... def __call__(self):
 ... self.c+=1
 ... def __str__(self):
 ... return str(self.c)
 ...
  c=Counter()
  c()
  print c
 1
  c()
  print c
 2
  class C5(Counter):
 ... c=5
 ...
  c5=C5()
  c5()
  print c5
 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:

  class APCounter:
 ... 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.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Christopher Subich
Antoon Pardon wrote:
 Op 2005-11-03, Stefan Arentz schreef [EMAIL PROTECTED]:
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.
 
 
 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/

 a.x = foo

correspond exactly to

 setattr(a,'x',foo) #?

Similarly, why shouldn't

 foo = a.x

correspond exactly to

 foo = getattr(a,'x') #?

With that in mind, the logical action for

 a.x = f(a.x)

is

 setattr(a,'x',f(a,'x')) #,

and since

 a.x += foo

is equal to

 a.x = A.__iadd__(a.x,foo) # (at least for new-style classes
  # that have __iadd__ defined.  Otherwise, it falls back on
  # __add__(self,other) to return a new object, making this
  # evern more clear),

why shouldn't this translate into

 setattr(a,'x',A.__iadd__(getattr(a,'x'),foo)) #?

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.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Christopher Subich
Steven D'Aprano wrote:
 On Thu, 03 Nov 2005 14:13:13 +, Antoon Pardon wrote:
 
 
Fine, we have the code:

  b.a += 2

We found the class variable, because there is no instance variable,
then why is the class variable not incremented by two now?
 
 
 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.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Christopher Subich schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 Op 2005-11-03, Stefan Arentz schreef [EMAIL PROTECTED]:
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.
 
 
 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/

 a.x = foo

 correspond exactly to

 setattr(a,'x',foo) #?

 Similarly, why shouldn't

 foo = a.x

 correspond exactly to

 foo = getattr(a,'x') #?

 With that in mind, the logical action for

 a.x = f(a.x)

 is

 setattr(a,'x',f(a,'x')) #,

 and since

 a.x += foo

 is equal to

 a.x = A.__iadd__(a.x,foo) # (at least for new-style classes
  # that have __iadd__ defined.  Otherwise, it falls back on
  # __add__(self,other) to return a new object, making this
  # evern more clear),

 why shouldn't this translate into

 setattr(a,'x',A.__iadd__(getattr(a,'x'),foo)) #?

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.

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Antoon Pardon
Op 2005-11-04, Christopher Subich schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 Op 2005-11-03, Stefan Arentz schreef [EMAIL PROTECTED]:
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 []

-- 
Antoon Pardon
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Steven D'Aprano
On Fri, 04 Nov 2005 09:03:56 +, Antoon Pardon wrote:

 Op 2005-11-03, Steven D'Aprano schreef [EMAIL PROTECTED]:
 On Thu, 03 Nov 2005 13:01:40 +, Antoon Pardon wrote:

 Seems perfectly sane to me. 

 What would you expect to get if you wrote b.a = b.a + 2?
 
 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?
 
 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]
 
 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 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.


 But b.a is not a name, it is an attribute lookup,
 
 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 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'


 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.



-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Christopher Subich
Antoon Pardon wrote:
Since ints are immutable objects, you shouldn't expect the value of b.a
to be modified in place, and so there is an assignment to b.a, not A.a.
 
 
 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).
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Christopher Subich
Antoon Pardon wrote:
 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.
  a
Traceback (most recent call last):
   File stdin, line 1, in ?
NameError: name 'a' is not defined
  b = object()
  b.a
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.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Magnus Lycka
Graham wrote:
 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:

  class A:
... def f(self):
... print 'Hello'
...
  a = A()
  a.f()
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.

  class A:
... def f(self):
... print 'Hello'
...
  a = A()
  a.f()
Hello
  del A.f
  a.f()
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?
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Magnus Lycka
Antoon Pardon wrote:
   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.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Christopher Subich
Antoon Pardon wrote:

 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.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Christopher Subich
Antoon Pardon wrote:
 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.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Steve Holden
Antoon Pardon wrote:
 Op 2005-11-04, Steve Holden schreef [EMAIL PROTECTED]:
 
Antoon Pardon wrote:

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.
 
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.
 
You are wrong.

regards
  Steve
-- 
Steve Holden   +44 150 684 7255  +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006  www.python.org/pycon/

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Steven D'Aprano
On Fri, 04 Nov 2005 10:48:54 +, Antoon Pardon wrote:

 Please explain why this is illegal.
 
 x = 1
 def f():
   x += 1

Because names in function namespaces don't have inheritance.


-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Steven D'Aprano
On Fri, 04 Nov 2005 09:07:38 +, Antoon Pardon wrote:

 Now the b.a on the right hand side refers to A.a the first time through
 the loop but not the next times. I don't think it is sane that which
 object is refered to depends on how many times you already went through
 the loop.

[snip]

 Look at that: the object which is referred to depends on how many times
 you've already been through the loop. How nuts is that?
 
 It is each time the 'x' from the same name space. In the code above the
 'a' is not each time from the same namespace.
 
 I also think you new very well what I meant.

I'm supposed to be a mindreader now? After you've spent multiple posts
ranting that, quote, I don't think it is sane that which object is
refered to depends on how many times you already went through the loop,
I'm supposed to magically read your mind and know that you don't actually
object to what you say you object to, but to something completely
different?



-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Steven D'Aprano
On Fri, 04 Nov 2005 07:46:45 +, Antoon Pardon wrote:

 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?
 
 That is an implemantation detail. The only answer that you are given
 means nothing more than: because it is implemented that way.

You keep saying that's an implementation detail and dismissing the
question, but that's the heart of the issue. What does b.a += 2 *mean*? It
doesn't mean sort the list referenced by b.a -- we agree on that much.
You seem to think that it means increment the object currently named
b.a by two. But that's not what it means.

b.a += 2 has a precise meaning, and for ints and many other objects that
meaning is the same as b.a = b.a + 2. Yes, it is an implementation detail.
So what? It is an implementation detail that b.a += 2 doesn't mean sort
the list referenced by b.a too.

In some other language, that's precisely what it could mean -- but Python
is not that language.

b.a has a precise meaning too, and again you have got it wrong. It doesn't
mean search b's namespace for attribute a. It means search b's
namespace for attribute a, if not found search b's class' namespace, and
if still not found, search b's class' superclasses. It is analogous to
nested scopes. In fact, it is a type of nested scope.

In some other language, b.a could mean what you think it means, but Python
is not that language. That's a deliberate design decision. Nested
attribute search gives the most useful results in the most common cases,
while still being easy to work around in the rare cases where it is not
what is wanted.


 I'm not saying that it couldn't, if that was the model for inheritance you
 decided to use. I'm asking why would you want it? What is your usage case
 that demonstrates that your preferred inheritance model is useful?
 
 It has nothing to do with a model for inheritance, but with a model of
 name resolution.

Which is designed to act the way it does in order to produce the
inheritance model. You can't have that inheritance model without that name
resolution.


 The hierarchie of searching an instance first in an object and then in
 a class isn't that different from searching first in a local namespace
 and then in a more global namespace.
 
 When we search names in a function we don't resolve the same name in
 different name spacese each occurence of the same name in the same
 function occurs in the same namespace.

That's because it isn't needed for function namespaces. Names in a
function don't inherit state or behaviour from names in a higher-level
scope. Attribute names in classes do.


 But with class variables we can have that one and the same name
 on a line refers to two different namespaces at the same time.
 That is IMO madness. You may argue that the madness is of little
 importance, you can argue that because of the current implementation
 little can be done about it. But I don't see how one can defend
 it as sane behaviour.

Because inheritance is useful, sensible, rational behaviour for OO
programming.


-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Steven D'Aprano
On Fri, 04 Nov 2005 08:08:42 +, Antoon Pardon wrote:

 One other way, to implement the += and likewise operators would be
 something like the following.
 
 Assume a getnsattr, which would work like getattr, but would also
 return the namespace where the name was found. The implementation
 of b.a += 2 could then be something like:
 
   ns, t = getnsattr(b, 'a')
   t = t + 2
   setattr(ns, 'a')
 
 
 I'm not arguing that this is how it should be implemented. Just
 showing the implication doesn't follow.

Follow the logical implications of this proposed behaviour.

class Game:
current_level = 1
# by default, games start at level one  

def advance(self):
self.current_level += 1


py antoon_game = Game()
py steve_game = Game()
py steve_game.advance()
py steve_game.advance()
py print steve_game.level
3
py print antoon_game.level

What will it print?

Hint: your scheme means that class attributes mask instance attributes.


-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Steven D'Aprano
On Fri, 04 Nov 2005 04:42:54 -0800, Paul Rubin wrote:

 Steven D'Aprano [EMAIL PROTECTED] writes:
 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.

Dangerous? In what way?


A basic usage case:

class Paper:
size = A4
def __init__(self, contents):
# it makes no sense to have class contents,
# so contents go straight into the instance
self.contents = contents


To internationalise it for the US market:

Paper.size = USLetter

Now create a document using the default paper size:

mydocument = Paper(Four score and seven years ago)
print mydocument.size == USLetter
= True

Now create a document using another paper size:

page = Paper(Eleventy MILLION dollars)
page.size = Foolscap

Because that's an instance attribute, our default doesn't change:

assert Paper().size == mydocument.size == USLetter
assert page.size != mydocument.size

In case it wasn't obvious, this is the same inheritance behaviour Python
objects exhibit for methods, except that it isn't normal practice to add
methods to instances dynamically. (It is more common to create a
subclass.) But you can do it if you wish, at least for classes you create
yourself.

Objects in Python inherit behaviour from their class.
Objects in Python inherit state from their class, unless their state is
specifically stored in a per-instance basis.


Here's another usage case:

class PrintableWidget(Widget):
prefix = START 
suffix =  STOP

def __str__(self):
return self.prefix + Widget.__str__(self) + self.suffix

PrintableWidgets now print with a default prefix and suffix, which can be
easily changed on a per-instance basis without having to create
sub-classes for every conceivable modification:

english_gadget = PrintableWidget(data)
print english_gadget
= prints START data STOP

dutch_gadget = PrintableWidget(data)
dutch_gadget.prefix = BEGIN 
dutch_gadget.suffix =  EINDE
print dutch_gadget
= prints BEGIN data EINDE




I have to ask... did OO programming suddenly fall out of favour when my
back was turned? People still use C++, C#, Objective-C and Java, right?
Why are so many folks on this list having trouble with inheritance? Have I
missed something?


-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Bengt Richter
On 4 Nov 2005 08:23:05 GMT, Antoon Pardon [EMAIL PROTECTED] wrote:

Op 2005-11-03, Magnus Lycka schreef [EMAIL PROTECTED]:
 Antoon Pardon wrote:
 There is no instance variable at that point. How can it add 2, to
 something that doesn't exist at the moment.

 Because 'a += 1' is only a shorthand for 'a = a + 1' if a is an
 immutable object? Anyway, the behaviour is well documented.

 http://docs.python.org/ref/augassign.html says:

 An augmented assignment expression like x += 1 can be rewritten as x = x 
 + 1 to achieve a similar, but not exactly equal effect. In the augmented 
 version, x is only evaluated once.

Then couldn't we expect that the namespace resolution is also done
only once?

I say that if the introduction on += like operators implied that the
same mentioning of a name would in some circumstances be resolved to
two different namespaces, then such an introduction would better have
not occured.

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

  x = x + 1.

both x's would resolve to the same namespace?

I think I would rather seek consistency in terms of
order of evaluation and action. IOW, the right hand side
of an assignment is always evaluated before the left hand side,
and operator precedence and syntax defines order of access to names
in their expression context on either side.

The compilation of function bodies violates the above, even allowing
future (execution-wise) statements to influence the interpretation
of prior statements. This simplifies defining the local variable set,
and allows e.g. yield to change the whole function semantics, but
the practicality/purity ratio makes me uncomfortable ;-)

If there were bare-name properties, one could control the meaning
of x = x + 1 and x += 1, though of course one would need some way
to bind/unbind the property objects themselves to make them visible
as x or whatever names.

It might be interesting to have a means to push and pop objects
onto/off-of a name-space-shadowing stack (__nsstack__), such that the first 
place
to look up a bare name would be as an attribute of the top stack object, i.e.,
   
name = name + 1

if preceded by   

__nsstack__.append(my_namespace_object)

would effectively mean

my_namespace_object.name = my_namespace_object.name + 1

by way of logic like

if __nsstack__:
setattr(__nsstack__[-1], getattr(__nstack__[-1], name) + 1))
else:
x = x + 1


Of course, my_namespace_object could be an instance of a class
that defined whatever properties or descriptors you wanted.
When you were done with that namespace, you'd just __nsstack__.pop()

If __nsstack__ is empty, then of course bare names would be looked
up as now.

BTW, __nsstack__ is not a literal proposal, just a way to illustrate the 
concept ;-)
OTOH, is suppose a function could have a reseved slot for a name space object 
stack
that wouldn't cost much run time to bypass with a machine language check for 
NULL.

BTW2, this kind of stack might play well with a future with, to guarantee name
space popping. Perhaps with syntax could even be extended to make typical 
usage
slick ;-)

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Christopher Subich
Bengt Richter wrote:
 
 It might be interesting to have a means to push and pop objects
 onto/off-of a name-space-shadowing stack (__nsstack__), such that the first 
 place
 to look up a bare name would be as an attribute of the top stack object, i.e.,

 name = name + 1
 

Don't be that specific; just unify Attributes and Names.

Instead of the 'name' X referring to locals()['X'] or globals()['X'], 
have a hidden namespace object/class, with lookups functioning akin 
to class inheritence.

This would allow, in theory, more uniform namespace behaviour with outer 
scoping:

x = 1
def f():
x += 1 # would work, as it becomes 
setattr(namespace,'x',getattr(namespace,'x')+1), just like attribute loookup

Also, with a new keyword outer, more rational closures would work:

def makeincr(start=0):
i = start
def inc():
   outer i
   j = i
   i += 1
   return j
return inc

 From a namespace object point of view, 'outer i' would declare i to 
be a descriptor on the namespace object, such that setting actions would 
set the variable in the inherited scope (getting actions wouldn't 
actually need modification, since it already falls-through).  At the 
first level, 'outer' would be exactly the same as 'global' -- indeed, it 
would be reasonable for the outer keyword to entirely replace global 
(which is actually module-scope).

As it stands, the different behaviours of names and attributes is only a 
minor quirk, and the fix would definitely break backwards compatibility 
in the language -- it'd have to be punted to Py3k.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Paul Rubin
Steven D'Aprano [EMAIL PROTECTED] writes:
 Follow the logical implications of this proposed behaviour.
 
 class Game:
 current_level = 1
 # by default, games start at level one  

That's bogus.  Initialize the current level in the __init__ method
where it belongs.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Mike Meyer
Paul Rubin http://[EMAIL PROTECTED] writes:
 Mike Meyer [EMAIL PROTECTED] writes:
 I've already argued that the kludges suggested to solve this problem
 create worse problems than this.
 The most obvious solution is to permit (or even require) the
 programmer to list the instance variables as part of the class
 definition.  Anything not in the list is not an instance variable,
 i.e. they don't get created dynamically.  That's what most other
 languages I can think of do.  Some Python users incorrectly think this
 is what __slots__ does, and try to use __slots__ that way.  That they
 try to do that suggests that the approach makes some sense.

That breaks the ability to add attributes dynamically, which is
usefull. If you need an extra piece of data with some existing class,
it's much easier to just add an attribute to hold it than to create a
subclass for the sole purpose of adding that attribute.

  mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Mike Meyer
Antoon Pardon [EMAIL PROTECTED] writes:

 Op 2005-11-04, Mike Meyer schreef [EMAIL PROTECTED]:

 Would it be too much to ask that in a line like.
 
   x = x + 1.
 
 both x's would resolve to the same namespace?

 Yes. That's to much bondage for programmers who've become accustomed
 to freedom. Explain why this should be illegal:

 class C:
 ...  def __getattr__(self, name):
 ...   x = 1
 ...   return locals()[name]
 ...  def __setattr__(self, name, value):
 ...   globals()[name] = value
 ... 
 o = C()
 o.x = o.x + 1
 x
 2

 I'll answer with a contra question.

 Please explain why this is illegal.

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

 f()

It isn't illegal, it just requires a different syntax.

   mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Mike Meyer
Antoon Pardon [EMAIL PROTECTED] writes:
 Op 2005-11-04, Mike Meyer schreef [EMAIL PROTECTED]:
 Antoon Pardon [EMAIL PROTECTED] writes:
 Op 2005-11-03, Mike Meyer schreef [EMAIL PROTECTED]:
 Antoon Pardon [EMAIL PROTECTED] writes:
 What would you expect to get if you wrote b.a = b.a + 2?
 I would expect a result consistent with the fact that both times
 b.a would refer to the same object.
 Except they *don't*. This happens in any language that resolves
 references at run time.
 Python doesn't resolve references at run time. If it did the following
 should work.

 You left out a key word: all.

 a = 1
 def f():
   a = a + 1

 f()

 If Python didn't resolve references at run time, the following
 wouldn't work:

 def f():
 ...  global a
 ...  a = a + 1
 ... 
 a = 1
 f()
 

 Why do you think so? I see nothing here that couldn't work with
 a reference resolved during compile time.

a - in the global name space - doedn't exist when f is compiled, and
hence can't be dereferenced at compile time. Of course, sufficiently
advanced analysis can figure out that a would exist before f is run,
but that's true no matter how a is added. That isn't the way python
works.

 But letting that aside. There is still a difference between resolving
 reference at run time and having the same reference resolved twice
 with each resolution a different result.
 The second is a direct result of the first. The environment can change
 between the references, so they resolve to different results.
 No the second is not a direct result of the first. Since there is
 only one reference, I see nothing wrong with the environment
 remebering the reference and reusing it if it needs the reference
 a second time.

Please stay on topic: we're talking about a = a + 1, not a += 1.
The former has two references, not one. I've already agreed that the
semantics of += are a wart.

 mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Mike Meyer
Steven D'Aprano [EMAIL PROTECTED] writes:
 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?

For the record, I've only seen one interpreter that actually
interpreted the source directly. Pretty much all of the rest of them
do a lexical analysis, turning keywords into magic tokens (dare I say
byte codes) and removing as much white space as possible. Or maybe
that's what you meant?

   mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Magnus Lycka
Paul Rubin wrote:
 Steven D'Aprano [EMAIL PROTECTED] writes:
 
Follow the logical implications of this proposed behaviour.

class Game:
current_level = 1
# by default, games start at level one  
 
 
 That's bogus.  Initialize the current level in the __init__ method
 where it belongs.

But there is a relevant use case for this:

If you have a class hierarchy, where the difference between the
classes is mainly/completely a matter of data, i.e. default
values. Then it's very convenient to use such defaults in the
class scope.

Of course, you *could* have an __init__ in the base class that
copies this data from class scope to instance scope on instance
creation, but why make it more complicated?

You could also imagine cases where you have many instances and
a big immutable variable which typically stays as default, but
must sometimes vary between instances.

As I explained in another post, member lookups in the instance
must look in the class to find methods, so why not get used to
the fact that it works like this, and use it when it's convenient.
It's not as if anyone puts a gun to your head and force you to
use this feature.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Paul Rubin
Steven D'Aprano [EMAIL PROTECTED] writes:
 A basic usage case:
 
 class Paper:
 size = A4
 def __init__(self, contents):
 # it makes no sense to have class contents,
 # so contents go straight into the instance
 self.contents = contents

So add:

 self.size = Paper.size

and you've removed the weirdness.  What do you gain here by inheriting?
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Bengt Richter
On Fri, 04 Nov 2005 02:59:35 +1100, Steven D'Aprano [EMAIL PROTECTED] wrote:

On Thu, 03 Nov 2005 14:13:13 +, Antoon Pardon wrote:

 Fine, we have the code:
 
   b.a += 2
 
 We found the class variable, because there is no instance variable,
 then why is the class variable not incremented by two now?
Because the class variable doesn't define a self-mutating __iadd__
(which is because it's an immutable int, of course). If you want
b.__dict__['a'] += 2 or b.__class__.__dict__['a'] += 2 you can
always write it that way ;-)

(Of course, you can use a descriptor to define pretty much whatever semantics
you want, when it comes to attributes).


Because b.a += 2 expands to b.a = b.a + 2. Why would you want b.a =

No, it doesn't expand like that. (Although, BTW, a custom import could
make it so by transforming the AST before compiling it ;-)

Note BINARY_ADD is not INPLACE_ADD:

  def foo(): # for easy disassembly
 ... b.a += 2
 ... b.a = b.a + 2
 ...
  import dis
  dis.dis(foo)
   2   0 LOAD_GLOBAL  0 (b)
   3 DUP_TOP
   4 LOAD_ATTR1 (a)
   7 LOAD_CONST   1 (2)
  10 INPLACE_ADD
  11 ROT_TWO
  12 STORE_ATTR   1 (a)

   3  15 LOAD_GLOBAL  0 (b)
  18 LOAD_ATTR1 (a)
  21 LOAD_CONST   1 (2)
  24 BINARY_ADD
  25 LOAD_GLOBAL  0 (b)
  28 STORE_ATTR   1 (a)
  31 LOAD_CONST   0 (None)
  34 RETURN_VALUE

And BINARY_ADD calls __add__ and INPLACE_ADD calls __iadd__ preferentially.

About __ixxx__:

These methods are called to implement the augmented arithmetic operations
(+=, -=, *=, /=, %=, **=, =, =, =, ^=, |=).
These methods should attempt to do the operation in-place (modifying self)
and return the result (which could be, but does not have to be, self).
If a specific method is not defined, the augmented operation falls back
to the normal methods. For instance, to evaluate the expression x+=y,
where x is an instance of a class that has an __iadd__() method,
x.__iadd__(y) is called. If x is an instance of a class that does not define
a __iadd() method, x.__add__(y) and y.__radd__(x) are considered, as with
the evaluation of x+y. 



something to correspond to b.__class__.a = something?

I'm not saying that it couldn't, if that was the model for inheritance you
decided to use. I'm asking why would you want it? What is your usage case
that demonstrates that your preferred inheritance model is useful?

It can be useful to find-and-rebind (in the namespace where found) rather
than use separate rules for finding (or not) and binding. The tricks for
boxing variables in closures show there is useful functionality that
is still not as convenient to spell as could be imagined.
It is also useful to find and bind separately. In fact, IMO it's not
separate enough in some cases ;-)

I've wanted something like
x := expr
to spell find x and rebind it to expr (or raise NameError if not found).
Extending that to attributes and augassign,
b.a +:= 2
could mean find the a attribute, and in whatever attribute dict it's found,
rebind it there. Or raise an Exception for whatever failure is encountered.
This would be nice for rebinding closure variables as well. But it's been 
discussed,
like most of these things ;-)

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Bengt Richter
On Thu, 03 Nov 2005 13:37:08 -0500, Mike Meyer [EMAIL PROTECTED] wrote:
[...]
 I think it even less sane, if the same occurce of b.a refers to two
 different objects, like in b.a += 2

That's a wart in +=, nothing less. The fix to that is to remove +=
from the language, but it's a bit late for that.

Hm, the fix? Why wouldn't e.g. treating augassign as shorthand for a source 
transformation
(i.e., asstgt op= expr  becomes by simple text substitution asstgt = asstgt 
op expr)
be as good a fix? Then we could discuss what

b.a = b.a + 2

should mean ;-)

OTOH, we could discuss how you can confuse yourself with the results of b.a += 2
after defining a class variable a as an instance of a class defining __iadd__ 
;-)

Or point out that you can define descriptors (or use property to make it easy)
to control what happens, pretty much in as much detail as you can describe 
requirements ;-)

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Bengt Richter
On 04 Nov 2005 11:04:58 +0100, Stefan Arentz [EMAIL PROTECTED] wrote:

Antoon Pardon [EMAIL PROTECTED] writes:

 Op 2005-11-03, Mike Meyer schreef [EMAIL PROTECTED]:
  Antoon Pardon [EMAIL PROTECTED] writes:
  What would you expect to get if you wrote b.a = b.a + 2?
  I would expect a result consistent with the fact that both times
  b.a would refer to the same object.
 
  Except they *don't*. This happens in any language that resolves
  references at run time.
 
 Python doesn't resolve references at run time. If it did the following
 should work.
 
 a = 1
 def f():
   a = a + 1
 
 f()

No that has nothing to do with resolving things at runtime. Your example
does not work because the language is very specific about looking up
global variables. Your programming error, not Python's shortcoming.

If someone has an old version of Python handy, I suspect that it used
to work, and the a on the right hand side was the global a because
a local a hadn't been defined until the assignment, which worked to
produce a local binding of a. Personally, I like that better than
the current way, because it follows the order of accesses implied
by the precedences in expression evaluation and statement execution.
But maybe I don't RC ;-)

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Paul Rubin
[EMAIL PROTECTED] (Bengt Richter) writes:
 Hm, the fix? Why wouldn't e.g. treating augassign as shorthand for
 a source transformation (i.e., asstgt op= expr becomes by simple
 text substitution asstgt = asstgt op expr) be as good a fix? Then
 we could discuss what

Consider a[f()] += 3.  You don't want to eval f() twice.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Bengt Richter
On 4 Nov 2005 11:09:36 GMT, Antoon Pardon [EMAIL PROTECTED] wrote:
[...]

Take the code:

  lst[f()] += 1

Now let f be a function with a side effect, that in succession
produces the positive integers starting with one.

What do you think this should be equivallent to:

  t = f()
  lst[t] = lst[t] + 1

or

  lst[f()] = lst[f()] + 1

If you think the environment can change between references then I
suppose you prefer the second approach.

I am quite sympathetic to your probe of python semantics, but I
don't think the above is an argument that should be translated
to attribute assignment. BTW, ISTM that augassign (+=) is
a red herring here, since it's easy to make a shared class variable
that is augassigned apparently as you want, e.g.,

  class shared(object):
 ... def __init__(self, v=0): self.v=v
 ... def __get__(self, *any): return self.v
 ... def __set__(self, _, v): self.v = v
 ...
  class B(object):
 ... a = shared(1)
 ...
  b=B()
  b.a
 1
  B.a
 1
  b.a += 2
  b.a
 3
  B.a
 3
  vars(b)
 {}
  vars(b)['a'] = 'instance attr'
  vars(b)
 {'a': 'instance attr'}
  b.a
 3
  b.a += 100
  b.a
 103
  B.a
 103
  B.a = 'this could be prevented'
  b.a
 'instance attr'
  B.a
 'this could be prevented'

The spelled out attribute update works too
  B.a = shared('alpha')
  b.a
 'alpha'
  b.a = b.a + ' beta'
  b.a
 'alpha beta'
  B.a
 'alpha beta'

But the instance attribute we forced is still there
  vars(b)
 {'a': 'instance attr'}

You could have shared define __add__ and __iadd__ and __radd__ also,
for confusion to taste ;-)

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Mike Meyer
[EMAIL PROTECTED] (Bengt Richter) writes:
 On Thu, 03 Nov 2005 13:37:08 -0500, Mike Meyer [EMAIL PROTECTED] wrote:
 [...]
 I think it even less sane, if the same occurce of b.a refers to two
 different objects, like in b.a += 2

That's a wart in +=, nothing less. The fix to that is to remove +=
from the language, but it's a bit late for that.

 Hm, the fix? Why wouldn't e.g. treating augassign as shorthand for a source 
 transformation
 (i.e., asstgt op= expr  becomes by simple text substitution asstgt = asstgt 
 op expr)
 be as good a fix? Then we could discuss what

 b.a = b.a + 2

 should mean ;-)

The problem with += is how it behaves, not how you treat it. But you
can't treat it as a simple text substitution, because that would imply
that asstgt gets evaluated twice, which doesn't happen.

 OTOH, we could discuss how you can confuse yourself with the results of b.a 
 += 2
 after defining a class variable a as an instance of a class defining 
 __iadd__ ;-)

You may confuse yourself that way, I don't have any problems with it
per se.

 Or point out that you can define descriptors (or use property to make it easy)
 to control what happens, pretty much in as much detail as you can describe 
 requirements ;-)

I've already pointed that out.

 mike
-- 
Mike Meyer [EMAIL PROTECTED]  http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Steven D'Aprano
On Fri, 04 Nov 2005 18:20:56 -0500, Mike Meyer wrote:

 Steven D'Aprano [EMAIL PROTECTED] writes:
 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?
 
 For the record, I've only seen one interpreter that actually
 interpreted the source directly. Pretty much all of the rest of them
 do a lexical analysis, turning keywords into magic tokens (dare I say
 byte codes) and removing as much white space as possible. Or maybe
 that's what you meant?

We could argue about details of a throw away line for hours :-)

What I meant was, there is the way Python does it, and then there are (or
were) interpreters that when faced with a block like this:

for i in range(10):
   print i

parses print i ten times.

It doesn't really matter whether any interpreters back in the 1970s were
actually that bad, or just toy interpreters as taught about in undergrad
university courses.


-- 
Steven.

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


Re: Class Variable Access and Assignment

2005-11-04 Thread Bengt Richter
On Fri, 04 Nov 2005 09:24:41 -0500, Christopher Subich [EMAIL PROTECTED] 
wrote:

Steven D'Aprano wrote:
 On Thu, 03 Nov 2005 14:13:13 +, Antoon Pardon wrote:
 
 
Fine, we have the code:

  b.a += 2

We found the class variable, because there is no instance variable,
then why is the class variable not incremented by two now?
 
 
 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.
But before you get to that, a (possibly inherited) type(b).a better
not have a __get__ method trumping __class__ and the rest ;-)

Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Class Variable Access and Assignment

2005-11-04 Thread Steven D'Aprano
On Fri, 04 Nov 2005 16:06:45 -0800, Paul Rubin wrote:

 Steven D'Aprano [EMAIL PROTECTED] writes:
 A basic usage case:
 
 class Paper:
 size = A4
 def __init__(self, contents):
 # it makes no sense to have class contents,
 # so contents go straight into the instance
 self.contents = contents
 
 So add:
 
  self.size = Paper.size
 
 and you've removed the weirdness.  What do you gain here by inheriting?


Documents which don't care what paper size they are will automatically use
the default paper size on whatever system they are opened under. Send them
to somebody in the US, and they will use USLetter. Send to someone in
Australia, and they will use A4.

In any case, even if you conclude that there is little benefit to
inheritance in this particular example, the principle is sound:
sometimes you gain benefit by inheriting state.



-- 
Steven.

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


  1   2   >