英文:
constantly having to re-type inputs each time function called inside other function
问题
# 定义一个全局变量来保存用户输入的变量
user_inputs = None
def print_intro():
print('This program returns an excel file in the users downloads')
print('that is the output of a special or cross+special')
def get_inputs():
global user_inputs # 使用全局变量
if user_inputs is None:
save_path = input('enter the file path of the folder that houses the excel file you want to work on, starting from C:, copy paste this ')
file = input('enter the name of the entire file path of the excel file followed by .xlsx: ')
abs_path = "C:\\Users\\mstevens\\python_test _Copy_for_pricing"
decision = input("enter 'y' for prod cross and special, else hit enter and a special only is assumed")
raw_key = input('enter the column name in the excel you want to join on. this needs to be exact')
user_inputs = (save_path, file, abs_path, decision, raw_key)
else:
save_path, file, abs_path, decision, raw_key = user_inputs
return save_path, file, abs_path, decision, raw_key
# 程序的其余部分保持不变
# ...
# ...
# 主函数
def kyle_special_pipeline():
print_intro()
save_path, file, abs_path, decision, raw_key = get_inputs()
write_into_excel(file)
print('the program has executed, check downloads folder.')
kyle_special_pipeline()
在这个修改后的程序中,我们使用了一个全局变量 user_inputs
来保存用户输入的变量。在 get_inputs
函数中,我们首先检查 user_inputs
是否已经被设置,如果已经设置,则直接使用它,否则才会要求用户输入。这样,用户只需要在程序运行的开始时输入一次,后续函数调用都会使用同样的输入值。
英文:
def print_intro():
print('This program returns an excel file in the users downloads')
print('that is the output of a special or cross+special')
def get_inputs():
save_path = input('enter the file path of the folder that houses the excel file you want to work on, starting from C:, copy paste this ')
file = input('enter the name of the entire file path of the excel file followed by .xlsx: ')
#abs_path = input('enter the path up until python sns')
abs_path = "C:\\Users\\mstevens\\python_test _Copy_for_pricing"
decision = input("enter 'y' for prod cross and special, else hit enter and a special only is assumed")
raw_key = input('enter the column name in the excel you want to join on. this needs to be exact')
return save_path,file,abs_path, decision,raw_key
# this function asks you whether to do prodcross+special or just special.
# also asks you to enter the EXACT join key string as it appears in the excel
def cross_or_not():
save_path,file,abs_path, decision,raw_key = get_inputs()
join_key = raw_key.lower()
if decision == 'y':
if 'cross' in join_key:
join_key = 'Clean Xrf Part No'
else:
decision == 'n'
if 'star' in join_key:
join_key = 'Newstar'
elif 'sku' in join_key:
join_key ='SKU'
elif 'tracking' in join_key:
join_key = 'Tracking No'
return decision,join_key,raw_key
# Data Load prod cross ref query and/or special query and convert it to a dataframe
def dataLoad():
decision,join_key,raw_key = cross_or_not()
join_key = 'SKU'
if decision =='y':
with utils.db.db_erp() as cnxn:
kyle_special = sqlQueries.to_df('kyle_special',cnxn)
with utils.db.db_erp() as cnxn:
cross = sqlQueries.to_df('prod_cross_ref',cnxn)
data = pd.merge(kyle_special,cross[['SKU','Clean Xrf Part No']],on= join_key,how='left')
else:
with utils.db.db_erp() as cnxn:
data = sqlQueries.to_df('kyle_special',cnxn)
return data
def add_special_cols():
special = dataLoad()
#converts decimal.decimal column datatypes to datatype float
special[['Avg. Cost w/ Tariff','Avg. Sell Prc.','Automann Prc.','Avg. Cost']]=special[['Avg. Cost w/ Tariff','Avg. Sell Prc.','Automann Prc.','Avg. Cost']].apply(pd.to_numeric, downcast='float')
special['Average Cost w/Tariff * 1.4'] = special['Avg. Cost w/ Tariff']*1.4
special['(Avg cost*1.4 - Avg. Cost w/ Tariff)/Avg cost*1.4'] = ((special['Avg. Cost']*1.4) - special['Avg. Cost w/ Tariff']) / (special['Avg. Cost']*1.4)
special['Avg. Sell Prc. *.99'] = special['Avg. Sell Prc.'] *.99
special['((Avg. Sell Prc. *.99) - Avg. Cost w/ Tariff) / Avg. Sell Prc. *.99'] = ((special['Avg. Sell Prc. *.99']) - special['Avg. Cost w/ Tariff']) / special['Avg. Sell Prc. *.99']
special['automann price *.99'] = special['Automann Prc.']*.99
special['((automann price *.99) - avg cost with tariff) / automann price *.99'] = (special['automann price *.99'] - special['Avg. Cost w/ Tariff']) / special['automann price *.99']
return special
# load file that needs to be crossed, convert it to a dataframe
def input_file(file):
try:
work_file = pd.read_excel(file)
except Exception as e:
print(str(e))
print('there was a problem reading your excel file')
return work_file
# clean the work file
def clean_work_file(file):
dirty_file = input_file(file)
decision,JoinKey,raw_key = cross_or_not()
dirty_file= dirty_file.rename(columns={raw_key: JoinKey})
if decision == 'y':
dirty_file = dirty_file.applymap(lambda x: str(x))
for i in range(len(dirty_file)):
dirty_file[JoinKey][i].replace(' ','')
dirty_file[JoinKey][i].replace('.','')
dirty_file[JoinKey][i].replace('-','')
dirty_file[JoinKey][i].replace('/','')
dirty_file[JoinKey][i].replace("'",'')
else:
dirty_file = dirty_file[JoinKey].str.strip()
clean_file = dirty_file
return clean_file
def workfile_join(file):
decision,JoinKey,raw_key = cross_or_not()
work_file = clean_work_file(file)
special = add_special_cols()
if decision == 'y':
work_file = pd.merge(work_file,special[['Clean Xrf Part No','SKU','Tracking Ln','Tracking No','Newstar','Description','Product Category','Product Sub-Category',
'Product Sub-Category 2','Tariff','Avg. Cost','Avg. Cost w/ Tariff',
'Std. Vendor Cost','Avg. Sell Prc.','Lowest Contract Prc.','SP1','Automann Prc.',
'Midwest Prc.','Average Cost w/Tariff * 1.4','(Avg cost*1.4 - Avg. Cost w/ Tariff)/Avg cost*1.4',
'Avg. Sell Prc. *.99','((Avg. Sell Prc. *.99) - Avg. Cost w/ Tariff) / Avg. Sell Prc. *.99',
'automann price *.99','((automann price *.99) - avg cost with tariff) / automann price *.99']],
on=JoinKey ,how='left')
else:
work_file = pd.merge(work_file,special[['SKU','Tracking Ln','Tracking No','Newstar','Description','Product Category','Product Sub-Category',
'Product Sub-Category 2','Tariff','Avg. Cost','Avg. Cost w/ Tariff',
'Std. Vendor Cost','Avg. Sell Prc.','Lowest Contract Prc.','SP1','Automann Prc.',
'Midwest Prc.','Average Cost w/Tariff * 1.4','(Avg cost*1.4 - Avg. Cost w/ Tariff)/Avg cost*1.4',
'Avg. Sell Prc. *.99','((Avg. Sell Prc. *.99) - Avg. Cost w/ Tariff) / Avg. Sell Prc. *.99',
'automann price *.99','((automann price *.99) - avg cost with tariff) / automann price *.99']],
on=JoinKey, how= 'left')
return work_file
def write_into_excel(file):
excel_doc = workfile_join(file)
excel_doc = excel_doc.to_excel(file[:-5]+'-'+'special.xlsx',engine='xlsxwriter')
def kyle_special_pipeline():
print_intro()
save_path,file,abs_path,decision,raw_key = get_inputs()
write_into_excel(file)
print('the program has executed, check downloads folder.')
kyle_special_pipeline()
Each time this program is run I have to resubmit the user input variables in the "get input" function. probably have to resubmit them each time the function is called in other functions. I thought if I defined them in the main function "kyle special pipeline" this would be avoided, apparently not. I just want to have to submit those inputs once for the program. any suggestions?
答案1
得分: 0
将一个一次性调用装饰器应用于你的 get_inputs
函数。
原始的 get_inputs
函数只会被调用一次。它的返回值将被记住,并且在后续的调用中返回。
实现非常简单:
def call_once(func):
"""一个确保只调用一次的装饰器。进一步的调用将返回初始值。"""
first_call = True
values = None
def wrapper(*args, **kwargs):
"""只执行包装的函数一次,并返回初始值。"""
nonlocal first_call, values
if first_call:
first_call = False
values = func(*args, **kwargs)
return values
return wrapper
@call_once
def get_inputs():
save_path = input('输入包含要处理的 Excel 文件的文件夹的文件路径,从 C: 开始,复制粘贴这个路径:')
file = input('输入 Excel 文件的完整文件路径的名称,后面加上 .xlsx:')
#abs_path = input('输入 Python sns 的路径:')
abs_path = "C:\\Users\\mstevens\\python_test _Copy_for_pricing"
decision = input("输入 'y' 以进行产品交叉和特殊处理,否则直接回车默认为特殊处理")
raw_key = input('输入要在 Excel 中加入的列名。这需要确切的名称:')
return save_path, file, abs_path, decision, raw_key
当装饰器首次应用于 get_inputs
时,first_call
标志被设置为 true。在每次调用时,它都会被检查,如果为 true,则调用实际的函数并保存其返回值,然后将标志设置为 false,最后返回该值。
first_call
和 values
被声明为 nonlocal
在 wrapper
函数内部。由于它们位于 wrapper
函数创建的闭包中,对它们值的更改会在函数调用之间持续存在。
你还可以使用 functools.cache
来实现相似的功能。
英文:
Apply a call-once decorator to your get_inputs
function.
The original get_inputs
will only be called once. Its return values will be remembered, and those values will be returned for subsequent calls.
The implementation is quite simple:
def call_once(func):
"""A decorator ensuring only 1 call. Further calls return initial value."""
first_call = True
values = None
def wrapper(*args, **kwargs):
"""Execute wrapped function only once and return initial value."""
nonlocal first_call, values
if first_call:
first_call = False
values = func(*args, **kwargs)
return values
return wrapper
@call_once
def get_inputs():
save_path = input('enter the file path of the folder that houses the excel file you want to work on, starting from C:, copy paste this ')
file = input('enter the name of the entire file path of the excel file followed by .xlsx: ')
#abs_path = input('enter the path up until python sns')
abs_path = "C:\\Users\\mstevens\\python_test _Copy_for_pricing"
decision = input("enter 'y' for prod cross and special, else hit enter and a special only is assumed")
raw_key = input('enter the column name in the excel you want to join on. this needs to be exact')
return save_path,file,abs_path, decision,raw_key
The first_call
flag is set to true when the decorator is first applied to get_inputs
. During each call, it is checked, and if it's true, the actual function is called and its return value is saved, the flag is set to false, and finally the value is returned.
first_call
and values
are declared as nonlocal
inside the wrapper
function. As they reside in the closure created by the wrapper
function, changes to their values persist across function calls.
You could also use functools.cache
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论