Modify parameter as a side-effect in python [duplicate] - python

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Python: How do I pass a variable by reference?
I'm trying to write a function that modifies one of the passed parameters. Here's the current code:
def improve_guess(guess, num):
return (guess + (num/guess)) / 2
x = 4.0
guess = 2.0
guess = improve_guess(guess, x)
However, I want to write the code in such a way that I don't have to do the final assignment. That way, I can just call:
improve_guess(guess,x)
and get the new value in guess.
(I intentionally didn't mention passing-by-reference because during my net-searching, I found a lot of academic discussion about the topic but no clean way of doing this. I don't really want to use globals or encapsulation in a list for this.)

You can't do this directly since integer and floating-point types are immutable in Python.
You could wrap guess into a mutable structure of some sort (e.g. a list or a custom class), but that would get very ugly very quickly.
P.S. I personally really like the explicit nature of guess = improve_guess(guess, x) since it leaves no doubt as to what exactly is being modified. I don't even need to know anything about improve_guess() to figure that out.

But those are the only two ways to do it: either use a global, or use a mutable type like a list. You can't modify a non-mutable variable in Python: doing so just rebinds the local name to a new value.
If you really don't like wrapping in a list, you could create your own class and pass around an instance that will be mutable, but I can't see any benefit in doing that.

Related

Should I ever return a list that was passed by reference and modified?

I have recently discovered that lists in python are automatically passed by reference (unless the notation array[:] is used). For example, these two functions do the same thing:
def foo(z):
z.append(3)
def bar(z):
z.append(3)
return z
x = [1, 2]
y = [1, 2]
foo(x)
bar(y)
print(x, y)
Before now, I always returned arrays that I manipulated, because I thought I had to. Now, I understand it's superfluous (and perhaps inefficient), but it seems like returning values is generally good practice for code readability. My question is, are there any issues for doing either of these methods/ what are the best practices? Is there a third option that I am missing? I'm sorry if this has been asked before but I couldn't find anything that really answers my question.
This answer works on the assumption that the decision as to whether to modify your input in-place or return a copy has already been made.
As you noted, whether or not to return a modified object is a matter of opinion, since the result is functionally equivalent. In general, it is considered good form to not return a list that is modified in-place. According to the Zen of Python (item #2):
Explicit is better than implicit.
This is borne out in the standard library. List methods are notorious for this on SO: list.append, insert, extend, list.sort, etc.
Numpy also uses this pattern frequently, since it often deals with large data sets that would be impractical to copy and return. A common example is the array method numpy.ndarray.sort, not to be confused with the top-level function numpy.sort, which returns a new copy.
The idea is something that is very much a part of the Python way of thinking. Here is an excerpt from Guido's email that explains the whys and wherefors:
I find the chaining form a threat to readability; it requires that the reader must be intimately familiar with each of the methods. The second [unchained] form makes it clear that each of these calls acts on the same object, and so even if you don't know the class and its methods very well, you can understand that the second and third call are applied to x (and that all calls are made for their side-effects), and not to something else.
Python built-ins, as a rule, will not do both, to avoid confusion over whether the function/method modifies its argument in place or returns a new value. When modifying in place, no return is performed (making it implicitly return None). The exceptions are cases where a mutating function returns something other than the object mutated (e.g. dict.pop, dict.setdefault).
It's generally a good idea to follow the same pattern, to avoid confusion.
The "best practice" is technically to not modify the thing at all:
def baz(z):
return z + [3]
x = [1, 2]
y = baz(x)
print(x, y)
but in general it's clearer if you restrict yourself to either returning a new object or modifying an object in-place, but not both at once.
There are examples in the standard library that both modify an object in-place and return something (the foremost example being list.pop()), but that's a special case because it's not returning the object that was modified.
There's not strict should of course, However, a function should either do something, or return something.. So, you'd better either modify the list in place without returning anything, or return a new one, leaving the original one unchanged.
Note: the list is not exactly passed by reference. It's the value of the reference that is actually passed. Keep that in mind if you re-assign

Functions in Python with or without parentheses? [duplicate]

This question already has answers here:
What does it mean when the parentheses are omitted from a function or method call?
(6 answers)
Closed 2 years ago.
In Python, there are functions that need parentheses and some that don't, e.g. consider the following example:
a = numpy.arange(10)
print(a.size)
print(a.var())
Why does the size function not need to be written with parentheses, as opposed to the variance function? Is there a general scheme behind this or do you just have to memorize it for every function?
Also, there are functions that are written before the argument (as opposed to the examples above), like
a = numpy.arange(10)
print(np.round_(a))
Why not write a.round_ or a.round_()?
It sounds like you're confused with 3 distinct concepts, which are not specific to python, rather to (object oriented) programming.
attributes are values, characteristics of an object. Like array.shape
methods are functions an object can run, actions it can perform. array.mean()
static methods are functions which are inherent to a class of objects, but don't need an object to be executed like np.round_()
It sounds like you should look into OOP: here is a python primer on methods.
Also, a more pythonic and specific kind of attributes are propertys. They are methods (of an object) which are not called with (). Sounds a bit weird but can be useful; look into it.
arrange returns an ndarray. size isn't a function, it's just an attribute of the ndarray class. Since it's just a value, not a callable, it doesn't take parenthesis.

Python 3.5.2: a class unexpectedly changes a global variable [duplicate]

This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 5 years ago.
I am quite new to programming, Python and object-oriented programming in general. For a school assignment, I had to write a code that defines a "polynomial" class and, with this, find the root of a polynomial. As the code did not behave as expected, I started analysing it and realised that a global variable, namely the list of coefficients representing the polynomial, which is the "input" for the polynomial class, was being modified. The problem is that I just can't seem to figure out what (part of the code) is causing this manipulation. Below is (the relevant part of) the code I use:
#set input list
il=[1,1,-1]
#define B!/(O-1)!, note that O is an "oh":
def pr(O,B):
p=1
for i in range(O,B+1):
p*=i
return p
#polynomial
class pol:
#init:
def __init__(self,L=[0]):
self.l=L
self.d=len(L)
self.n=self.d-1
#evaluate:
def ev(self,X=0):
if X==0:
return self.l[0]
else:
s=self.l[0]
for i in range(1,self.d):
s+=self.l[i]*X**i
return s
#N-th derivative:
def der(self,N=1):
if self.n < N:
return pol([0])
else:
lwork=self.l
for i in range(N,self.d):
lwork[i]*=pr(i-N+1,i)
return pol(lwork[N:])
#define specific polynomial and take derivative:
#---here I have put some extra prints to make clear what the problem is---
f=pol(il)
print(il)
fd=f.der()
print(il)
fd2=f.der(2)
print(il)
Now this should evaluate to (at least it does so on my machine)
[1,1,-1]
[1,1,-2]
[1,1,-4]
while I expect it to be just the first list three times, since in the definition of the method "der", I do not manipulate the input list, or so it seems to me.
Can someone explain what's going on? Am I missing a (simple) detail, or am I misusing (some aspect of) classes here?
To execute my code, I use an online compiler (repl.it), running on Python 3.5.2.
One: Never use a mutable default argument for a function/method of any kind.
Two: Assigning from one name to another, as in:
lwork=self.l
is just aliasing, lwork becomes a reference to the same list as self.l. If you don't want to change self.l, (shallow) copy it, e.g.: for simple sequences like list:
lwork = self.l[:]
That will make a new list with the same values as self.l. Since the values are all immutable, the shallow copy was enough; if the values might be mutable, you'd want to use the copy module's copy.deepcopy to ensure the copy has no ties to the original list.
Similarly, if you don't want to preserve a tie between the list passed to the pol initializer and the list stored on the instance, make a copy of it, e.g.:
self.l = list(L)
In this case, I used list(L) instead of L[:] because it gets us a guaranteed type (list), from any input iterable type. This actually makes the mutable default argument safe (because you always shallow copy it, so no one is ever actually mutating it), but even so, mutable defaults are usually considered code smell, so it's best to avoid them.
Fixing up the whole __init__ method, you'd end up with:
# Mostly to avoid code smell, use immutable default (list constructor converts to list)
def __init__(self, L=(0,)):
self.l = list(L) # Create list from arbitrary input iterable
self.d = len(self.l) # Get length of now guaranteed list (so iterator inputs work)
self.n = self.d-1

Should I explicitly return list from function? [duplicate]

This question already has answers here:
Correct Style for Python functions that mutate the argument
(4 answers)
Closed 6 years ago.
I want to do some list modification in a function and then continue to use the modified list after calling the function, which is the better approach to do this:
def modify(alist):
alist.append(4)
alist = [1,2,3]
modify(alist)
alist.append(5)
Or this:
def modify(alist):
alist.append(4)
return alist
alist = [1,2,3]
alist = modify(alist)
alist.append(5)
Is the first some kind of bad tone?
Ordinarily a function should return the results it generates. However when you pass a list, you either need to make a copy of the list or accept the fact that it will be modified; it's redundant to return the modified list. It also leads to a problem if you ever provide a default argument, since the default will also be modified.
I generally prefer to make arguments read-only unless it's obvious that they will be modified inplace.
My recommendation:
def modify(alist=[]):
alist = alist[:] # make a copy
alist.append(4)
return alist
Since you're modifying the list inplace, it would not make much sense to return the same list you have modified.
Your inplace mutation propagates from the reference to the list, so better to leave out the return statement and raise an exception if an error occurs somewhere in the function, but not return the modified object.
There should be one-- and preferably only one --obvious way to do it.
It's safe to return the list from a function.
Formally, both approaches fullfil the task you want - to modify a list.
But, the second approach with function return some value which is stored in your variable is safer, and such code is much-much easier to maintain and develop, especially if you have many lists to modify, for example. Or in general you have a code that solves some difficult task, for which you need a lot of functions and variables. "Safe" means you don't have to worry about variable name conflict inside you code - everything you create inside your function namespace, stays local (except the case when you create a class attribute). So, it's generally considered a better practice. Good luck!

memory management with objects and lists in python

I am trying to understand how exactly assignment operators, constructors and parameters passed in functions work in python specifically with lists and objects. I have a class with a list as a parameter. I want to initialize it to an empty list and then want to populate it using the constructor. I am not quite sure how to do it.
Lets say my class is --
class A:
List = [] # Point 1
def __init1__(self, begin=[]): # Point 2
for item in begin:
self.List.append(item)
def __init2__(self, begin): # Point 3
List = begin
def __init3__(self, begin=[]): # Point 4
List = list()
for item in begin:
self.List.append(item)
listObj = A()
del(listObj)
b = listObj
I have the following questions. It will be awesome if someone could clarify what happens in each case --
Is declaring an empty like in Point 1 valid? What is created? A variable pointing to NULL?
Which of Point 2 and Point 3 are valid constructors? In Point 3 I am guessing that a new copy of the list passed in (begin) is not made and instead the variable List will be pointing to the pointer "begin". Is a new copy of the list made if I use the constructor as in Point 2?
What happens when I delete the object using del? Is the list deleted as well or do I have to call del on the List before calling del on the containing object? I know Python uses GC but if I am concerned about cleaning unused memory even before GC kicks in is it worth it?
Also assigning an object of type A to another only makes the second one point to the first right? If so how do I do a deep copy? Is there a feature to overload operators? I know python is probably much simpler than this and hence the question.
EDIT:
5. I just realized that using Point 2 and Point 3 does not make a difference. The items from the list begin are only copied by reference and a new copy is not made. To do that I have to create a new list using list(). This makes sense after I see it I guess.
Thanks!
In order:
using this form is simply syntactic sugar for calling the list constructor - i.e. you are creating a new (empty) list. This will be bound to the class itself (is a static field) and will be the same for all instances.
apart from the constructor name which must always be init, both are valid forms, but mean different things.
The first constructor can be called with a list as argument or without. If it is called without arguments, the empty list passed as default is used within (this empty list is created once during class definition, and not once per constructor call), so no items are added to the static list.
The second must be called with a list parameter, or python will complain with an error, but using it without the self. prefix like you are doing, it would just create a new local variable name List, accessible only within the constructor, and leave the static A.List variable unchanged.
Deleting will only unlink a reference to the object, without actually deleting anything. Once all references are removed, however, the garbage collector is free to clear the memory as needed.
It is usually a bad idea to try to control the garbage collector. instead. just make sure you don't hold references to objects you no longer need and let it make its work.
Assigning a variable with an object will only create a new reference to the same object, yes. To create a deep copy use the related functions or write your own.
Operator overloading (use with care, it can make things more confusing instead of clearer if misused) can be done by overriding some special methods in the class definition.
About your edit: like i pointed above, when writing List=list() inside the constructor, without the self. (or better, since the variable is static, A.) prefix, you are just creating an empty variable, and not overriding the one you defined in the class body.
For reference, the usual way to handle a list as default argument is by using a None placeholder:
class A(object):
def __init__(self, arg=None):
self.startvalue = list(arg) if arg is not None else list()
# making a defensive copy of arg to keep the original intact
As an aside, do take a look at the python tutorial. It is very well written and easy to follow and understand.
"It will be awesome if someone could clarify what happens in each case" isn't that the purpose of the dis module ?
http://docs.python.org/2/library/dis.html

Categories