>>> c=[1,100,3]
>>>def nullity (lst):
lst=[]
>>>nullity (c)
>>>c
[1,100,3]
Why c doesn't return []? Isn't nullity(c) mean c=lst so thy both point now at []?
Python has pass-by-value semantics, meaning that when you pass a parameter to a function, it receives a copy to the object's reference, but not the object itself. So, if you reassign a function parameter to something else (as you did), the assignment is local to the function, the original object "outside" the function remains unchanged. A completely different situation happens if you change something inside the object:
def test(a):
a[0] = 0
lst = [1, 2, 3]
test(lst)
lst
=> [0, 2, 3]
In the above snippet the list's elements were changed, that's because both lst and a are pointing to the exact same object. Now back to the original question - notice that in Python 3.2 and below there isn't a clear() method (it was added in Python 3.3), here is a related discussion. But you can do this for the same effect, and it'll work in Python 2.x and 3.x:
def nullity(lst):
del lst[:]
You're reassigning local variable lst to a new empty list. To empty an existing list, you need to delete all its members:
del lst[:]
Lets use the id() function
In [14]: c=[1,2,3]
In [15]: def nullity (lst):
...: print id(lst)
...: lst=[]
...: print id(lst)
...:
In [16]: id(c)
Out[16]: 33590520
In [17]: nullity(c)
33590520
33591024
When doing the reassignment a new local object is created which is not the same as the one used when calling the function.
Python does not allow you to replace parameters. You are only changing what "lst" refers to within the function, but it does not affect the calling code.
Instead change the list itself by clearing it:
def nullity (lst):
lst.clear() # With Python >= 3.3
Related
If I have a list comprehension (for example) like this:
['' for x in myList]
Effectively making a new list that has an empty string for every element in a list, I never use the x. Is there a cleaner way of writing this so I don't have to declare the unused x variable?
_ is a standard placeholder name for ignored members in a for-loop and tuple assignment, e.g.
['' for _ in myList]
[a+d for a, _, _, d, _ in fiveTuples]
BTW your list could be written without list comprehension (assuming you want to make a list of immutable members like strings, integers etc.).
[''] * len(myList)
No. As the Zen puts it: Special cases aren't special enough to break the rules. The special case being loops not using the items of the thing being iterated and the rule being that there's a "target" to unpack to.
You can, however, use _ as variable name, which is usually understood as "intentionally unused" (even PyLint etc. knows and respect this).
It turns out that using dummy* (starting word is dummy) as the variable name does the same trick as _. _ is a known standard and it would be better to use meaningful variable names. So you can use dummy, dummy1, dummy_anything. By using these variable names PyLint won't complain.
Add the following comment after the for loop on the same line:
#pylint: disable=unused-variable
for i in range(100): #pylint: disable=unused-variable
If you need to name your arguments (in case, for example, when writing mocks that don't use certain arguments that are referenced by name), you can add this shortcut method:
def UnusedArgument(_):
pass
and then use it like this
def SomeMethod(name_should_remain):
UnusedArgument(name_should_remain)
The generator objects don't actually use the variables. So something like
list(('' for x in myList))
should do the trick. Note that x is not defined as a variable outside of the generator comprehension.
You can also prepend a variable name with _ if you prefer giving the variable a human readable name. For example you can use _foo, _foo1, _anything and PyLint won't complain. In a for loop, it would be like:
for _something in range(10):
do_something_else()
edit: Add example
A verbose way is:
newList = []
while len(newList) < len(mylist):
newList.append('')
You avoid declaring an used variable this way.
Also you can append both mutable and immutable objects (like dictionaries) into newList.
Another thing for python newbies like me, '_', 'dummy' are a bit disconcerting.
Try it, it's simple:
# Use '_' instead of the variable
for _ in range(any_number):
do_somthing()
Comment to How can I get around declaring an unused variable in a for loop? (Ran out of comment size)
Python maintains the same reference for the object created. (irrespective of mutability),for example,
In [1]: i = 1
In [2]: j = 1
In [3]: id(i)
Out[3]: 142671248
In [4]: id(j)
Out[4]: 142671248
You, can see both i and j, refer to the same object in memory.What happens, when we change the value of one immutable variable.
In [5]: j = j+1
In [6]: id(i)
Out[6]: 142671248
In [7]: id(j)
Out[7]: 142671236
you can see j now starts to point a new location, (where 2 is stored), and i still points to location where 1 is stored.
While evaluating,
j = j+1
The value is picked from 142671248, calculated(if not already cached), and put at a new location 142671236. j is made to point to
the new location. In simpler terms a new copy made everytime an immutable variable is modified.
Mutability
Mutable objects act little different in this regard. When the value pointed by
In [16]: a = []
In [17]: b = a
In [18]: id(a)
Out[18]: 3071546412L
In [19]: id(b)
Out[19]: 3071546412L
Both a and b point to the same memory location.
In [20]: a.append(5)
Memory location pointed by a is modified.
In [21]: a
Out[21]: [5]
In [22]: b
Out[22]: [5]
In [23]: id(a)
Out[23]: 3071546412L
In [24]: id(b)
Out[24]: 3071546412L
Both a and b, still point to the same memory location. In other word, mutable variables act of the same memory location pointed by the variable, instead of making a copy of the value pointed by the variable, like in immutable variable case.
This is the code I type. Here the value of int has not changed outside of function but value of list has changed.I was expecting the value of list will not change. What is the reason?
>>> def p1(list1):
list1[0]=1000
>>> def p2(i):
i+=10
>>> li=[1,2,3,4,5]
>>> int1=10
>>> p1(li)
>>> p2(int1)
>>> li
[1000, 2, 3, 4, 5]
>>> int1
10
Note that in p1, you are not assigning a value to list1, which is the name of a variable local to p1. You are actually assigning to the first element of the list object referenced by list1, which is the same list object referenced by li in the enclosing scope.
In p2, on the other hand, i+=10 does assign a value to the local variable i, not the variable int1 in the enclosing scope. This is because the += operator on objects of type int do not actually modify the object, but return a new object instead. (That is, for an int, i+=10 is equivalent to i = i + 10.)
Just to show that += can operate on the underlying object directly, consider this function:
def p3(list1):
list1 += [10]
Then run it on a list:
>>> foo = [1,2,3]
>>> p3(list1)
>>> foo
[1, 2, 3, 10]
Here, the call list1 += [10] is really equivalent to list1.extend([10]), not list1 = list1 + [10], due to how list.__iadd__ is defined. Here, you are again not assigning a value to the name list1, but rather invoking a method on the object referenced by list1 (which is the same object referenced by foo).
(Update: as pointed out by user2357112, technically you do assign to list1, but list.__iadd__ is designed to properly assign the same list back, so that the end result is that you still have a reference to the same mutable object you started with.)
Assigning to a variable, like i+=10, is an operation on a variable, while index assignment, like list1[0]=1000, is an operation on the object a variable refers to.
When you call p2(int1), the local variable i gets set to refer to the int int1 referred to, and then the i+=10 statement redirects i to refer to a new, larger integer. int1 still refers to the old integer.
When you call p1(li), the local variable list1 gets set to refer to the list li referred to, and then the list1[0]=1000 statement sets the first cell of the list to refer to 1000. li still points to this list throughout the modification, and after the function returns, li still reflects the change.
(There's another complexity here in that += also requests that an object mutate itself if it's mutable, in addition to performing an assignment, but that doesn't come up in this code.)
A list is like a pointer to a list object.
#For example
a =[0,0]
b = a
b[0]=1
resulting in
b
[1,0]
Where as an int is an a different beast
#For Example
a = 0
b = a
b +=1
resulting in
a
1
to get the int behaviour from a listyou can make a clone of a list by passing it to list()
#for example
a = [0,0]
b = list(a)
b[0]=1
resulting in
a
[0,0]
and if you want the list behaviour from an int I guess you would have to just put it in a list.
Context: I needed to randomly erase some precise element of a few lists of numbers, extracting some random indexes and saving them in a set called aleaindex (done, it properly works, thanks to some SO users' help). Now, I'd like to substitute the old lists a, b, etc with the new, eventually shorter ones newa, newb, etc. Here is the function:
def myfunction(N, other_parameters, a, b, c):
...
while (...):
aleaindex.add(random.randint(..., ...))
...
new_a = [v for i, v in enumerate(a) if i not in aleaindex]
while a: a.pop()
a = new_a[:]
...
and so on for the other lists b, c, etc.
Problem: the function seems to correctly modify them within the module (checked by printing) but then, when I print the modified lists outside the module, that is in the "main" file, lists are as they had not modified. Where am I wrong?
This line:
a=new_a[:]
overwrites the variable a with a new object. Outside the function or module, the old object is still pointed at by a (or whatever it was called there). Try:
new_a = [v for i, v in enumerate(a) if i not in aleaindex]
while a:
a.pop()
a[:] = new_a[:]
Explanation
To see this, just try the following.
>>> a = [1,2,3,4]
>>> b = a
>>> print b
[1, 2, 3, 4]
>>> a[:] = [2,3]
>>> print b
[2, 3]
>>> a = [5]
>>> print b
[2, 3]
Example in function!
If the variable is mutable (and a normal list is), this works:
>>> def f(a):
... a[0] = 2
>>> b = [3]
>>> f(b)
>>> print b
[2]
Variables are not passed by value - you can edit a mutable value.
I do not know what you are trying to do but from your snippets you are clearly lost. Your code does not make much sense and there are more more than one problem. Nonetheless, the problem you asked about - why the list is not fully changed? - seems to be related to this loop:
while a: a.pop()
a = new_a[:]
Suppose we call your function this way:
list1 = [1, 2, 3, 4, 5, 6, 7]
myfunction(N, other_parameters, list1, [], [])
What will happen is, when you call the first line, you will get a variable called list1 and it will point to a list:
When you call the function myfunction(), the function, among other things, create a variable called a which will point to the same list pointed by list1:
So far, so good. Then we get at the loop below:
while a:
a.pop()
a = new_a[:]
In the first line of it (a.pop()), you get an item out of the list. Since both variables a and list1 points to the same list, you would see the same result...
...if it were not for the next line of the loop (a = new_a[:]). In this line, you are making the a variable to point to another list:
Now, every operation you execute on a will be in this list, which is in no way related to list1. For example, you can execute a.pop() at the next iteration to get it:
However, it makes no sense at all, because the line a = new_a[:] will replace the list pointed to a again for yet another different list:
So, what is the solution? I don't know. As I have said, it is not possible (to me, at least) to make sense from your code. You have to reflect a bit more about what you are trying to do and explain it to us, with a bit more of context.
There is no function in the code you have posted. I suspect the problem is that you are not returning the new value.
Your code likely does something like:
a = "foo"
def func():
a = "bar" # uh-oh this not the same as the global a
func()
At this point global a is unchanged because the a local to func is not the same variable.
You want to do:
a = "foo"
def func():
return "bar"
a = func()
That code assigns to the a in global scope, changing it.
I create many object then I store in a list. But I want to delete them after some time because I create news one and don't want my memory goes high (in my case, it jumps to 20 gigs of ram if I don't delete it).
Here is a little code to illustrate what I trying to do:
class test:
def __init__(self):
self.a = "Hello World"
def kill(self):
del self
a = test()
b = test()
c = [a,b]
print("1)Before:",a,b)
for i in c:
del i
for i in c:
i.kill()
print("2)After:",a,b)
A and B are my objects. C is a list of these two objects. I'm trying to delete it definitely with a for-loop in C: one time with DEL and other time with a function. It's not seem to work because the print continue to show the objects.
I need this because I create 100 000 objects many times. The first time I create 100k object, the second time another 100k but I don't need to keep the previous 100k. If I don't delete them, the memory usage goes really high, very quickly.
tl;dr;
mylist.clear() # Added in Python 3.3
del mylist[:]
are probably the best ways to do this. The rest of this answer tries to explain why some of your other efforts didn't work.
cpython at least works on reference counting to determine when objects will be deleted. Here you have multiple references to the same objects. a refers to the same object that c[0] references. When you loop over c (for i in c:), at some point i also refers to that same object. the del keyword removes a single reference, so:
for i in c:
del i
creates a reference to an object in c and then deletes that reference -- but the object still has other references (one stored in c for example) so it will persist.
In the same way:
def kill(self):
del self
only deletes a reference to the object in that method. One way to remove all the references from a list is to use slice assignment:
mylist = list(range(10000))
mylist[:] = []
print(mylist)
Apparently you can also delete the slice to remove objects in place:
del mylist[:] #This will implicitly call the `__delslice__` or `__delitem__` method.
This will remove all the references from mylist and also remove the references from anything that refers to mylist. Compared that to simply deleting the list -- e.g.
mylist = list(range(10000))
b = mylist
del mylist
#here we didn't get all the references to the objects we created ...
print(b) #[0, 1, 2, 3, 4, ...]
Finally, more recent python revisions have added a clear method which does the same thing that del mylist[:] does.
mylist = [1, 2, 3]
mylist.clear()
print(mylist)
Here's how you delete every item from a list.
del c[:]
Here's how you delete the first two items from a list.
del c[:2]
Here's how you delete a single item from a list (a in your case), assuming c is a list.
del c[0]
If the goal is to delete the objects a and b themselves (which appears to be the case), forming the list [a, b] is not helpful. Instead, one should keep a list of strings used as the names of those objects. These allow one to delete the objects in a loop, by accessing the globals() dictionary.
c = ['a', 'b']
# create and work with a and b
for i in c:
del globals()[i]
To delete all objects in a list, you can directly write list = []
Here is example:
>>> a = [1, 2, 3]
>>> a
[1, 2, 3]
>>> a = []
>>> a
[]
>>> def test():
... a.remove(1)
>>> a = [1,2]
>>> test()
>>> print a
[2]
Why does a equal [2] rather than [1,2]?
List is mutable. If you pass it to a function, and the function changes it, it stays changed.
Use an immutable structure: tuple: a = (1,2)
Pass a copy of original list: b = list(a); b.remove(1) — now a and b have different contents, a hasn't changed.
Also, try not to use mutable global data. Either pass a to the function, or have a as an attribute of an object, and the function as its method.
It's not clear what you want. Your test() function modifies the global 'a' list, so it's unsurprising that 'a' gets modified.
If you want 'test' to work on a copy of a instead directly on a, you may copy it first.
For example,
def test():
a2 = list(a)
a2.remove(1)
Lists are mutable objects, they are meant to be changed. If you want to forbid changes, convert it to a tuple (e.g. a = (1, 2)) instead. Tuples are immutable, so it's not possible to change them without copying and re-assigning the variable.
Because the list a exists in the global namespace and when you call a remove on it, the value 1 is removed.
If you don't want it to be modified, simply create a new list. If you call remove on the list a, of course it going to remove the value.