Python list being appended when not (directly) referenced - python

Okay so this is just a rough bit of code I made when trying to make a Guess Who(TM) for class challenge and I wanted to make a random character generator function (its only a proof of concept and I would expand it complexity later! Please don't judge!). However the character's template feature list seems to be appended every iteration (and so skewing my other loops) when it aught not to. It should be adding an item to the end of each new generated list - not the template. Yet the template variable is not appended to in the code, only a temporary copy is/should be. Here's the code:
tempfeatures = characters = []
for i in range(len(characternames)):
tempfeatures = []
charactername = characternames[random.randint(0,len(characternames)-1)]
characternames.remove(charactername)
a = features
tempfeatures = a
### "Debug bit" ###
print(features)
print("loooooop")
for y in range(len(features)):
print(len(features))
temp = random.randint(0,1)
if temp == 1:
tempfeatures[y][1] = True
else:
tempfeatures[y][1] = False
tempfeatures.append(["Dead",True])
characters.append([charactername,tempfeatures])
print(characters)
Thank you!

Apparently the tempfeature variable is "call by reference" and not "call by value". - thanks python.
So when duplicating lists, one must use this on the end of the variable name
tempfeature = feature[:]
(the [:] bit)
Thanks all for your comments!

This is called a shallow copy, it just referenciates the list to another variable, as seen here:
https://docs.python.org/2/library/copy.html
You need to make and intependent copy, or a deep copy, as: tempfeature = list(feature) so changing tempfeature won't interfere with feature

Related

Add an element to a list past the end of the list in python

Is there a pythonic way to add to a list at a known index that is past the end of the list? I cannot use append, as I'm looking add at an index that is more than 1 past the end. (For example, I want to put a value at x[6] when len(x) == 3).
I have a code that performs actions for sequential steps, and each step has a set of inputs. The users create an input file with these inputs. I store those inputs as a dictionary for each step, then a list of dictionaries to keep the order of the steps. I had just been reading the inputs for each step, then appending the dictionary to the list. I want to harden the code against the steps being out of order in the input files. If the user puts step 6 before step 3, I can't just append. I do not know the total number of steps until after the file has been read. I have a method worked out, but it seems clunky and involves multiple copies.
My kludgy attempt. In this case InputSpam and CurrentStep would actually be read from the user file
import copy
AllInputs = []
InputSpam = {'Key',999}
for i in xrange(0,3):
AllInputs.append(InputSpam.copy())
CurrentStep = 7
if CurrentStep - 1 == len(AllInputs):
AllInputs.append(InputSpam.copy())
elif CurrentStep - 1 < len(AllInputs):
AllInputs[CurrentStep-1] = InputSpam.copy()
elif CurrentStep - 1 > len(AllInputs):
Spam = [{}]*CurrentStep
Spam [:len(AllInputs)] = copy.deepcopy(AllInputs)
AllInputs = copy.deepcopy(Spam)
AllInputs[CurrentStep-1] = InputSpam.copy()
del Spam
Only after I wrote the answer I notice you use pyhton 2. Python 2 is unsupported for a long time now. You should switch to python 3. (The following solution is only valid for python 3.)
You can use collections.UserList to crate your own variation of a list like this:
from collections import UserList
class GappedList(UserList):
PAD_VALUE = object() # You may use None instead
def __setitem__(self, index, value):
self.data.extend(self.PAD_VALUE for _ in range(len(self.data), index+1))
self.data[index] = value
Inheriting from the UserList makes the whole structure to mostly behave like a regular list, unless specified otherwise. The data attribute gives access to "raw" underlying list. Only thing we need to redefine here is __setitem__ method which cares to assignments like my_list[idx] = val. We redefine in to firstly fill in a gap inbetween the end of the current list and the index you want to write in. (Actually it fills the list including the index you want to write to and then re-writes to value -- it makes the code a bit simpler).
You might need to redefine alse __getitem__ method if you want to handle access to index in the gaps somewhat differently.
Usage:
my_list = GappedList([0,1,2])
my_list.append(3)
my_list[6] = 6
my_list.append(7)
my_list[5] = 5
print(my_list)
# output:
[0, 1, 2, 3, <object object at 0x7f42cbd5ec80>, 5, 6, 7]

Checking for change in dictionaries

I am using python 3.6, In the program I am writing is comparing a set of dictionaries for any difference. if found it updates a reference dictionary and clears the data.
On first start up it works and registers the first change but everyone after that it does not, and just displays the information but does not identify that it has changed. It acts as Πython is linking the two dictionaries together. Is there anything else Ι can do?
def Check_Data():
global Ref_Readings
print('Ref_Readings')
print(Ref_Readings)
print('Data')
print(Data)
a=Ref_Readings
b=Data
if (a != b):
print('**************Updated Data')
del Ref_Readings[:]
Ref_Readings = Data
#print(Ref_Readings)#
Store_Readings()
else:
print('checking Settings')
del Data[:]
print(Data)
Ref_Readings = Data => a = b
Python uses references. If you want to have two different dictionaries you must do a copy.
import copy
Ref_Readings = copy.deepcopy(Data)
list_a = list_b makes "memory pointer match". You have to use copy library.
Add to begin:
import copy from copy
Change:
Ref_Readings = copy(Data)
you can also remove
a=Ref_Readings
b=Data
and change:
if (Data != Ref_readings):

Re-initialising a list

I have a list of dictionaries that is initialised by a call to a function with:
new = {'device_id':name,'device_mac':mac, 'device_ttl':ttl}
dev[0] = new
Thereafter, new entries are appended with:
dev.append(new)
Each dictionary has a time to live (TTL). Once that is reached the dictionary is removed:
for i in dev:
if (i['device_ttl'] == 0):
dev.remove(i)
This all seems fine until the list is completely empty. If I then try and add a new entry with:
dev[0] = new
again, I get a 'list index out of range' error.
I've tried changing the original initialisation with an append to an empty list, but that bombs out immediately with a KeyError: device_id.
The entire function that adds entries is:
# Adds a new device to the list of known devices.
def add_device(dev, num, name, mac, ttl):
new = {'device_id':name,'device_mac':mac, 'device_ttl':ttl}
if (num == 0):
#dev.append(new)
#dev = new
dev[0] = new
else:
dev.append(new)
return (num + 1)
The essential part of the main routine is:
devices = [{}] # Empty list.
num_devices = 0
# Code that determines whether to add to the list or not
num_devices = add_device(devices, num_devices,\
name_long, mac_address, ttl_n)
I don't understand why initialising by appending to an empty list is problematic, nor why what does work to initialise, doesn't work when the list is empty. It is created as empty in the first place!
Is there a better way to initialise or append to an empty list?
The answer was to not declare an empty list of dictionaries ,but just an empty list. A number of respondents pointed out the error but did not elucidate an answer.
Declaring an empty list of dictionaries with:
devices=[{}]
Creates an empty list with an empty dictionary. Assigning the first dictionary with:
dev[0] = new
just replaced the empty dictionary. Hence why the same assignment doesn't work when the list is emptied.
The correct initialisation was to just declare:
devices = []
Adding any dictionary after that, including the first one, is by using an append in the function:
dev.append(new)
Thanks for all of the pointers. I found the answer by switching IDE from Atom to Idle for testing. I have to use Atom as it is the only IDE with the PyCom plugin. Idle flagged the error almost immediately.

Python references to references in python

I have a function that takes given initial conditions for a set of variables and puts the result into another global variable. For example, let's say two of these variables is x and y. Note that x and y must be global variables (because it is too messy/inconvenient to be passing large amounts of references between many functions).
x = 1
y = 2
def myFunction():
global x,y,solution
print(x)
< some code that evaluates using a while loop >
solution = <the result from many iterations of the while loop>
I want to see how the result changes given a change in the initial condition of x and y (and other variables). For flexibility and scalability, I want to do something like this:
varSet = {'genericName0':x, 'genericName1':y} # Dict contains all variables that I wish to alter initial conditions for
R = list(range(10))
for r in R:
varSet['genericName0'] = r #This doesn't work the way I want...
myFunction()
Such that the 'print' line in 'myFunction' outputs the values 0,1,2,...,9 on successive calls.
So basically I'm asking how do you map a key to a value, where the value isn't a standard data type (like an int) but is instead a reference to another value? And having done that, how do you reference that value?
If it's not possible to do it the way I intend: What is the best way to change the value of any given variable by changing the name (of the variable that you wish to set) only?
I'm using Python 3.4, so would prefer a solution that works for Python 3.
EDIT: Fixed up minor syntax problems.
EDIT2: I think maybe a clearer way to ask my question is this:
Consider that you have two dictionaries, one which contains round objects and the other contains fruit. Members of one dictionary can also belong to the other (apples are fruit and round). Now consider that you have the key 'apple' in both dictionaries, and the value refers to the number of apples. When updating the number of apples in one set, you want this number to also transfer to the round objects dictionary, under the key 'apple' without manually updating the dictionary yourself. What's the most pythonic way to handle this?
Instead of making x and y global variables with a separate dictionary to refer to them, make the dictionary directly contain "x" and "y" as keys.
varSet = {'x': 1, 'y': 2}
Then, in your code, whenever you want to refer to these parameters, use varSet['x'] and varSet['y']. When you want to update them use varSet['x'] = newValue and so on. This way the dictionary will always be "up to date" and you don't need to store references to anything.
we are going to take an example of fruits as given in your 2nd edit:
def set_round_val(fruit_dict,round_dict):
fruit_set = set(fruit_dict)
round_set = set(round_dict)
common_set = fruit_set.intersection(round_set) # get common key
for key in common_set:
round_dict[key] = fruit_dict[key] # set modified value in round_dict
return round_dict
fruit_dict = {'apple':34,'orange':30,'mango':20}
round_dict = {'bamboo':10,'apple':34,'orange':20} # values can even be same as fruit_dict
for r in range(1,10):
fruit_set['apple'] = r
round_dict = set_round_val(fruit_dict,round_dict)
print round_dict
Hope this helps.
From what I've gathered from the responses from #BrenBarn and #ebarr, this is the best way to go about the problem (and directly answer EDIT2).
Create a class which encapsulates the common variable:
class Count:
__init__(self,value):
self.value = value
Create the instance of that class:
import Count
no_of_apples = Count.Count(1)
no_of_tennis_balls = Count.Count(5)
no_of_bananas = Count.Count(7)
Create dictionaries with the common variable in both of them:
round = {'tennis_ball':no_of_tennis_balls,'apple':no_of_apples}
fruit = {'banana':no_of_bananas,'apple':no_of_apples}
print(round['apple'].value) #prints 1
fruit['apple'].value = 2
print(round['apple'].value) #prints 2

Python - efficient way to create 20 variables?

I need to create 20 variables in Python. That variables are all needed, they should initially be empty strings and the empty strings will later be replaced with other strings. I cann not create the variables as needed when they are needed because I also have some if/else statements that need to check whether the variables are still empty or already equal to other strings.
Instead of writing
variable_a = ''
variable_b = ''
....
I thought at something like
list = ['a', 'b']
for item in list:
exec("'variable_'+item+' = '''")
This code does not lead to an error, but still is does not do what I would expect - the variables are not created with the names "variable_1" and so on.
Where is my mistake?
Thanks, Woodpicker
Where is my mistake?
There are possibly three mistakes. The first is that 'variable_' + 'a' obviously isn't equal to 'variable_1'. The second is the quoting in the argument to exec. Do
for x in list:
exec("variable_%s = ''" % x)
to get variable_a etc.
The third mistake is that you're not using a list or dict for this. Just do
variable = dict((x, '') for x in list)
then get the contents of "variable" a with variable['a']. Don't fight the language. Use it.
I have the same question as others (of not using a list or hash), but if you need , you can try this:
for i in xrange(1,20):
locals()['variable_%s' %i] = ''
Im assuming you would just need this in the local scope. Refer to the manual for more information on locals
never used it, but something like this may work:
liste = ['a', 'b']
for item in liste:
locals()[item] = ''

Categories