I get stuck in my school missions about a couple of days! The question asks to copy a tuple into a new tuple which has the different ID with the original tuple! This is my current code but still can't get how to copy with different Ids!
def copy_tree(tree):
mylist=[]
for items in tree:
mylist.append(items)
mytuple=tuple(mylist)
return mytuple
original = (1, 2, 3, 4)
Tuples in Python are immutable, so creating a copy is usually not needed. That's probably the reason, why other than e.g. list, tuple will not automatically create a new tuple if the given parameter already is a tuple:
>>> l = [1,2,3]
>>> list(l) is l # new list ...
False
>>> t = (1,2,3)
>>> tuple(t) is t # but same tuple
True
You can, however, convert the tuple to a list first, and then create a new tuple from that list.
>>> tuple(list(t)) == t # equal ...
True
>>> tuple(list(t)) is t # ... but not the same
False
>>> id(tuple(list(t))), id(t) # different id
(139852830618896, 139852830618752)
Which is basically what you are currently doing, although in a few more lines, so your code should actually work just fine.
Note, however, that this will create a shallow copy of the tuple, i.e. the objects within the tuple (other tuples, list, whatever) are not copied. If you need to copy those, too, use copy.deepcopy as in the other answer. However, this, too, is so "smart" that it will not create a copy if the (nested) tuple only contains immutable values:
>>> k = (1, (2, "3")) # all immutable
>>> copy.deepcopy(k) is k
True
>>> k = (1, (2, "3", [])) # contains mutable list
>>> copy.deepcopy(k) is k
False
#There is no need to copy immutables. For Academic Purpose:
from copy import deepcopy
#initialising first tuple k
k=(1,2)
id(k) # checking memory id of k
j=deepcopy(k) #deepcopying k to j
id(j) # checking memory id of j
Don't really know what you are looking for but :
t1 = (1, 2, 3, 4)
t2 = t1
print(t1)
print(t2)
in this, t2 is a literal copy/clone of t1.
as mentioned before, tuples are not mutable. if you want to add tuple to another you can just use "," as a separator.
You could just add numbers: "t2=t1,1,2,3,4" which would make it tuple copied within another tuple.
or
You could insert numbers from another tuple to another by slicing it like t2=t1[2],1,2,3
Related
Could you please help me understand why does deepcopy not work for all the elements in the dictionary from the example below?
import copy
a = [{'id':1, 'list':[1,2,3], 'num':3}, {'id':2,' list':[4,5,6], 'num':65}]
b = {i['id']:copy.deepcopy(i) for i in a}
In [1]: print(id(a) == id(b))
Out[1]: False
In [2]: print(id(a[0]) == id(b[1]))
Out[2]: False
In [3]: print(id(a[0]['list']) == id(b[1]['list']))
Out[3]: False
In [4]: print(id(a[0]['num']) == id(b[1]['num']))
Out[4]: True
In particular, the values associated to the 'num' key are the same while those for the 'list' key seem to have been copied successfully with deepcopy. I'm guessing it has to do with the data type of the value being stored, could someone please point me in the right direction?
Thanks!
This has nothing to do with the dict comprehension but, as you suggested, with the data type:
>>> import copy
>>> x = 1
>>> copy.deepcopy(x) is x
True
>>> x = [1]
>>> copy.deepcopy(x) is x
False
The distinction made by #mengban is correct: you have mutable and immutable objects (that depends on the type of the object). Typical examples of immutable objects are: integers (0, 1, 2...), floats (3.14159), but also strings ("foo") and tuples ((1, 3)). Typical examples of mutable objects are: lists ([1, 2, 3]) or dictionaries ({'a': 1, 'b': 2}).
Basically, the deepcopy of an immutable object returns the object itself: no actual copy is performed (there's a little trick with tuples: I'll explain it later):
>>> x = "foo"
>>> copy.deepcopy(x) is x
True
>>> x = (1, 2)
>>> copy.deepcopy(x) is x
True
And deepcopy of mutable objects creates a new instance of the object having the same elements.
This the right behavior because when you have acquired a deep copy o2 of an object o, the contract is that this is your copy. No operation performed on o should be able to modify o2. If o is immutable, this is guaranteed for free. But if o is mutable, then you need to create a new instance, having the same content (this implies a recursive deep copy).
Now what's the matter with tuples?
>>> o = ([1], [2])
>>> copy.deepcopy(o) is o
False
Even if the tuple itself is immutable, maybe one of its elements could be mutable. If I give you a reference o2 to the value of o (ie o2 = o), you can write o2[0].append(10) and my object o is modified. Hence the deepcopy function looks for mutable objects in the tuple, and decides whether an actual copy is necessary or not.
Bonus: have a look at the deepcopy implementation. The _deepcopy_dispatch maps types to the actual copier:
_deepcopy_dispatch = d = {}
...
d[int] = _deepcopy_atomic
d[float] = _deepcopy_atomic
d[bool] = _deepcopy_atomic
...
d[str] = _deepcopy_atomic
...
d[list] = _deepcopy_list
...
d[tuple] = _deepcopy_tuple
...
d[dict] = _deepcopy_dict
...
While _deepcopy_atomic simply returns the value, _deepcopy_list, _deepcopy_tuple, _deepcopy_dict... perform usually an in-depth copy.
You can check the _deepcopy_tuple function to understand the process. Basically, deep copy every element until an actual copy is made. If a copy was made, create a new tuple of deep copies. Else return the initial tuple.
If you don't want a reference in your dictionary in your new dictionary you can do the following:
new_dictionary = json.loads(json.dumps(old_dictionary))
There is a big difference between mutable and immutable types in python.
In general, variable types in Python include lists, dictionaries, and collections. Immutable types include strings, int, float, and tuples.
Re-assigning a variable of an immutable type is actually re-creating an object of an immutable type and re-pointing the original variable to the newly created object (a new memory address is opened up), if no other variables refer to the original object (That is, the reference count is 0), the original object will be recycled.
I'm not quite sure how to phrase it yet, so I'll demonstrate what I mean.
a = 1
b = 2
my_list = [a,b]
print my_list # [1,2]
a = a + 1
b = b * 2
print a # 2
print b # 4
# prints [1,2] but I want [2,4]
print my_list
This happens for tuples and sets too. What is the data structure I need? Or what is the logic I need?
Integers are immutable. That means that once you've created an integer object, e.g. with a = 1, it can never be changed. That doesn't mean that you can't rebind the name a to another object, just that the value of the integer object itself won't change.
When you do a = a + 1, you are creating a new integer with value 2, and assigning it to a. But the original 1 is still around. In fact the element my_list[0] still refers to the original object, since it was never told to refer to anything else. In that sense, names are like pointers in Python.
To get the list element to change, you have two options:
Tell it to change explicitly. Any time you modify a, set my_list[0] = a again. Or just drop a entirely. Why have two references to the same object of you don't need to? You can do
my_list[0] += 1
my_list[1] *= 2
Store a mutable object in the list. Strings and integers, as you already saw, are immutable. Tuples are as well. But sets, dicts and lists are mutable, so any in-place changes you make to them will be directly visible. This is probably not the best option in your particular case, but here's an example:
a = [1]
b = {2}
my_list = [a, b]
a[0] += 1
a.append(3)
b.add(4)
print my_list
[[2, 3], {2, 4}]
Both of methods shown here work just fine for lists. The notation for sets is a little different for sets since in the first case, you'd have to remove the original object and insert the new one. The concept is the same though.
Only the second method could work with tuples though, and even that's not usually recommended. As I mentioned earlier, tuples are supposed to be immutable. The are certain expectations that come with that, like hashability, which are violated when you put a mutable object, like a list, into a tuple. It's perfectly fine to do that, but you just have to be a little careful.
For your particular use-case (accessing the values by name, but also grouping them into a single data structure), dictionaries may be more suitable than lists. You can index a dictionary much like a list, except that the keys can be the names you want instead of essentially arbitrary indices. Your example would look like this:
my_dict = {
'a': 1,
'b': 2,
}
my_dict['a'] += 1
my_dict['b'] *= 2
print my_dict
<p/>
{'a': 2, 'b': 4}
I want to iterate over a certain range and create several sets that contain only the current i. (In the code I don't want to do this for every i, but it's about the general principle).
for i in range(5):
s=set(i)
print(s)
It says int object is not iterable. Why doesn't this work? Please keep the answers simple, I'm a newbie.
set() takes a sequence of values to add, and a single integer is not a sequence.
You could wrap it in a tuple or a list:
s = set((i,))
s = set([i])
but the better option is to use the {..} set literal notation:
s = {i}
The notation looks a lot like creating a dictionary, but you only list values, not keys.
Demo (on Python 2, where the representation uses set([..]) notation):
>>> i = 42
>>> set((i,))
set([42])
>>> set([i])
set([42])
>>> {i}
set([42])
Python 3 reflects sets using the literal notation:
>>> i = 42
>>> {i}
{42}
Set constructor set(x) requires x to be some container, like a list, or other set. You pass an integer, python tries to iterate over it, and fails.
In order to do so you need to pass a singleton of x, like that:
for i in range(5):
s = set([i]) # or s = set((i,))
print(s)
or through simplified set constructor
for i in range(5):
s = {i}
print(s)
or construct an empty set and add your element
for i in range(5):
s = set()
s.add(i)
print(s)
instead of using a for loop in range, you can also feed it to set (or a frozenset if you dont need to change it's content):
>>> set(range(5))
# {0, 1, 2, 3, 4}
I understand Tuple are immutable and most of the list methods don't work on Tuple. Is there a way to find the index of an element in a tuple?(Other than typecasting it into a list and checking the index)
I don't quite see the problem:
>>> t = (1,2,3)
>>> t.index(2)
1
you can use index method of tuple to find the index of tuple.
>>> t = (1,2,3,4)
>>> t.index(2)
1
if tuple contains repetative items then use start and stop check.
t.index: (value, [start, [stop]])
>>> t = (1,2,3,4,2)
>>> t.index(2, 2, len(t))
4
I occasionally see the list slice syntax used in Python code like this:
newList = oldList[:]
Surely this is just the same as:
newList = oldList
Or am I missing something?
[:] Shallow copies the list, making a copy of the list structure containing references to the original list members. This means that operations on the copy do not affect the structure of the original. However, if you do something to the list members, both lists still refer to them, so the updates will show up if the members are accessed through the original.
A Deep Copy would make copies of all the list members as well.
The code snippet below shows a shallow copy in action.
# ================================================================
# === ShallowCopy.py =============================================
# ================================================================
#
class Foo:
def __init__(self, data):
self._data = data
aa = Foo ('aaa')
bb = Foo ('bbb')
# The initial list has two elements containing 'aaa' and 'bbb'
OldList = [aa,bb]
print OldList[0]._data
# The shallow copy makes a new list pointing to the old elements
NewList = OldList[:]
print NewList[0]._data
# Updating one of the elements through the new list sees the
# change reflected when you access that element through the
# old list.
NewList[0]._data = 'xxx'
print OldList[0]._data
# Updating the new list to point to something new is not reflected
# in the old list.
NewList[0] = Foo ('ccc')
print NewList[0]._data
print OldList[0]._data
Running it in a python shell gives the following transcript. We can see the
list being made with copies of the old objects. One of the objects can have
its state updated by reference through the old list, and the updates can be
seen when the object is accessed through the old list. Finally, changing a
reference in the new list can be seen to not reflect in the old list, as the
new list is now referring to a different object.
>>> # ================================================================
... # === ShallowCopy.py =============================================
... # ================================================================
... #
... class Foo:
... def __init__(self, data):
... self._data = data
...
>>> aa = Foo ('aaa')
>>> bb = Foo ('bbb')
>>>
>>> # The initial list has two elements containing 'aaa' and 'bbb'
... OldList = [aa,bb]
>>> print OldList[0]._data
aaa
>>>
>>> # The shallow copy makes a new list pointing to the old elements
... NewList = OldList[:]
>>> print NewList[0]._data
aaa
>>>
>>> # Updating one of the elements through the new list sees the
... # change reflected when you access that element through the
... # old list.
... NewList[0]._data = 'xxx'
>>> print OldList[0]._data
xxx
>>>
>>> # Updating the new list to point to something new is not reflected
... # in the old list.
... NewList[0] = Foo ('ccc')
>>> print NewList[0]._data
ccc
>>> print OldList[0]._data
xxx
Like NXC said, Python variable names actually point to an object, and not a specific spot in memory.
newList = oldList would create two different variables that point to the same object, therefore, changing oldList would also change newList.
However, when you do newList = oldList[:], it "slices" the list, and creates a new list. The default values for [:] are 0 and the end of the list, so it copies everything. Therefore, it creates a new list with all the data contained in the first one, but both can be altered without changing the other.
As it has already been answered, I'll simply add a simple demonstration:
>>> a = [1, 2, 3, 4]
>>> b = a
>>> c = a[:]
>>> b[2] = 10
>>> c[3] = 20
>>> a
[1, 2, 10, 4]
>>> b
[1, 2, 10, 4]
>>> c
[1, 2, 3, 20]
Never think that 'a = b' in Python means 'copy b to a'. If there are variables on both sides, you can't really know that. Instead, think of it as 'give b the additional name a'.
If b is an immutable object (like a number, tuple or a string), then yes, the effect is that you get a copy. But that's because when you deal with immutables (which maybe should have been called read only, unchangeable or WORM) you always get a copy, by definition.
If b is a mutable, you always have to do something extra to be sure you have a true copy. Always. With lists, it's as simple as a slice: a = b[:].
Mutability is also the reason that this:
def myfunction(mylist=[]):
pass
... doesn't quite do what you think it does.
If you're from a C-background: what's left of the '=' is a pointer, always. All variables are pointers, always. If you put variables in a list: a = [b, c], you've put pointers to the values pointed to by b and c in a list pointed to by a. If you then set a[0] = d, the pointer in position 0 is now pointing to whatever d points to.
See also the copy-module: http://docs.python.org/library/copy.html
Shallow Copy: (copies chunks of memory from one location to another)
a = ['one','two','three']
b = a[:]
b[1] = 2
print id(a), a #Output: 1077248300 ['one', 'two', 'three']
print id(b), b #Output: 1077248908 ['one', 2, 'three']
Deep Copy: (Copies object reference)
a = ['one','two','three']
b = a
b[1] = 2
print id(a), a #Output: 1077248300 ['one', 2, 'three']
print id(b), b #Output: 1077248300 ['one', 2, 'three']