Pass large data structure in Python - python

In C++, it's good practice to pass references to large data structures to avoid the overhead of copying the whole thing by value. Python works very differently, though, and I'm wondering how best to pass a large data structure.
Here's the simple version. Is this what I should use, or is there something better?
foo(hugeArray):
# Change values in hugeArray
return hugeArray
hugeArray = foo(hugeArray)
Solution (Kudos to jonrsharpe!)
foo(hugeArray)
hugeArray[0] = "New!"
myArray[0] = "Old."
foo(myArray)
print myArray[0] # Prints "New!"
The function changes the original array, so there's no need to assign the return value to the original to change it.

No need to copy stuff
def foo(array):
array[0] = 3 # do stuff to the array in place
huge_array = [1, 2, 3]
foo(huge_array) # returns None
print(huge_array) # [3, 2, 3]

Python will do this for you, unless you explicitly copy it or modify.
foo(hugeArray):
# Change values in hugeArray
return hugeArray
hugeArray2 = foo(hugeArray)
print("Was Python Clever? - ", hugeArray2 is hugeArray)
Note that if you want to re-assign hugeArray without making a copy, you can use slicing. so
hugeArray[:] = hugeNewArray
Instead of
hugeArray = hugeNewArray

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]

Python: how to pass an object/variable trhough a function and change it directly inside of the function?

In C language I was used to doing this by passing address of variables (pass by reference), but in Python, despite having already read about some alternatives, I have no ideia how can I do to pass a Google Sheet (worksheet) to a function that must change and save it online, using gspread library.
Here is my code:
def ordenar(self, list):
sheet = len(list.worksheets())
for i in range(sheet):
lista = list.get_worksheet(i).row_values(1)
lista.sort()
size = len(lista)
if size > 1:
cell_list = list.get_worksheet(i).range(1, size)
j = 0
for cell in cell_list:
cell.value = lista[j]
j = j+1
# Update in batch
list.get_worksheet(i).update_cells(cell_list)
Now the part of the main code that uses the function:
#Teste de ordenação
Jose.vocabulario.ordenar(Jose.vocabulario.artigo)
First off, don't use list as a parameter name, since it shadows Python's built-in list function.
You can change an object in a function simply by... modifying it somehow. Of course, the object has to be mutable. Ex:
mylist = [1, 2, 3]
print(mylist) # output: [1, 2, 3]
def append_five(list_to_modify):
list_to_modify.append(5)
append_five(mylist)
print(mylist) # output: [1, 2, 3, 5]
What I suspect is happening in your case is that, at some point, the Google Sheets worksheet needs to be saved in order to the resulting file reflect the changes in your code. I don't know much about Google Sheets API and you didn't mention the module you are using to work with them, but that's how you'd do it in openpyxl, a Python module for working with Excel spreadsheets.
I've solved it.
The error was in the worksheet.range() function: worksheet.range(start line, start column, final line, final column).

The equivalent of Python getattr, but for index or key

If a complex container A contains some element xyz, which can be accessed by key or by index (similar to lists or dictionaries):
xyz = A[somekey]
xyz = A[someindex]
how would I access the element, given a string? Basically I'd like the equivalent of:
method_of_a = getattr(A, 'method_of_a') # gets A.method_of_a
prop_of_a = getattr(A, 'prop_of_a') # gets A.prop_of_a
but I don't know of anything like:
element_by_key = getitem(A, 'somekey')# get A['somekey']
element_by_index = getitem(A,'2')# get A[2]
The reason I want that, is that I should copy a property or an element.
The problem is that I can only access the base containers, and a string representation of where to look. A more realistic exaple would be:
# copy A.some.weird.path[0].including['Keys']
# to B.some.weird.path[0].including['Keys']
prop = magic_get_function(A, "some.weird.path[0].including['Keys']")
magic_set_function(B, "some.weird.path[0].including['Keys']", prop)
I'd very much like to not resort to eval, as eval is evil (or rather it's vulnerable).
If there's no other way than eval, how would you go at it?

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):

It's possibile to use set function on a object basing only one attribute?

I'm creating this type of object:
class start_url_mod ():
link = ""
id = 0
data = ""
I'm creating a list of this object and I want to know if there is some way in order to delete one of then if I find same link attribute.
I know the function set() for the deleting of duplicates in a "sample" list, but there is something very fast and computational acceptable?
Use a dict key-ed on the attribute. You can preserve order with collections.OrderedDict:
from collections import OrderedDict
# Keep the last copy with a given link
kept_last = OrderedDict((x.link, x) for x in nonuniquelist).values()
# Keep the first copy with a given link (still preserving input order)
kept_first = list(reversed(OrderedDict((x.link, x) for x in reversed(nonuniquelist)).viewvalues()))
If order is not important, plain dict via dict comprehensions is significantly faster in Python 2.7 (because OrderedDict is implemented in Python, not C, and because dict comprehensions are optimized more than constructor calls; in Python 3.5 it's implemented in C):
# Keep the last copy with a given link but order not preserved in result
kept_last = {x.link: x for x in nonuniquelist}.values()
# Keep the first copy with a given link but order not preserved in result
kept_first = {x.link: x for x in reversed(nonuniquelist)}.values()
You can use a dictionary with the attribute that you're interested in being the key ...

Categories