Python list assignation - python

I've got this code
class coordenates:
x = 0
y = 0
coor = coordenates()
coor.x=0
coor.y=0
list = []
list.append(coor)
list.append(coor)
Now, the problem is that when I update
list[0].x=100
it is also modifing list[1].x somehow!
print str(list[0].x)
>> 100
print str(list[1].x)
>> 100
which must remain in 0 since I haven't update it. Is append() creating the same object pointing in the same position in memory in positions 0 and 1? why creating 2 different objects solves the problem?

In your current code, x and y are class-level attributes. I suspect that you want them to be instance-level attributes. If so, set them in __init__():
class Coordinates:
def __init__(self):
self.x = 0
self.y = 0
More important, if you append the same coor to the list twice, any mutation of the coor will be reflected in "both" coordinates (because the list is just holding a reference to the same underlying coordinate in both positions of the list). Maybe you want something like this instead, where you create two independent coordinate instances?
list = []
list.append(Coordinates())
list.append(Coordinates())
You can see an illustration of your problem with this code:
c = Coordinates()
cs = []
cs.append(c)
cs.append(c)
for c in cs:
print id(c) # Both elements of the list refer to the same object.

Related

Possible to change the original variables in an array?

Consider this (uncontroversial) simple example:
allvars = []
a = 1
allvars.append(a)
b = 2
allvars.append(b)
c = 3
allvars.append(c)
d = 4
allvars.append(d)
e = 5
allvars.append(e)
for ix in allvars:
ix = ix + 1 # changes local variable ix, but not array elements
print(allvars) # [1, 2, 3, 4, 5]
for i, ix in enumerate(allvars):
allvars[i] = ix + 1 # changes array elements ...
print(allvars) # [2, 3, 4, 5, 6]
# ... but not original variables
print(a,b,c,d,e) # 1 2 3 4 5
Even if we had some variables "stored" into a Python list - changing that list did not change the original variables.
It is clear why this happens, if we recall that Python in fact stores pointers (as I read somewhere, "python has names, not variables"):
when we do a = 1; a points to the address of the int object 1
allvars[0], which is where we thought we stored a, also gets the address of the int object 1
In allvars[0] = allvars[0]+1, the final allvars[0] gets the address of the resulting int object, 2
however, that doesn't change the fact that a still points to the int object 1
The thing is, however, - I have a situation, where I have to manage a bunch of variables (like a, b ... above) separately; however, in the code, there are cases that would be more straightforward to handle, if I ran a loop over all these variables - but, the variables would have to be updated, because after the phase when the loops are useful, I have some remaining processing to be done on the variables (a, b etc) individually, where the updated values are expected.
So is there some (not too convoluted) way in Python, to put variables (or maybe, variable names) in a list/array, and then iterate over that array - and change the original variable (names)?
In terms of above example, I'd want to do something like this pseudocode:
...
for i, ix in enumerate(allvars):
change_originals("allvars[i] = ix + 1")
print(a,b,c,d,e) # this should be 2, 3, 4, 5, 6
Here you have created an array of primitives value. Primitives always copy whenever you use it. So mofication wont reflect on the original variable.
There are possible solution base on your requirement.
class Val:
def __init__(self, val = -1):
self._val = val
def get_val(self):
return self._val
# setter method
def set_val(self, x):
self._val = x
allvars = []
one = Val(1)
allvars.append(one)
print(allvars[0]._val)
one.set_val(2)
print(allvars[0]._val)
You can use a dictionary with key[1,2,3,4...]
You can create array of object
One way I can think of to do this would store the variable names as strings in a list, then use the exec function. This function always returns 0. It accepts a string argument and then executes that string as valid python code. So:
# Where allvars contains string names of variables
...
for i, ix in enumerate(allvars):
exec(f"{allvars[i]} = {ix} + 1")
Another way would use the locals() function, which gives you a dictionary with names and values of variables and any other names:
# using locals() function
# Make a list of variable names
allvars_strings = ['a','b','c','d','e']
# Slightly simpler
for i in allvars_strings:
locals()[i] = locals()[i] + 1
string = ''
print('\n\n')
for i in allvars_strings:
string += str(locals()[i]) + ', '
print(string[:-2])

Why function changes global list and not global integer with the same code [duplicate]

This question already has answers here:
Why can a function modify some arguments as perceived by the caller, but not others?
(13 answers)
Closed 3 years ago.
Let's take a simple code:
y = [1,2,3]
def plusOne(y):
for x in range(len(y)):
y[x] += 1
return y
print plusOne(y), y
a = 2
def plusOne2(a):
a += 1
return a
print plusOne2(a), a
Values of 'y' change but value 'a' stays the same. I have already learned that it's because one is mutable and the other is not. But how to change the code so that the function doesn't change the list?
For example to do something like that (in pseudocode for simplicity):
a = [1,2,3,...,n]
function doSomething(x):
do stuff with x
return x
b = doSomething(a)
if someOperation(a) > someOperation(b):
do stuff
EDIT: Sorry, but I have another question on nested lists. See this code:
def change(y):
yN = y[:]
for i in range(len(yN)):
if yN[i][0] == 1:
yN[i][0] = 0
else:
yN[i][0] = 1
return yN
data1 = [[1],[1],[0],[0]]
data2 = change(data1)
Here it doesn't work. Why? Again: how to avoid this problem? I understand why it is not working: yN = y[:] copies values of y to yN, but the values are also lists, so the operation would have to be doubled for every list in list. How to do this operation with nested lists?
Python variables contain pointers, or references, to objects. All values (even integers) are objects, and assignment changes the variable to point to a different object. It does not store a new value in the variable, it changes the variable to refer or point to a different object. For this reason many people say that Python doesn't have "variables," it has "names," and the = operation doesn't "assign a value to a variable," but rather "binds a name to an object."
In plusOne you are modifying (or "mutating") the contents of y but never change what y itself refers to. It stays pointing to the same list, the one you passed in to the function. The global variable y and the local variable y refer to the same list, so the changes are visible using either variable. Since you changed the contents of the object that was passed in, there is actually no reason to return y (in fact, returning None is what Python itself does for operations like this that modify a list "in place" -- values are returned by operations that create new objects rather than mutating existing ones).
In plusOne2 you are changing the local variable a to refer to a different integer object, 3. ("Binding the name a to the object 3.") The global variable a is not changed by this and continues to point to 2.
If you don't want to change a list passed in, make a copy of it and change that. Then your function should return the new list since it's one of those operations that creates a new object, and the new object will be lost if you don't return it. You can do this as the first line of the function: x = x[:] for example (as others have pointed out). Or, if it might be useful to have the function called either way, you can have the caller pass in x[:] if he wants a copy made.
Create a copy of the list. Using testList = inputList[:]. See the code
>>> def plusOne(y):
newY = y[:]
for x in range(len(newY)):
newY[x] += 1
return newY
>>> y = [1, 2, 3]
>>> print plusOne(y), y
[2, 3, 4] [1, 2, 3]
Or, you can create a new list in the function
>>> def plusOne(y):
newList = []
for elem in y:
newList.append(elem+1)
return newList
You can also use a comprehension as others have pointed out.
>>> def plusOne(y):
return [elem+1 for elem in y]
You can pass a copy of your list, using slice notation:
print plusOne(y[:]), y
Or the better way would be to create the copy of list in the function itself, so that the caller don't have to worry about the possible modification:
def plusOne(y):
y_copy = y[:]
and work on y_copy instead.
Or as pointed out by #abarnet in comments, you can modify the function to use list comprehension, which will create a new list altogether:
return [x + 1 for x in y]
Just create a new list with the values you want in it and return that instead.
def plus_one(sequence):
return [el + 1 for el in sequence]
As others have pointed out, you should use newlist = original[:] or newlist = list(original) to copy the list if you do not want to modify the original.
def plusOne(y):
y2 = list(y) # copy the list over, y2 = y[:] also works
for i, _ in enumerate(y2):
y2[i] += 1
return y2
However, you can acheive your desired output with a list comprehension
def plusOne(y):
return [i+1 for i in y]
This will iterate over the values in y and create a new list by adding one to each of them
To answer your edited question:
Copying nested data structures is called deep copying. To do this in Python, use deepcopy() within the copy module.
You can do that by make a function and call this function by map function ,
map function will call the add function and give it the value after that it will print the new value like that:
def add(x):
return x+x
print(list(map(add,[1,2,3])))
Or you can use (*range) function it is very easy to do that like that example :
print ([i+i for i in [*range (1,10)]])

How can I create an indefinite iterations of objects in python?

I'm new to python and am trying to create a program to test some methods of object creation. Currently, I'm writing a program that involves creating objects, giving them a unique numeric variable, and assigning them to a list for future referencing. Here's what I wrote to create the variable names:
def getRectangleName():
rectName = list("Rectangle")
SPAWNEDOBJECTLIST.append(len(SPAWNEDOBJECTLIST))
rectName.append(str(len(SPAWNEDOBJECTLIST)))
return rectName
and then that's passed onto something to turn that string into a variable name. I tried eval(), learned this was Bad for some reason and it didn't work anyway, and tried some workarounds to no avail.
I figure there's plenty of games that have an indefinite number of characters on the screen. Is there an established way of making iterations of objects like this?
The objects themselves have an X and Y so that they act as reference points for the display of rectangles on screen(the idea in the future is to have each one move around on their own, so simply making lists of X and Y to draw rectangles isn't useful).
Edit: The problem is that I don't know how to give each object its own variable to put it on a list for future referencing.
Edit2: I don't think I'm asking the right question, actually, or using the right terminology. I need to be able to have an indefinite number of objects created on the fly after the program is already running, and be able to reference them individually.
The problem is that I don't know how to give each object its own variable to put it on a list for future referencing.
Whenever you think you need variables you didn't type into your program, you're doing something wrong. You don't need to assign something to a variable to put it on a list:
x = [1, 2, 3] # Note how I don't assign 1, 2, or 3 to variables.
x.append(4) # 4 doesn't get a variable either.
x.append(make_a_rectangle()) # We create a rectangle and stick it on the list.
do_stuff_with(x[4]) # We pass the rectangle to a function.
x = [] # New list.
for i in xrange(n):
x.append(make_a_rectangle()) # This happens n times.
# At this point, we have n rectangles, none of them associated with their own
# variable, none of them with a name.
If you think you need names for things (and quite often, you don't really need the names), you can use a dict:
x = {}
x['foo'] = make_a_rectangle()
do_stuff_with(x['foo'])
It's not a great idea to combine the function of managing the rectangles -- accessing, adding, or deleting them -- with the idea of being rectangles. You never know when you might need to maintain multiple lists, or change from unordered lists to organized ones.
Until you really need more, keep the management functions simple: use built-in lists or dictionaries. Use lists if you just care about ordering, or only need to know you have a bunch of stuff:
class Rectangle (object):
def __init__(self, top, bottom, left, right):
self.Top = top
self.Left = left
self.Right = right
self.Bottom = bottom
list_of_rects = [Rectangle(10,0,0,10), Rectangle(20, 10, 10 ,20)]
# how many rects?
len(list_of_rects)
# result: 2
# where is this particular rect?
fred = Rectangle(30,20,20, 30)
list_of_rects.insert(fred, 1)
list_of_rects.index(fred)
# result: 1
#remove an item from the list:
list_of_rects.remove(fred)
#search the list:
right_of_5 = [rect for rect in list_of_rects if rect.Left > 5]
If you need to get access to the individual rects for some reason -- 'what's the rectangle of the goal' or something -- you have two choices:
1) the code that needs the rect just keeps a reference to it:
class Goal(object):
def __init__(self, rect):
self.Rect = rect
goalrect = Rectangle (0,0,20,20)
mygoal = Goal(goalrect)
list_of_rects.append(goalrect)
# now goalrect always knows about it's own rect, but the list can keep track of it too...
2) Or, use a dictionary:
named_rects = {}
named_rects['goal'] = Rectangle(0,0,20,20)
You get all the same abilities with a dictionary that you do with a list -- add, delete, and find -- except dictionaries don't preserve order, so you can't manage things like priority:
# add to the dict:
named_rects['new_rect'] = Rectangle(90,90,95,95)
# remove
del named_rects['new_rect']
# find = is there a known key?
if 'new_rect' in named_rects: print new_rect
# search:
right_of_5 = [rect for rect in named_rects.items() if rect.Left > 5]
There are cases where you need fancier things than plain old lists and dicts -- but always try it with the free stuff first :)
If you dynamically want to create variables and add them to class instances, use this
class MainClass:
def __setattr__(self, name, value):
self.__dict__[name] = value
def getRectangleNameGenerator(N = 10):
X = 0
while X <= N:
X += 1
yield "Rectangle" + str(X)
RectangleName = getRectangleNameGenerator()
ClassInstances = {next(RectangleName) : MainClass}
ClassInstances[next(RectangleName)] = MainClass
ClassInstances["Rectangle1"].Temp = 10
print ClassInstances["Rectangle1"].Temp
If the class is going to have only X and Y,
class MainClass:
X, Y = 0, 0
def getRectangleNameGenerator(N = 10):
X = 0
while X <= N:
X += 1
yield "Rectangle" + str(X)
RectangleName = getRectangleNameGenerator()
ClassInstances = {next(RectangleName) : MainClass}
ClassInstances[next(RectangleName)] = MainClass
ClassInstances["Rectangle1"].X = 11
print ClassInstances["Rectangle1"].X
If you really want to refer to your rectangle instances by name, I would suggest to keep a dictionary at class level. Something like this:
#! /usr/bin/python3
from threading import Lock
import random
class Rectangle:
instances = {}
lock = Lock ()
#classmethod
def forName (cls, name):
return cls.instances [name] if name in cls.instances else None
#classmethod
def push (cls, inst):
with cls.lock:
name = None
while not name or name in cls.instances:
name = ''.join (random.choice ('abcdefghij') for i in range (16) )
cls.instances [name] = inst
return name
def __init__ (self):
self.name = Rectangle.push (self)
names = [Rectangle ().name for i in range (5) ]
for name in names:
print (name, Rectangle.forName (name) )

Prevent member objects referencing the same list

This should be simple...
class Object:
x = 0
y = []
a = Object()
b = Object()
a.x = 1
b.x = 2
print a.x, b.x
# output: 1 2
# works as expected
a.y.append(3)
b.y.append(4)
print a.y, b.y
# output: [3, 4] [3, 4]
# same list is referenced how to fix?
# desired output: [3] [4]
As far as I can tell, a.y and b.y reference the same list. How can I get them to be separate? Preferably, without adding an __init__ method.
You're creating the value of y only once, when you define the class. To assign a different list to each instance of y, you do need an init function. Just put self.y = [] in __init__ and it will work as intended.
What's happening here is that you actually have actually redefined x as an instance level attribute, and your class definition had them as both class level attributes.
If you do this, you can see your original x is still at 0.
>>> Object.x
0
As you don't create a new list, it's taking the class attribute. If you were to do this:
>>> a.y = []
>>> b.y = []
>>> a.y.append(1)
>>> b.y.append(2)
>>> print a.y, b.y
[1] [2]
That is what you are expecting. Really though you should be defining your class like this:
class Object(object):
def __init__(self):
self.y = []
self.x = 0
(and don't use Object as a classname!)
The easiest way to setup instance properties instead of class properties is to use __init__
When you reference an instance property (like a.y) the parser tries to return that first but if it isn't found the class property (Object.y) is returned.
In your case only defined a class property which is shared by all instances.
The only way to do that is creating the __init__ method
class Object:
def __init__(self):
self.x = 0
self.y = []
That way upon Object's construction, a new value will be assined to x and a new List will be created for y.
The way you were doing before creates two class/static variables to Object, but only y stays the same because it holds statically only a reference to the true List, reflecting to all instances of Object.
More on class/static variables on this other question:
Static class variables in Python
*Sorry if I used the wrong terms, I'm more of a Java person ;-)

Pointers in Python? ` x.pointerDest = y.pointerDest`?

I am breaking my old question to parts because it is very messy beast here. This question is related to this answer and this answer. I try to understand pointers, not sure even whether they exist in Python.
# Won't change x with y=4
>>> x = 0; y = x; y = 4; x
0
# Won't change y
>>> x = 0; y = x; x = 2; y
0
#so how can I change pointers? Do they even exist in Python?
x = 0
y.pointerDestination = x.pointerDestination #How? By which command?
x = 2
# y should be 0, how?
[Update 2: Solved]
Perhaps, contradictive statements about the existence There are no pointers in Python. and Python does not have the concept of a "pointer" to a simple scalar value.. Does the last one infer that there are pointers to something else, nullifying the first statement?
Scalar objects in Python are immutable. If you use a non-scalar object, such as a list, you can do this:
>>> x = [0]
>>> y = x
>>> y[0] = 4
>>> y
[4]
>>> x
[4]
>>> x is y
True
Python does not have the concept of a "pointer" to a simple scalar value.
Don't confuse pointers to references. They are not the same thing. A pointer is simply an address to an object. You don't really have access to the address of an object in python, only references to them.
When you assign an object to a variable, you are assigning a reference to some object to the variable.
x = 0
# x is a reference to an object `0`
y = [0]
# y is a reference to an object `[0]`
Some objects in python are mutable, meaning you can change properties of the object. Others are immutable, meaning you cannot change the properties of the object.
int (a scalar object) is immutable. There isn't a property of an int that you could change (aka mutating).
# suppose ints had a `value` property which stores the value
x.value = 20 # does not work
list (a non-scalar object) on the other hand is mutable. You can change individual elements of the list to refer to something else.
y[0] = 20 # changes the 0th element of the list to `20`
In the examples you've shown:
>>> x = [0]
>>> y = [x]
you're not dealing with pointers, you're dealing with references to lists with certain values. x is a list that contains a single integer 0. y is a list that contains a reference to whatever x refers to (in this case, the list [0]).
You can change the contents of x like so:
>>> print(x)
[0]
>>> x[0] = 2
>>> print(x)
[2]
You can change the contents of the list referenced by x through y's reference:
>>> print(x)
[2]
>>> print(y)
[[2]]
>>> y[0][0] = 5
>>> print(x)
[5]
>>> print(y)
[[5]]
You can change the contents of y to reference something else:
>>> print(y)
[[5]]
>>> y[0] = 12345
>>> print(x)
[5]
>>> print(y)
[12345]
It's basically the same semantics of a language such as Java or C#. You don't use pointers to objects directly (though you do indirectly since the implementations use pointers behind the scenes), but references to objects.
There are no pointers in Python. There are things called references (which, like C++ references, happen to be commonly implemented in pointers - but unlike C++ references don't imply pass-by-reference). Every variable stores a reference to an object allocated somewhere else (on the heap). Every collection stores references to objects allocated somewhere else. Every member of an object stores a reference to an object allocated somewhere else.
The simple expression x evaluates to the reference stored in x - whoever uses it has no way to determine that is came from a variable. There's no way to get a link to a variable (as opposed to the contents of it) that could be used to track changes of that variable. Item (x[y] = ...) and member (x.y = ...) assignments are different in one regard: They invoke methods and mutate existing objects instead of overwriting a local variable. This difference is mainly important when dealing with scoping, but you can use either of those to emulate mutability for immutable types (as shown by #Greg Hewgill) and to share state changes across function boundaries (def f(x): x = 0 doesn't change anything, but def g(x): x.x = 0 does). It's not fully up to emulating pass by reference though - unless you replace every variable by a wrapper object whose sole purpose is to hold a mutable val property. This would be the equivalent to emulating pass-by-reference through pointers in C, but much more cumbersome.

Categories