473,473 Members | 1,823 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Bug or feature?

Hello. Found a strange python behaivoir while writing some object. I've
stripped out all other stuff so the problem is stright here:
=================================
#!/usr/bin/python

class Object:
def __init__(self,val):
self.val=val

def Sub(self,delta):
self.val-=delta
return delta

c=Object(1)

### case 1 ###
d=c.Sub(1)
c.val+=d
print 'case A:',c.val

### case 2 ###
c.val+=c.Sub(1)
print 'case B:',c.val
=================================
Case 1 and case 2 prints out different calues (1 and 2 respectively).
Do not know - if this is a bug or feature of python.

--
Alexey Nezhdanov

Jul 18 '05 #1
16 1280
On Thursday 15 January 2004 5:40 am, Alexey Nezhdanov wrote:
Hello. Found a strange python behaivoir while writing some object. I've
stripped out all other stuff so the problem is stright here:
=================================
#!/usr/bin/python

class Object:
def __init__(self,val):
self.val=val

def Sub(self,delta):
self.val-=delta
return delta

c=Object(1)

### case 1 ###
d=c.Sub(1)
c.val+=d
print 'case A:',c.val

### case 2 ###
c.val+=c.Sub(1)
print 'case B:',c.val
=================================
Case 1 and case 2 prints out different calues (1 and 2 respectively).
Do not know - if this is a bug or feature of python.

--
Alexey Nezhdanov


This is the expected behaviour.

The terms on the RHS (c.val and c.Sub(1) in case 2) are evaluated left to
right before being added together. If you'd reversed the terms of case 2 and
written:

c.val = c.Sub(1) + c.val

c.val would end up as 1.

James
Jul 18 '05 #2
Alexey Nezhdanov fed this fish to the penguins on Wednesday 14 January
2004 21:40 pm:
Case 1 and case 2 prints out different calues (1 and 2 respectively).
Do not know - if this is a bug or feature of python.
It's a problem with using what I would consider a side effect... And
not understanding that "variables" are not memory addresses.

Observe -- I've explicitly made all "var" accesses methods of the
class, which means the equations have to be written in long form:

class O:
def __init__(self, ival):
self._val = ival
print "__init__", self._val

def Sub(self, delta):
self._val -= delta
print "Sub", self._val
return delta

def GetVal(self):
print "GetVal", self._val
return self._val

def SetVal(self, nval):
self._val = nval
print "SetVal", self._val

c = O(1)

print c.GetVal()
print

d = c.Sub(1)
c.SetVal(c.GetVal() + d)

print c.GetVal()
print

c.SetVal(c.GetVal() + c.Sub(1))

print c.GetVal()
print

c.SetVal(c.Sub(1) + c.GetVal())

print c.GetVal()
print

And here is the result of the run:

[wulfraed@beastie wulfraed]$ python t.py
__init__ 1
GetVal 1
1

Sub 0
GetVal 0
SetVal 1
GetVal 1
1

GetVal 1
Sub 0
SetVal 2
GetVal 2
2

Sub 1
GetVal 1
SetVal 2
GetVal 2
2

Note how the order of the Sub() and GetVal() calls affects the result.
--
Alexey Nezhdanov

-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Bestiaria Home Page: http://www.beastie.dm.net/ <
Home Page: http://www.dm.net/~wulfraed/ <


Jul 18 '05 #3

"Dennis Lee Bieber" <wl*****@ix.netcom.com> wrote in message
news:3d************@beastie.ix.netcom.com...
Alexey Nezhdanov fed this fish to the penguins on Wednesday 14 January
2004 21:40 pm:
Case 1 and case 2 prints out different calues (1 and 2 respectively).
Do not know - if this is a bug or feature of python.
It's a problem with using what I would consider a side effect...

And not understanding that "variables" are not memory addresses.


In particular, the problem with both modifying in place (the side effect)
and returning a value. I see a little better Guido's reason for having
list modification methods return None. While chaining is not too
problematical, object returns would allow list expressions mixing implicit
and overt effects with possible puzzles similar to the one presented in
this thread.

Terry J. Reedy
Jul 18 '05 #4
Terry Reedy fed this fish to the penguins on Thursday 15 January 2004
15:39 pm:

and returning a value. I see a little better Guido's reason for
having
list modification methods return None. While chaining is not too
problematical, object returns would allow list expressions mixing
implicit and overt effects with possible puzzles similar to the one
presented in this thread.
Now that you mention it... Yeah... Can you imagine trying to figure
out what something like

alist = ['j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']
res = alist[:5] + alist.sort() + alist[5:]

was supposed to return?

jihgfabcdefghijedcba
or
jihgfabcdefghijabcde
or
abcdeabcdefghijabcde
or
abcdeabcdefghijfghij

The only "known" is that the middle is supposed to be abcdefghij, but
the left and right ends depend solely on order of evaluation...

-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Bestiaria Home Page: http://www.beastie.dm.net/ <
Home Page: http://www.dm.net/~wulfraed/ <


Jul 18 '05 #5
Terry Reedy wrote:
"Dennis Lee Bieber" <wl*****@ix.netcom.com> wrote in message
news:3d************@beastie.ix.netcom.com...
Alexey Nezhdanov fed this fish to the penguins on Wednesday 14 January
2004 21:40 pm:

Case 1 and case 2 prints out different calues (1 and 2 respectively).
Do not know - if this is a bug or feature of python.


It's a problem with using what I would consider a side effect...


And
not understanding that "variables" are not memory addresses.

In particular, the problem with both modifying in place (the side effect)
and returning a value. I see a little better Guido's reason for having
list modification methods return None. While chaining is not too
problematical, object returns would allow list expressions mixing implicit
and overt effects with possible puzzles similar to the one presented in
this thread.

Terry J. Reedy


So since the word "problem" is so popular in this tred I have an another
question:
Does anybody agree that this is a python problem and not a programmer
problem?

Let me explain.
I DO know that this behaivoir of python is matches the DOCS and all
declared official language laws.
I DO know why it is happening and how to fix my program to solve the
problem (in fact I already knowed it when written my first post here).
I DO know that fixing on python level it will rise particular
incompartibility with previous versions of python.
BUT
I know the case where such python behaivoir causes hard-to-catch problems.
I do not know any case (anybody knows? please give example) where such
"feature" may be useful.

So I proposing to make a change into python and reverse the order of
calculations.
Just for sure:
=== Order used now ===
## a+=a.Sub(b)
1. evaluate value of 'a'
2. evaluate value of 'a.Sub(b)'
3. evaluate the sum
4. store the result into 'a'
=== Proposed order ===
## a+=a.Sub(b)
1. evaluate value of 'a.Sub(b)'
2. evaluate value of 'a'
3. evaluate the sum
4. store the result into 'a'

(same about -=, *=,... of course)

--
Respectfully
Alexey Nezhdanov

Jul 18 '05 #6
On Fri, Jan 16, 2004 at 08:31:32AM +0000, Dennis Lee Bieber wrote:
Terry Reedy fed this fish to the penguins on Thursday 15 January 2004
15:39 pm:

and returning a value. I see a little better Guido's reason for having
list modification methods return None. While chaining is not too
problematical, object returns would allow list expressions mixing
implicit and overt effects with possible puzzles similar to the one
presented in this thread.

Now that you mention it... Yeah... Can you imagine trying to figure
out what something like

alist = ['j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']
res = alist[:5] + alist.sort() + alist[5:]

was supposed to return?

jihgfabcdefghijedcba
or
jihgfabcdefghijabcde
or
abcdeabcdefghijabcde
or
abcdeabcdefghijfghij

The only "known" is that the middle is supposed to be abcdefghij, but
the left and right ends depend solely on order of evaluation...


http://python.org/doc/current/ref/evalorder.html

Doesn't seem to be a problem, after all.

Jp

Jul 18 '05 #7
Now that you mention it... Yeah... Can you imagine trying to figure
out what something like

alist = ['j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']
res = alist[:5] + alist.sort() + alist[5:]

was supposed to return?
...
The only "known" is that the middle is supposed to be abcdefghij, but
the left and right ends depend solely on order of evaluation...


That's easy. You get a TypeError exception, because alist.sort() returns
None.

Like Jp said:

Jp> Doesn't seem to be a problem, after all.

Skip

Jul 18 '05 #8
Skip Montanaro fed this fish to the penguins on Friday 16 January 2004
07:44 am:


That's easy. You get a TypeError exception, because alist.sort()
returns None.
That is the behavior in the real Python... The example was meant to
apply to a hypothetical version where operations like [].sort()
modified in place /and/ returned the modified list for chained
operations.

The example was meant to illustrate the perils of side-effects in
functions. A casual newcomer to programming could be perplexed by the
left-to-right evaluation if they were expecting to just have a sorted
copy embedded in the middle, as the side-effect would have changed the
value of the right-end expression.

-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Bestiaria Home Page: http://www.beastie.dm.net/ <
Home Page: http://www.dm.net/~wulfraed/ <


Jul 18 '05 #9
On Friday 16 January 2004 2:44 pm, Alexey Nezhdanov wrote:
<snip>
I know the case where such python behaivoir causes hard-to-catch problems.
I do not know any case (anybody knows? please give example) where such
"feature" may be useful.

So I proposing to make a change into python and reverse the order of
calculations.
Just for sure:
=== Order used now ===
## a+=a.Sub(b)
1. evaluate value of 'a'
2. evaluate value of 'a.Sub(b)'
3. evaluate the sum
4. store the result into 'a'
=== Proposed order ===
## a+=a.Sub(b)
1. evaluate value of 'a.Sub(b)'
2. evaluate value of 'a'
3. evaluate the sum
4. store the result into 'a'


-1
In any language that uses such an operator I would expect:

a += b

to be synonymous with:

a = a + b

You are suggesting that it should mean:

a = b + a

It is not like Python to attach its own idiosyncratic semantics to operators
already well known from other languages. I think this would catch a lot of
people out.

Of course, it's probably best to avoid writing code where the order makes a
difference. :)

James
--
James Henderson, Logical Progression Ltd.
http://www.logicalprogression.net/
Jul 18 '05 #10
Alexey Nezhdanov fed this fish to the penguins on Friday 16 January
2004 06:44 am:


So I proposing to make a change into python and reverse the order of
calculations.
Just for sure:
=== Order used now ===
## a+=a.Sub(b)
1. evaluate value of 'a'
2. evaluate value of 'a.Sub(b)'
3. evaluate the sumf
4. store the result into 'a'
=== Proposed order ===
## a+=a.Sub(b)
1. evaluate value of 'a.Sub(b)'
2. evaluate value of 'a'
3. evaluate the sum
4. store the result into 'a'

(same about -=, *=,... of course)
But, since Python is dynamically typed, reversing the evaluation order
could have major effects on other operations... The "problem" is not
the order of evaluation, but that you have a "hidden" modification to a
term occurring.
def se(a): #side-effect .... a.insert(0,3)
.... return a
.... def nose(a): #no side-effect .... a = [3] + list(a)
.... return a
.... l = [1,5,7]
l += nose(l)
l [1, 5, 7, 3, 1, 5, 7] l = [1,5,7]
l += se(l)
l [3, 1, 5, 7, 3, 1, 5, 7] l = [1,5,7]

A very long time ago, some FORTRAN compilers had "non-constant
constants"...

subroutine Modify(a, b)
a = a + b
return
end

program demo
call Modify(1, 3)
print 1
stop
end

On these machines, calling Modify would result in the "constant" 1
taking the value of /4/, and the print statement would print 4.
Nowaday's it is normal to place all such constants in a read-only block
of memory, generating a trap when a modification is attempted. Other
languages have explicit usage qualifications allowing a compiler to
determine validity.

None of which can be done in Python if one passes in a mutable object.

-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Bestiaria Home Page: http://www.beastie.dm.net/ <
Home Page: http://www.dm.net/~wulfraed/ <


Jul 18 '05 #11

"Jp Calderone" <ex*****@intarweb.us> wrote in message
news:ma**************************************@pyth on.org...
On Fri, Jan 16, 2004 at 08:31:32AM +0000, Dennis Lee Bieber wrote:
Terry Reedy fed this fish to the penguins on Thursday 15 January 2004
15:39 pm:

and returning a value. I see a little better Guido's reason for having list modification methods return None. While chaining is not too
problematical, object returns would allow list expressions mixing
implicit and overt effects with possible puzzles similar to the one
presented in this thread.
Now that you mention it... Yeah... Can you imagine trying to figure out what something like...
http://python.org/doc/current/ref/evalorder.html
Doesn't seem to be a problem, after all.


Not for you, but how about newbie and others who don't read or ignore,
misunderstand, or reject what they read? Lets try this example based on
OP's real examples. Again, hypothetical, assuming list mutators were to
return list.

l3 = range(3)
l3+l3.reverse()
# I believe that this wouldbe [1,2,3,3,2,1]
l3 = range(3)
tem = l3.reverse()
l3 + tem
# I believe that this would instead be [3,2,1,3,2,1]

I am sure that were such things legal, there would be numerous posts
complaining about 'unexpected' outcomes. Hence my comment about their not
being legal being good.

OP believe that getting a different answer when inserting a tempory in the
midst of a side-effect dependent expression is such a problem that we
should break code to 'fix' it. I obviously disagree.

Terry J. Reedy
Jul 18 '05 #12
On Fri, Jan 16, 2004 at 04:13:06PM +0000, James Henderson wrote:
On Friday 16 January 2004 2:44 pm, Alexey Nezhdanov wrote:
<snip>
I know the case where such python behaivoir causes hard-to-catch problems.
I do not know any case (anybody knows? please give example) where such
"feature" may be useful.

So I proposing to make a change into python and reverse the order of
calculations.
Just for sure:
=== Order used now ===
## a+=a.Sub(b)
1. evaluate value of 'a'
2. evaluate value of 'a.Sub(b)'
3. evaluate the sum
4. store the result into 'a'
=== Proposed order ===
## a+=a.Sub(b)
1. evaluate value of 'a.Sub(b)'
2. evaluate value of 'a'
3. evaluate the sum
4. store the result into 'a'
-1
In any language that uses such an operator I would expect:

a += b

to be synonymous with:

a = a + b


Of course, it should be noted that, in Python, "a += b" is only sometimes
synonymous with "a = a + b". The rest of the time, it's hard to say what it
is synonymous with :)

You are suggesting that it should mean:

a = b + a

It is not like Python to attach its own idiosyncratic semantics to operators
already well known from other languages. I think this would catch a lot of
people out.

Definitely. Consider tuple += tuple. It would not only be idiosyncratic,
but outright surprising and irrational if using += on (1, 2) and (3, 4)
resulted in (3, 4, 1, 2).
Of course, it's probably best to avoid writing code where the order makes a
difference. :)


Amen. Write simple code and all those who follow in your footsteps will
thank you.

Jp

Jul 18 '05 #13

"Dennis Lee Bieber" <wl*****@ix.netcom.com> wrote in message
news:3b************@beastie.ix.netcom.com...
But, since Python is dynamically typed, reversing the evaluation order could have major effects on other operations... The "problem" is not
the order of evaluation, but that you have a "hidden" modification to a
term occurring.
def se(a): #side-effect ... a.insert(0,3)
... return a
... def nose(a): #no side-effect ... a = [3] + list(a)
... return a
... l = [1,5,7]
l += nose(l)
l [1, 5, 7, 3, 1, 5, 7] l = [1,5,7]
l += se(l)
l

[3, 1, 5, 7, 3, 1, 5, 7]


Lovely example, no hypotheticals needed.

For those who did not get it, the key is that Python expressions evaluate
to objects, and that the + operator does not reach into the objects to pull
out values for the new object until it has (references to) both objects,
which in the second case, are both the same.

Terry J. Reedy
Jul 18 '05 #14
Of course, it should be noted that, in Python, "a += b" is only
sometimes synonymous with "a = a + b". The rest of the time, it's
hard to say what it is synonymous with :)
James> What do you have in mind? J.

For immutable objects, += works as you'd expect: return a new object,
leaving the old object unchanged. That's not the case for mutable objects,
to wit:
foo = [1]
bar = foo
foo += [2]
The object referenced by foo is modified in-place...
bar [1, 2] foo = foo + [2]
Here foo is bound to a new object, leaving the old object (still referenced
by bar) unchanged.
foo [1, 2, 2] bar

[1, 2]

Skip

Jul 18 '05 #15
On Friday 16 January 2004 7:18 pm, Jp Calderone wrote:
Of course, it should be noted that, in Python, "a += b" is only sometimes
synonymous with "a = a + b". The rest of the time, it's hard to say what
it is synonymous with :)


What do you have in mind? J.
--
James Henderson, Logical Progression Ltd.
http://www.logicalprogression.net/
http://sourceforge.net/projects/mailmanager/
Jul 18 '05 #16
On Friday 16 January 2004 10:51 pm, Skip Montanaro wrote:
>> Of course, it should be noted that, in Python, "a += b" is only
>> sometimes synonymous with "a = a + b". The rest of the time, it's
>> hard to say what it is synonymous with :)
James> What do you have in mind? J.

For immutable objects, += works as you'd expect: return a new object,
leaving the old object unchanged. That's not the case for mutable objects,

to wit: >>> foo = [1]
>>> bar = foo
>>> foo += [2]
The object referenced by foo is modified in-place...
>>> bar
[1, 2]
>>> foo = foo + [2]
Here foo is bound to a new object, leaving the old object (still referenced
by bar) unchanged.
>>> foo
[1, 2, 2]
>>> bar


[1, 2]

Skip


Thanks for pointing that out. It's also the case the += may be more
efficient, although that doesn't undermine my original point about surface
behaviour.

For any third party interested the details are at:

http://www.python.org/doc/current/ref/augassign.html

Back to the original topic, I have to agree with Robert Brewer that Alexey
Nezhdanov's proposal was capable of several other interpretations than a
switch to right-to-left evaluation.

James
--
James Henderson, Logical Progression Ltd.
http://www.logicalprogression.net/
http://sourceforge.net/projects/mailmanager/
Jul 18 '05 #17

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: dayzman | last post by:
Hi, I've read somewhere that feature-based analysis can be used to extract the semantic structure of HTML documents. By semantic structure, they mean the model of the rendered view a reader...
5
by: scsharma | last post by:
Hi, I am using .Net on Windows XP Professional. I am facing a unique problem with visual studio where intellisense feature is getting turned off. If i close IDE and reopen my solution the...
4
by: christopher diggins | last post by:
A feature that I find signficantly missing in C# is the ability to write functions in interfaces that can call other functions of the interface. Given an interface ISomeInteface the only way we can...
18
by: Kamen Yotov | last post by:
hi all, i first posted this on http://msdn.microsoft.com/vcsharp/team/language/ask/default.aspx (ask a c# language designer) a couple of days ago, but no response so far... therefore, i am...
7
by: Russell Mangel | last post by:
I was thinking about what IDE feature I would want the most in the next version of VC++? I would definately ask for the C# feature: #region / #endregion. In my opinion this feature was a...
30
by: Raymond Hettinger | last post by:
Proposal -------- I am gathering data to evaluate a request for an alternate version of itertools.izip() with a None fill-in feature like that for the built-in map() function: >>> map(None,...
12
by: Raymond Hettinger | last post by:
I am evaluating a request for an alternate version of itertools.izip() that has a None fill-in feature like the built-in map function: >>> map(None, 'abc', '12345') # demonstrate map's None...
12
by: =?Utf-8?B?RGFyYSBQ?= | last post by:
Would like to know from the crowd that why do we require a Partial Class. By having such feature aren't we going out of the scope of Entity Concept. Help me to understand in what context this...
20
by: Luke R | last post by:
One thing i used to use alot in vb6 was that tiny little button in the bottom left of the code window which allowed you to view either the whole code file, or just the function/sub you are currenly...
10
by: Conrad Lender | last post by:
In a recent thread in this group, I said that in some cases object detection and feature tests weren't sufficient in the development of cross-browser applications, and that there were situations...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
1
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
0
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.