Adding lists by reference - python

Is it possible to add two lists using a reference of each list instead of a copy?
For example -
first_list = [1,2,3]
second_list = [5,6]
new_list = first_list + second_list
print(new_list) # Will print [1,2,3,5,6]
first_list.append(4)
print(new_list) # Should print [1,2,3,4,5,6]
Is there a way to do this in Python? Or is code re-write my only option?
Edit: I removed confusing comments I made about using C++ to do this.

You can't directly do this in Python any more than you can in C++.
But you can indirectly do it in Python the exact same way you can in C++: by writing an object that holds onto both lists and dispatches appropriately.
For example:
class TwoLists(collections.abc.Sequence):
def __init__(self, a, b):
self.a, self.b = a, b
def __len__(self):
return len(self.a) + len(self.b)
def __getitem__(self, idx):
# cheating a bit, not handling slices or negative indexing
if idx < len(self.a):
return self.a[idx]
else:
return self.b[idx - len(self.a)]
Now:
>>> first_list = [1,2,3]
>>> second_list = [5,6]
>>> two_lists = TwoLists(first_list, second_list)
>>> print(*two_lists)
1 2 3 5 6
>>> first_list.append(4)
>>> print(*two_lists)
1 2 3 4 5 6
What I think you were missing here is a fundamental distinction between Python and C++ in how variables work. Briefly, every Python variable (and attribute and list position and so on) is, in C++ terms, a reference variable.
Less misleadingly:
C++ variables (and attributes, etc.) are memory locations—they're where values live. If you want a to be a reference to the value in b, you have to make a reference-to-b value, and store that in a. (C++ has a bit of magic that lets you define a reference variable like int& a = b, but you can't later reassign a to refer to c; if you want that, you have to explicitly use pointers, C-style.)
Python variables (and etc.) are names for values, while the values live wherever they want to. If you want a to be a reference to the value in a, you just bind a to the same value b is bound to: a = b. (And, unlike C++, you can reassign a = c at any time.)
Of course the cost is performance: there's an extra indirection to reach any value from its name in Python, while in C++, that only happens when you use pointer variables. But that cost is pretty much always invisible compared to the other overhead of Python (interpreting bytecode and dynamically looking names up in dictionaries and so on), so it makes sense for a high-level language to just not give you the choice.
All that being said, there's usually not a good reason to do this in either language. Both Python, and the C++ standard library, are designed around (similar, but different notions of) iteration.
In Python, you usually don't actually need a sequence, just an iterable. And to chain two iterables together is trivial:
>>> from itertools import chain
>>> first_list = [1,2,3]
>>> second_list = [5,6]
>>> print(*chain(first_list, second_list))
1 2 3 5 6
>>> first_list.append(4)
>>> print(*chain(first_list, second_list))
1 2 3 4 5 6
Yes, I can only iterate over the chain once, but usually that's all you need. (Just as in C++ you usually only need to loop from begin(c) to end(c), not to build a new persistent object that holds onto them.)
And if you think that's cheating because I'm using itertools, we can define it ourselves:
def chain(*its):
for it in its:
yield from it

Related

Python find same elemts in an optional amount of lists

I'm looking for a way to find an element that exists in an optional amount of lists.
Currently I'm able to find it in two lists:
def Mengen(liste1, liste2):
print(liste2)
A = set(liste1)
B = set(liste2)
if (A & B):
return(A & B)
I now would like to expand that for multiple lists. I already tried to use pointers but I weren't able to make this work.
Has anyone a good way to solve that problem?
Thanks for any help in advance :)
Edit:
The function is called like this:
a = [1,2,3,4]
b = [4,5,6,7]
c = [4,8,9,20]
d = [4,567,756,456,423]
Mengen(a,b)
And the output should be just a 4 or [4]
Since you just want "what's in every input", this can be done easily with set's intersection method (which takes varargs, and does not require them to be sets themselves, so you can pass all of your arguments save the first to it), and it does it all in one efficient operation:
def common_entries(iterable, *rest):
return list(set(iterable).intersection(*rest))
This improves on the existing answer in a few ways (I originally began this as a comment suggesting improvements, but it got involved enough that I decided to separate it):
I removed a multiple unnecessary list comprehensions (the inner listcomp is completely unnecessary; [i for i in args] needlessly makes a list from the tuple received when you could just use args directly)
It avoids a ton of temporary sets you don't strictly need (set.intersection's arguments can be any iterable; you don't need to convert them)
Since one input is mandatory (the original code would explode in a more confusing way if you passed no arguments), you can accept it separately, making the code allowed by #2 neater
For the simple test input of:
a = [1,2,3,4]
b = [4,5,6,7]
c = [4,8,9,20]
d = [4,567,756,456,423]
my common_entries(a, b, c, d) takes roughly half the time to run as the other answer's findDuplicates(a, b, c, d), and reduces the number of explicit temporaries from n + 2 to zero (internally, set.intersection does make temporary sets to represent progressive intersection results, but those can't be avoided in any reasonable way).
def findDuplicated(*args):
return list(set.intersection(*[set(j) for j in [i for i in args]]))
findDuplicated([1,2,3,4], [4,5,6,7], [4,8,9,20], [4,567,756,456,423])
This works:
Set1 = set(input().split())
Set2 = set(input().split())
Set3 = set(input().split())
Set4 = set(input().split())
Set5 = Set1.intersection(Set2)
Set6 = Set3.intersection(Set4)
print(Set5.intersection(Set6))
The input should be in the format of this:
1 2 3 4
4 5 6 7
4 9 10
4 567 572
It has to be separated by the space, but this should work.

How to re-assign a variable in python without changing its id?

When assigning a variable to another, they point to the same object. So, how do I change the value for one of them with the variables still pointing to the same object?
a = 10
b = a
a -= 1
print(b) #expect to print 9 but it print 10
How to re-assign a variable in python without changing its id?
I'm not sure whether you're confused about variables in Python, or about immutable values. So I'm going to explain both, and half the answer will probably seem like "no duh, I already knew that", but the other half should be useful.
In Python—unlike, say, C—a variable is not a location where values live. It's just a name. The values live wherever they want to.1 So, when you do this:
a = 10
b = a
You're not making b into a reference to a. That idea doesn't even make sense in Python. You're making a into a name for 10, and then making b into another name for 10. And if you later do this:
a = 11
… you've made a into a name for 11, but this has no effect on b—it's still just a name for 10.
This also means that id(a) is not giving you the ID of the variable a, because there is no such thing. a is just a name that gets looked up in some namespace (e.g., a module's globals dict). It's the value, 11 (or, if you ran it earlier, the different value 10) that has an ID. (While we're at it: it's also values, not variables, that are typed. Not relevant here, but worth knowing.)
Things get a bit tricky when it comes to mutability. For example:
a = [1, 2, 3]
b = a
This still makes a and b both names for a list.
a[0] = 0
This doesn't assign to a, so a and b are still names for the same list. It does assign to a[0], which is part of that list. So, the list that a and b both name now holds [0, 2, 3].
a.extend([4, 5])
This obviously does the same thing: a and b now name the list [0, 2, 3, 4, 5].
Here's where things get confusing:
a += [6]
Is it an assignment that rebinds a, or is it just mutating the value that a is a name for? In fact, it's both. What this means, under the covers, is:
a = a.__iadd__([6])
… or, roughly:
_tmp = a
_tmp.extend([6])
a = _tmp
So, we are assigning to a, but we're assigning the same value back to it that it already named. And meanwhile, we're also mutating that value, which is still the value that b names.
So now:
a = 10
b = 10
a += 1
You probably can guess that the last line does something like this:
a = a.__iadd__(1)
That's not quite true, because a doesn't define an __iadd__ method, so it falls back to this:
a = a.__add__(1)
But that's not the important bit.2 The important bit is that, because integers, unlike lists, are immutable. You can't turn the number 10 into the number 11 the way you could in INTERCAL or (sort of) Fortran or that weird dream you had where you were the weirdest X-Man. And there's no "variable holding the number 10" that you can set to 11, because this isn't C++. So, this has to return a new value, the value 11.
So, a becomes a name for that new 11. Meanwhile, b is still a name for 10. It's just like the first example.
But, after all this telling you how impossible it is to do what you want, I'm going tell you how easy it is to do what you want.
Remember earlier, when I mentioned that you can mutate a list, and all the names for that list will see the new value? So, what if you did this:
a = [10]
b = a
a[0] += 1
Now b[0] is going to be 11.
Or you can create a class:
class Num:
pass
a = Num()
a.num = 10
b = a
a.num += 1
Now, b.num is 11.
Or you can even create a class that implements __add__ and __iadd__ and all the other numeric methods, so it can hold numbers (almost) transparently, but do so mutably.
class Num:
def __init__(self, num):
self.num = num
def __repr__(self):
return f'{type(self).__name__}({self.num})'
def __str__(self):
return str(self.num)
def __add__(self, other):
return type(self)(self.num + other)
def __radd__(self, other):
return type(self)(other + self.num)
def __iadd__(self, other):
self.num += other
return self
# etc.
And now:
a = Num(10)
b = a
a += 1
And b is a name for the same Num(11) as a.
If you really want to do this, though, you should consider making something specific like Integer rather than a generic Num that holds anything that acts like a number, and using the appropriate ABC in the numbers module to verify that you covered all the key methods, to get free implementations for lots of optional methods, and to be able to pass isinstance type checks. (And probably call num.__int__ in its constructor the way int does, or at least special-case isinstance(num, Integer) so you don't end up with a reference to a reference to a reference… unless that's what you want.)
1. Well, they live wherever the interpreter wants them to live, like Romanians under Ceaușescu. But if you're a builtin/extension type written in C and a paid-up member of the Party, you could override __new__ with a constructor that doesn't rely on super to allocate, but otherwise you have no choice.
2. But it's not completely unimportant. By convention (and of course in all builtin and stdlib types follow the convention), __add__ doesn't mutate, __iadd__ does. So, mutable types like list define both, meaning they get in-place behavior for a += b but copying behavior for a + b, while immutable types like tuple and int define only __add__, so they get copying behavior for both. Python doesn't force you to do things this way, but your type would be very strange if it didn't pick one of those two. If you're familiar with C++, it's the same—you usually implement operator+= by mutating in-place and returning a reference to this, and operator+ by copying and then returning += on the copy, but the language doesn't force you to, it's just confusing if you don't.
Variables don't have id, an id belongs to an object.
Integers e.g.: 10,9 are separate and immutable objects, 'a','b' variables are references only. id(a) really gives the id of the referenced object. The object '10' can not be mutated in place.
id(10), id(9)
Out[16]: (10943296, 10943264)
In [17]: a,b=10,10
In [18]: id(a),id(b)
Out[18]: (10943296, 10943296)
In [19]: b=a-1
In [20]: id(b)==id(9)
Out[20]: True
However, lists are mutable objects and can be changed in place with the [:] operator (and of course, with their methods,e.g.: append,extend):
l=[10,5]
In [29]: id(l),id(l[0]),id(l[1])
Out[29]: (139638954619720, 10943296, 10943136)
In [30]: id(l[0])==id(10)
Out[30]: True
In [31]: l=[10,5] # a new list object created, though the content is the same
In [32]: id(l)
Out[32]: 139638920490248
In [33]: l[:]=["a","b"] # in place changes
In [34]: id(l)
Out[34]: 139638920490248

Why is python treating lists like this when defining a function?

I was making a code, and variables started to behave strangely and get assigned to things which I thought they shouldn't. So, I decided to reduce the situation to minimal complexity in order to solve my doubts, and this is what happened:
The following code:
a = [2]
def changeA(c):
d = c
d[0] = 10
return True
changeA(a)
print(a)
prints '[10]'. This doesn't make sense to me, since I never assigned the list "a" to be anything after the first assignment. Inside the function changeA, the local variable d is assigned to be the input of the function, and it seems to me that this assignment is happening both ways, and even changing the "outside". If so, why? If not, why is this happening?
I've also noticed that the code
a = [2]
def changeA(c):
d = list(c)
d[0] = 10
return True
changeA(a)
print(a)
behaves normally (i.e., as I would expect).
EDIT: This question is being considered a duplicate of this one. I don't think this is true, since it is also relevant here that the locality character of procedures inside a function is being violated.
Python variables are references to objects, and some objects are mutable. Numbers are not, neither are strings nor tuples, but lists, sets and dicts are.
Let us look at the following Python code
a = [2] # ok a is a reference to a mutable list
b = a # b is a reference to the exact same list
b[0] = 12 # changes the value of first element of the unique list
print(a) # will display [12]
In the first example, you simply pass the reference of c(which is a) to d.
So whatever you do to d will happen on a.
In the second example, you copy the value of c(which is a) and give it to a new variable d.
So the d now has the same value as c(which is a) but different reference.
Note: you can see the reference or id of a variable using the id() function.
a = [2]
print id(a)
def changeA(c):
d = c
pirnt id(d)
d[0] = 10
return True
changeA(a)
print(a)
a = [2]
print id(a)
def changeA(c):
d = list(c)
print id(d)
d[0] = 10
return True
changeA(a)
print(a)
Its because when you do:
d = list(c)
that creates a new object. But when you do
d = c
You are making a reference to that object.
if you did
d.append(5)
to the first example you would get
[10,5]
Same operation to the second one and the list isn't modified.
Deeper explanation in the following link: http://henry.precheur.org/python/copy_list
In Python, names refer to values, so you have 2 names pointing to the same value.
In version 1 you create a list a, pass it in to the function under the pseudonym c, create another pseudonym d for the very same list, and then change the first value in that list. a, c, and d all refer to the same list.
In version 2, you're using list(c) which, to Python, means "take the contents of this iterable thing named c and make a new, different, list from it named d". Now, there are two copies of your list floating around. One is referred to as a or c, and the other is d. Therefore, when you update d[0] you're operating a second copy of the list. a remains unchanged.
'd=c' means reference copy as stated before. What it means, is that now d will reference the same object as c. As you are doing a direct manipulation on the referenced object, the value of the object a was referencing to is changed as well.
When you do 'd = list(c)' what it means that a new list object is created, with the baked of c. However, d is not referencing the same object as a anymore. Hence, the changes within the function doesn't impact a.

temporary variables in a python expression

Some (many? all?) functional programming languages like StandardML and Haskell have a type of expression in the form let ... in ... where is possible to create temporary variables with the scope of the expression itself.
Example: let a=b*c in a*(a+1)
It seems that in Python there is no expression construct similar to this.
Motivation:
For example the body of a lambda function must be a (one) expression. Not two expressions. Not a statement (an assignment is a statement and not an expression).
Moreover, when writing functional expressions and in general one-liners in python, things can become messy pretty easily (see my answer to Python 2 list comprehension and eval).
The point of such a construct is to avoid repetition (which sometimes leads to re-computation), for example l[:l.index(a)]+l[l.index(a)+1:] instead of an hypothetic let i=l.index(a) in l[:i]+l[i+1:]
How can we achieve a similar language feature in python2 / python3?
This isn't really idiomatic code, but for single expressions you can use lambdas that you immediately invoke. Your example would look like this:
>>> b, c = 2, 3
>>> (lambda a: a * (a + 1))(b * c)
42
You can also write this using keyword arguments if that helps readability:
>>> (lambda a: a * (a + 1))(a=b * c)
42
You can sort of simulate a smaller scope for your temporary variable by putting it into an iterable and then looping over that iterable:
>>> b,c = 2,3
>>> var = [a*(a+1) for a in [b*c]][0]
>>> var
42
This puts the single value b*c into a list, then loops over that list in a comprehension, with each new value consisting of some transformation of each element. The created list is one element in length, and we get the first element in it with [0]. Without the comprehension, it looks as follows:
>>> b,c = 2,3
>>> var = []
>>> for a in [b*c]:
... var.append(a*(a+1))
...
>>> var = var[0]
>>> var
42

Why Use a=b in Python

If I define
foo = [[1,2],[2,3],[3,4]]
bar = foo
then foo and bar reference the same object, namely [[1,2],[2,3],[3,4]]. I can now use either of these "tags/namespaces/references" to make changes to the object [[1,2],[2,3],[3,4]], but how is this useful to anyone?
One reason it can be useful to rebind names to existing values is if you intend to reuse the original name for a different object. For instance, this function to calculate the nth number in the Fibonacci sequence reuses the names a, b and temp repeatedly in a loop, binding the value previously referenced by a to b (via temp) each time:
def fib(n):
a = 1
b = 0
for _ in range(n):
temp = a
a = a+b
b = temp
# A more Pythonic version of the last three lines would be: a, b = a+b, a
return b
Let's say I have an attribute of my class instance, frobnoz, a reference to an instance of a Frobnoz class which in turn an attribute marfoos which is a list of all the associated marfoos, and I want to perform several operations on the first one.
marfoo = self.frobnoz.marfoos[0]
marfoo.rotate(CLOCKWISE, degrees=90)
if marfoo.is_cloudy():
self.purge_clouds(marfoo)
If it were not possible to create an additional reference to the marfoo I wanted to perform actions on, I would have had to not only have lengthy references to it, but would also incur the expense of looking up both the frobnoz and marfoos references plus the first element of the list each time I wanted to use it.
It is useful (among other things) for function calls that modify a value:
def changeFoo(bar):
bar[0][0]=3.14
changeFoo(foo)
Note: This does not technically use assignment, but it is equivalent.
It can also be used when multiple objects need to have a reference to the same object (such as in linked lists).

Categories