Functions not using variables from functions above them - python

I have a program where I have defined a function called historyA()
def historyA(self, name, price, category, sub, comment):
sh = login("Budget")
worksheet = sh.get_worksheet(0)
emptyrowresize()
date = getDate()
toAppend = [date, name, category, sub, price, comment]
worksheet.append_row(toAppend)
In this function it is giving the variable worksheet values.
Immediately after that it runs the function emptyrowresize()
def emptyrowresize():
print("\n")
count = 0
cycle = 0
empty = False
for i in range(emptyrowcount()):
for i in range(worksheet.col_count):
if(lastvalue(i+1) == ""):
count += 1
if(count >= worksheet.col_count):
empty = True
if(empty == True):
worksheet.resize(worksheet.row_count-1,worksheet.col_count)
print("Fixing empty row at {0}..." .format(worksheet.row_count+1))
break
emptyrowresize() calls the functions lastvalue() in it
def lastvalue(x, y=0):
cycles = 0
#returns last value in col x with vertical offset y
while(True):
count = worksheet.row_count
val = worksheet.cell(int(count-y), x).value
cycles += 1
if(val == ''):
y = cycles
else:
break
return val
and last value needs the worksheet that was named in historyA() but it keeps giving the error that worksheet is not a defined global variable.
Why is this not working? I have had a problem with this once before but I don't remember how I fixed it without making a separate function for each of the three worksheets I need to work with.
EDIT: I feel like it is worth mentioning that everything passed historyA() is in a separate file that I am importing. I'm not sure if that means anything.

Related

function within f-string is returning the function outside the string, and returning None inside the string

I'm new to python and trying to do an f-string as follows:
next_patient = East_Room.get_highest_priority()
print(f"The next patient is {next_patient.display_symptoms()} please")
Where East_Room is an instance of a Class and get_highest_priority is a method within the class to display a patient with the highest integer for the 'severity' attribute as follows:
def get_highest_priority(self):
tmp_priority_patient = None
current_size = self.SLL_waiting_list.size()
counter = 1
while counter <= current_size:
tmp_node = self.SLL_waiting_list.get_node(counter)
tmp_patient = tmp_node.get_obj()
if tmp_priority_patient == None:
tmp_priority_patient = tmp_patient
else:
if tmp_patient.severity > tmp_priority_patient.severity:
tmp_priority_patient = tmp_patient
counter = counter + 1
return tmp_priority_patient
def display_symptoms(self):
print(f"{self.firstname} {self.lastname}:{self.symptoms}")
This is the output:
Conor : Naseau
The next patient is None please
I know that this method works as it works perfectly if I call it without the f-string. thanks for you help!
display_symptoms only prints information but doesn't return anything.
In Python, function that don't return anything return None, hence the output you got: "The next patient is None please"
If you also want the function to return this string, you have to explicitly return it:
def display_symptoms(self):
print(f"{self.firstname} {self.lastname}: {self.symptoms}")
return f"{self.firstname} {self.lastname}: {self.symptoms}"
An even better way to do it would be to make it a property:
#property
def display_symptoms(self):
return f"{self.firstname} {self.lastname}: {self.symptoms}"

Python function not picking updated list values

I have two functions, updates_list updates values to the list altered_source_tables while the other picks the values in that list. The issue is, even though the first function updates the list, the second function use_list still has the list as empty.
altered_source_tables = []
table_name = 'table_1'
def updates_list(table_name, **kwargs):
# CODE
for e in job.errors:
fullstring = e['message']
substring = "No such field"
if search(substring, fullstring):
altered_source_tables.append(table_name)
print("altered_source_tables list ", altered_source_tables) # output from fn call: altered_source_tables = ['table_1']
else:
print('ERROR: {}'.format(e['message']))
def use_list(**kwargs):
print("altered_source_tables list ", altered_source_tables) # output from fn call: altered_source_tables = []
if len(altered_source_tables) > 0:
# Loop through all altered tables
for table_name in altered_source_tables:
# CODE
What I'm I missing?

How to convert recursion to iteration when need to process nested lists?

I have a function on Python get_object_by_id, that restores object by its id, calling different functions depending on the type of the object:
def get_object_by_id(object_id: int) -> tp.Union[int, float, tuple, list, str, bool]:
"""
Restores object by id.
:param object_id: Object Id.
:return: An object that corresponds to object_id.
"""
info = struct.unpack("LL", ctypes.string_at(object_id, 16))
if info[1] == id(int):
return get_int_by_id(object_id)
elif info[1] == id(float):
return get_float_by_id(object_id)
elif info[1] == id(bool):
return get_bool_by_id(object_id)
elif info[1] == id(str):
return get_str_by_id(object_id)
elif info[1] == id(list):
return get_list_by_id(object_id)
elif info[1] == id(tuple):
return get_tuple_by_id(object_id)
else:
return None
My function get_list_by_id restores lists recursively:
def get_list_by_id(object_id: int) -> list:
info = struct.unpack("5L", ctypes.string_at(object_id, 40))
size_of_list = str(info[2]) + 'L'
elements_ides = struct.unpack(size_of_list, ctypes.string_at(info[3], 8 * info[2]))
res_list = []
for i in range(info[2]):
res_list.append(get_object_by_id(elements_ides[i]))
return res_list
It works well if nested lists are not very deep, but exceeds maximum recursion depth otherwise. I'm new to Python, and I struggle to understand, how can I rewrite this function without recursion and not make it looking monstrous.
Well, I didn't test it, so I don't know if it really works, but hopefully it makes the point: if the system stack won't do it, make your own stack.
def get_list_by_id(object_id: int) -> list:
stack_im_working_on = [] # maybe dqueue is faster?
# records are [info, elements_ides, 2=res_list, 3=i]
def push_new_list(object_id: int) -> list:
info = struct.unpack("5L", ctypes.string_at(object_id, 40))
size_of_list = str(info[2]) + 'L'
elements_ides = struct.unpack(size_of_list, ctypes.string_at(info[3], 8 * info[2]))
res_list = []
nonlocal stack_im_working_on
stack_im_working_on.append([info, elements_ides, res_list, 0])
push_new_list(object_id) # start from working on this
while True: # work from top of the stack
info, elements_ides, res_list, i = stack_im_working_on[-1]
while i < info[2]:
if info[1] == id(list): # The recursive call does not happen
push_new_list(elements_ides[i]) # Now we work on this
break # go to while stack_im_working_on
else:
res_list.append(get_object_by_id(elements_ides[i]))
# res_list is shared with the stack frame, but i is not.
stack_im_working_on[-1][3] = i = i + 1 # save that progress
else: # else for while... run when it gets to the end, until NOT i < info[2](and not on break)
# we finished this stack frame, so return the answer
stack_im_working_on.pop() # removes last element (that we just finished)
if stack_im_working_on:
# return to prev stack frame (not done yet)
stack_im_working_on[-1][2].append(res_list)
else:
# return to caller
return res_list
# Not Reached, as the only pop() checks for empty above
I hear that people don't like the "else" at the end of a loop, but it really is useful. (I always put a comment on it)
On the other hand, if your stack really won't ever be that huge, and you can predict a max size... just increase the system stack size limit. (it looks alot easier)
https://stackoverflow.com/questions/3323001/what-is-the-maximum-recursion-depth-in-python-and-how-to-increase-it
import sys
sys.setrecursionlimit(1500)

How do I print all of the instances from a set of variables that are undefined from the beginning?

I have a program that I want to be able to print all of the instances of each variable using my method that I created. Problem is I can't figure out a way to print them since each are listed under a different variable that aren't configured from hardcoding them in and I need a way to automatically recall them in my code.
class fit:
def __init__(self,day,did,workout='Not Recorded',time='An unknown amount of',calories='An unknown amount of'):
self.day = day
self.did = did
if did.lower()=='no':
self.workout = 'Not Recorded'
self.time = "An unknown amount of Minutes"
self.calories = "An unknown amount of Calories"
else:
self.workout = workout
self.time = "{} Minutes".format(time)
self.calories = "{} Calories".format(calories)
def formate(self):
self.formate = "{}:\n\nDid you work out: {}\nWorkout focus: {}\nYou worked out for: {}\nYou burned: {}\n\n----------------------------------------------------------".format(self.day,self.did,self.workout,self.time,self.calories)
return self.formate
def reader(day,index):
file = open('readme.txt')
file = file.read()
stripped = file.rsplit("\n")
for i in range(len(stripped)):
stripped[i] = stripped[i].rsplit(" ")
del stripped[-1]
if int(index) >= len(stripped[day-1]):
return "none"
else:
return stripped[day-1][index]
x = 0
def create_new_instance(class_name,instance_name):
globals()[instance_name] = class_name(reader(x,0),reader(x,1),reader(x,2),reader(x,3),reader(x,4))
print('Class instance {} created'.format(instance_name))
while True:
try:
x+=1
ins = 'day_' + str(x)
create_new_instance(fit,ins)
except:
break
break
def printer(instance):
print(.formate())
while True:
x+=1
inst = 'day_' + str(x)
printer(inst)
An example of this might be that I have 8 lines of data from a text document and I have a system that creates instances of day_1, day_2, day_3 ect until day_8 and then I want to print each of those instances out, but again I don't have those instances directly hardcoded into my code so I don't know how I'd do it. I've tried looking into maybe a while loop and increasing a variable by 1 and concatenating it with day and trying to make a variable out of that but the my limited experience with python isn't helping.
A very unpythonic and ugly way would be to use exec, for example:
day_3=5
x = 'day_'+'3'
exec("print("+x+")")
I would recommend another way to store your variables though.

How to deal with large csv file in python?

I have CSV file that contains a data of 40k rows.
My each function open csv file and works with it and then close it.
Is there a way that I can open the file once and then close it and I can work with it whenever I want? I tried to put each field in a separate list and work whit it whenever I call it or in dictionary but both methods works good up to 1k row if more then it takes long time to processes it, I found a way to speed up by filtering them, but not sure how to apply it.
sample of my codes.
files=open("myfile.csv","r")
def spec_total():
total = 0.0
files.readline() # skip first row
for line in files:
field=line.strip().split(",") #make Into fields
tall=float(field[0])
if tall >= 9.956:
total +=tall
print("The sum is: %0.5f" % (total))
spec_total()
files.close()
other function
files=open("3124749c.csv","r")
def code():
match= 0
files.readline() # skip first row
for row in files:
field=row.strip().split(",") #make Into fields
code=(field[4])
import re
if re.search(r'\[[A-Za-z][0-9]+\][0-9]+[A-Za-z]{2}[0-9]+#[0-9]+', code) is None:
match += 1
print("The answer that do not match code is :",match)
code()
files.close()
and there is plenty more functions that opens each time the csv file and split them into field in order to recognise which field I am referring to.
If I understand correctly try:
import csv
total = 0.0
for row in csv.reader(open("myfile.csv")):
tall = float(row[0])
if tall >= 9.956:
total += tall
print("The sum is: %0.5f" % total)
More complex version - create calculation classes for processing each row.
class Calc(object):
def process(self,row):
pass
def value(self):
pass
class SumColumn(Calc):
def __init__(self, column=0,tall=9.956):
self.column = column
self.total = 0
def process(self, row):
tall = float(row[0])
if tall >= self.tall:
self.total += tall
def value(self):
return self.total
class ColumnAdder(Calc):
def __init__(self, col1, col2):
self.total = 0
self.col1 = col1
self.col2 = col2
def process(self, row):
self.total += (row[self.col1] + row[self.col2])
def value(self):
return self.total
class ColumnMatcher(Calc):
def __init__(self, col=4):
self.matches = 0
def process(self, row):
code = row[4]
import re
if re.search(r'\[[A-Za-z][0-9]+\][0-9]+[A-Za-z]{2}[0-9]+#[0-9]+', code) is None:
self.match += 1
def value(self):
return self.matches
import csv
col0_sum = SumColumn()
col3_sum = SumColumn(3, 2.45)
col5_6_add = ColumnAdder(5,6)
col4_matches = ColumnMatcher()
for row in csv.reader(open("myfile.csv")):
col0_sum.process(row)
col3_sum.process(row)
col5_6_add.process(row)
col4_matches.process(row)
print col0_sum.value()
print col3_sum.value()
print col5_6_add.value()
print col4_matches.value()
This code was typed into SO, which was a tedious affair - so bare with on syntax etc.
For illustration purposes only - not to be taken too literally.
All is object in Python: that means functions too.
So there is no need to define special classes to craft functions as instances of these classes as sotapme does, since every function we define is already an object in the sense of 'instance of a class'.
Now, if someone needs to create several functions of the same type, for example each of them adds all the values of a precise CSV file's column, that's right that it's interesting to create these many functions by a repeating process.
At this point, raises the question: using function factory or class ?
Personnaly, I prefer the function factory way because it is less verbose.
I also discovered in the Theran's answer HERE that it's also faster.
In the following code, I use a trick with globals() to give a particular name to each function created by means of a function factory. Some will say it's bad, but I don't know why. If there's another way to do the same , I will be happy to learn it.
In the code, 3 functions are build by a function factory, and I let one defined by plain normal definition (op3).
Python is fantastic!
import csv
import re
# To create a CSV file
with open('Data.csv','wb') as csvhandle:
hw = csv.writer(csvhandle)
hw.writerows( ((2,10,'%%',3000,'-statusOK-'),
(5,3,'##',500,'-modo OOOOKKK-'),
(1,60,'**',700,'-- anarada-')) )
del hw
# To visualize the content of the CSV file
with open(r'Data.csv','rb') as f:
print "The CSV file at start :\n "+\
'\n '.join(map(repr,csv.reader(f)))
def run_funcs_on_CSVfile(FUNCS,CSV):
with open(CSV,'rb') as csvhandle:
for f in FUNCS:
# this is necessary for functions not created via
# via a function factory but via plain definition
# that defines only the attribute col of the function
if 'field' not in f.__dict__:
f.field = f.col - 1
# columns are numbered 1,2,3,4,...
# fields are numbered 0,1,2,3,...
for row in csv.reader(csvhandle):
for f in FUNCS:
f(row[f.field])
def SumColumn(name,col,start=0):
def g(s):
g.kept += int(s)
g.kept = start
g.field = col -1
g.func_name = name
globals()[name] = g
def MultColumn(name,col,start=1):
def g(s):
g.kept *= int(s)
g.kept = start
g.field = col - 1
g.func_name = name
globals()[name] = g
def ColumnMatcher(name,col,pat,start = 0):
RE = re.compile(pat)
def g(s,regx = RE):
if regx.search(s):
g.kept += 1
g.kept = start
g.field = col - 1
g.func_name = name
globals()[name] = g
SumColumn('op1',1)
MultColumn('op2',2)
ColumnMatcher('op4',5,'O+K')
def op3(s):
s = int(s)
if s%2:
op3.kept += (2*s)
else:
op3.kept += s
op3.kept = 0
op3.col = 4
print '\nbefore:\n ' +\
'\n '.join('%s.kept == %d'
% (f.func_name, f.kept)
for f in (op1,op2,op3,op4) )
# The treatment is done here
run_funcs_on_CSVfile((op2,op3,op4,op1),r'Data.csv')
# note that the order of the functions in the tuple
# passed as argument can be any either one or another
print '\nafter:\n ' +\
'\n '.join('%s(column %d) in %s.kept == %d'
% (f.func_name, f.field+1, f.func_name, f.kept)
for f in (op1,op2,op3,op4) )
.
result
.
The CSV file at start :
['2', '10', '%%', '3000', '-statusOK-']
['5', '3', '##', '500', '-modo OOOOKKK-']
['1', '60', '**', '700', '-- anarada-']
before:
op1.kept == 0
op2.kept == 1
op3.kept == 0
op4.kept == 0
after:
op1(column 1) in op1.kept == 8
op2(column 2) in op2.kept == 1800
op3(column 4) in op3.kept == 4200
op4(column 5) in op4.kept == 2

Categories

Resources