Jump to content
  • Advertisement
Sign in to follow this  
PimpWilly

Python question: Default Pass by reference, or value?

This topic is 4421 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have been working on programming a game entirely in python, using pygame, in an attempt to learn python (I already know c++). I have run into a problem with a recursive function I wrote (pathfinding). Basically, it seems to me that the variables are passing by reference, instead of by value (as is the default in c++). As you can imagine, this is causing problems since I wrote the function assuming that pass by value was the default. Is the default indeed pass by reference? And if so, is there any way to pass by value? Otherwise, I'm going to need a messy work-around for the function (as if my code isn't messy enough) Thanks in advance

Share this post


Link to post
Share on other sites
Advertisement
It's a little more complicated - see the fairly involved discussion on the Python mailing list. It's similar to pass-by-reference semantics, but more involved that that. The discussion linked has a decent explanation.


Personally, I haven't used the language enough to know if there's a way to force copy semantics when passing arguments to a function; I'm sure someone else can answer that half, though [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by PimpWilly
Is the default indeed pass by reference? And if so, is there any way to pass by value?


It's pass by reference, but assignment is not overwriting but is rebinding. So although you get a reference in the called function, if you assign to that object, it won't affect the original object. However, if you modify that object, it does affect the original.

Basically, if you want a copy, make a copy. This might involve the copy module, or whatever it's called. Generally, it's actually very rare that you actually do need to make that copy. I've never used that module myself. You can probably express the problem in a different way that doesn't require a copy.

Share this post


Link to post
Share on other sites
As far as argument passing goes, the only available Python way is pass-by-value. All Python variables are references to objects of course, but they themselves are not passed by reference. It's clearly references that are passed by value. Don't confuse passing by reference and passing a reference.

Share this post


Link to post
Share on other sites
You're blurring the 2 concepts beyond the point of usefulness however. It's exactly the same in C or C++, or Java - the called function ends up with a copy of the reference or the pointer. At the low level it's copying a value which represents a memory location, but in language terms it's still "pass by reference" because changes made to an argument in the called function are reflected in the corresponding object in the calling function.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kylotan
You're blurring the 2 concepts beyond the point of usefulness however. It's exactly the same in C or C++, or Java - the called function ends up with a copy of the reference or the pointer. At the low level it's copying a value which represents a memory location, but in language terms it's still "pass by reference" because changes made to an argument in the called function are reflected in the corresponding object in the calling function.


Not at all. Consider this simple Python function that gets an angle and returns both the sine and the cosine, ie it needs to return 2 values:


import math

def sin_cos(angle,sin,cos):
sin=math.sin(angle);
cos=math.cos(angle);

angle=45.0;
sin=None;
cos=None;
sin_cos(angle,sin,cos);
print "The sine of ",angle,"is: ",sin
print "The sine of ",angle,"is: ",cos








Claiming that Python uses pass-by-reference would be a big mistake, as the programmer would naturally expect the above code to work just as it works with C++(where references are regularly used to for multiple return values). He must realize the difference between pass-by-reference and pass-by-value of a reference and use the correct way to do this, that is return a tuple that contains both results.

See this for a couple of more ways to emulate pass-by-reference in Python, although most of them are overcomplicating things and most probably can be avoided.

[Edited by - mikeman on July 3, 2006 2:12:37 PM]

Share this post


Link to post
Share on other sites
It's passing references by value, in the same way that Java does, except that Python doesn't have any "primitives" - everything is an object, including "ints".

If you need to copy (clone) things, then do so, with the copy module. However, you normally should be trying to write things in such a way that you don't need to do this.

I don't suppose you could show the code in question? :s

Share this post


Link to post
Share on other sites
I'll go ahead and post the path function. Might be a bit convuluted, but eh, here it goes:

Note: I tried changing leftData to self.leftData, to see if that would help the problem, but it didn't seem to do the trick. so thats why it's referenced different right now

def findPath(self, currentData, currentSquare, destinationSquare, movementLeft):
#subtract current tile movement cost from movement spaces left
# check if movement cost < 0.
# If so, I cant get here, so append with a -1 and return it
#print "Updating Data for debug:", currentData
tileInfo = self.getTile(currentSquare[0], currentSquare[1])
currentTileMovementCosts = self.mapKey.getMovementCost(tileInfo)
print " TileCosts:", currentTileMovementCosts
if movementLeft < 0:
currentData[0] = -1
return currentData
#Check if I am on the destination square
if currentSquare == destinationSquare:
print "Found the dest square, returning data ->", currentData
return currentData
else:
currentData[0] += currentTileMovementCosts
movementLeft -= currentTileMovementCosts
self.leftData = currentData
self.leftData.append('L')
tempSquare = currentSquare
tempSquare[0] -= 1
self.leftData = self.findPath(self.leftData, tempSquare, destinationSquare, movementLeft)

upData = currentData
upData.append('U')
tempSquare = currentSquare
tempSquare[1] -= 1
upData = self.findPath(upData, tempSquare, destinationSquare, movementLeft)

rightData = currentData
rightData.append('R')
tempSquare = currentSquare
tempSquare[0] += 1
rightData = self.findPath(rightData, tempSquare, destinationSquare, movementLeft)

downData = currentData
downData.append('D')
tempSquare = currentSquare
tempSquare[1] += 1
downData = self.findPath(downData, tempSquare, destinationSquare, movementLeft)

#Find which path is >0 and which has the lowest movement costs
#print "all data:", self.leftData
if upData[0] >= 0:
lowestData = upData
elif rightData[0] >= 0:
lowestData = rightData
elif self.leftData[0] >= 0:
print "@@@@@@@@@@@@@Left Data", self.leftData
lowestData = rightData
elif downData[0] >= 0:
lowestData = downData
else:
#no paths found
# set currentData[0] to -1 and return
currentData[0] = -1
#print "Path not found"
return currentData
print "!!!!!!!!!!!!!!!!!!!!!!!!!!Left Data,", self.leftData
if upData[0] > 0 and upData[0] < lowestData[0]:
lowestData = upData
if rightData[0] > 0 and rightData[0] < lowestData[0]:
lowestData = rightData
if self.leftData[0] > 0 and self.leftData[0] < lowestData[0]:
print "#####################Left Data", self.leftData
lowestData = leftData
if downtData[0] > 0 and downData[0] < lowestData[0]:
lowestData = downData

#now return our shortest path
print " Path found, heres data ->", lowestData
return lowestData




As the algorithm runs, it ends up just adding a whole lot of data to leftData, rightData,upData,downData, and currentData, so that when it finally returns with what I hoped would be the shortest path, it ends up just being a path with like 60+ moves (even for just one square over)

Share this post


Link to post
Share on other sites
Just an update, but I haven't had any luck so far. Looks like I am going to have to go ahead and just create a temp variable before each recursion call, then re-assign it after it returns, unless anybody has any better alternatives?

Thanks,

--Steve

Share this post


Link to post
Share on other sites
I'm having a hard time parsing your code. Could you post your algorithm alone?

Also, take a look at shortest path implementations in Python (Dijkstra, A*).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!