one function used to change variable in another function - python-3.x

# making a basic calendar
#list of months and their days
month_day = [[1,'January',31],[2,'February',28],
[3,'March',31],[4,'April',30],
[5,'May',31],[6,'June',30],
[7,'July',31],[8,'August',31],
[9,'September',30],[10,'October',31],
[11,'November',30],[12,'December',31]]
#checksum for new year
def isleapyear(year):
if year%4 == 0:
if year%100 == 0:
if year%400 == 0:
month_day[1][2] = 29
else:
month_day[1][2] = 28
else :
month_day[1][2] = 29
else:
month_day[1][2] = 28
#editable date (supposed to be
def Date():
year = 1
day = 31
month = 1
isleapyear(year)
date = [day, month_day[month-1][1], year]
return date
#function to increase day counter by 1
def new_day():
#checksum for month or year rollover
if Date.day == month_day[Date.month-1][2]:
Date.day = 1
if Date.month == 12:
Date.month = 1
Date.year = Date.year + 1
else:
Date.month = month + 1
else:
Date.day = Date.day + 1
new_day()
print (Date())
I am trying to teach myself python, so I have made a project a few smaller projects working together and one of them is a Date tracker. The Date function works. however when i try to call the new day function to bump the day by 1 and change month and year if needed, i get an error "AttributeError: 'function' object has no attribute 'day'". I understand that inside a function is a separate local variable not a global and that your not supposed to make global variables constantly changing. So I'm trying to get one function to call and use anothers variable I plan on making it into a button that changes the day by 1 or 7, I'm just having trouble visualizing how to get the function working. Any direction or help with getting this to work would be greatly appreciated
Thank you all in advance!

Firstly, you can't get variables from function.
One way you can deal with it is in function Date add line global year, day, month, this will make variables year, day, month global so you can use it in all function and outside of functions. And in new_day remove Date..
This should get rid of your problem.
Date.day would only work if Date was class not function.
For example:
class Date:
def __init__(self):
self.year = 1
self.day = 31
self.month = 1
Date().year # Should return 1
Date().day # Should return 31
Date().month # Should return 1

Related

fill out missing values for dates

I can pull average currency exchange (EUR->PLN) here: https://api.nbp.pl/api/exchangerates/rates/a/eur/2022-12-01/2022-12-31/?format=json
in the 'rates' field I have values :
"rates":[{"no":"232/A/NBP/2022","effectiveDate":"2022-12-01","mid":4.6892},{"no":"233/A/NBP/2022","effectiveDate":"2022-12-02","mid":4.6850},{"no":"234/A/NBP/2022","effectiveDate":"2022-12-05","mid":4.6898},{"no":"235/A/NBP/2022","effectiveDate":"2022-12-06","mid":4.6995},{"no":"236/A/NBP/2022","effectiveDate":"2022-12-07","mid":4.6968},{"no":"237/A/NBP/2022","effectiveDate":"2022-12-08","mid":4.6976},{"no":"238/A/NBP/2022","effectiveDate":"2022-12-09","mid":4.6821},{"no":"239/A/NBP/2022","effectiveDate":"2022-12-12","mid":4.6912},{"no":"240/A/NBP/2022","effectiveDate":"2022-12-13","mid":4.6945},{"no":"241/A/NBP/2022","effectiveDate":"2022-12-14","mid":4.6886},{"no":"242/A/NBP/2022","effectiveDate":"2022-12-15","mid":4.6843},{"no":"243/A/NBP/2022","effectiveDate":"2022-12-16","mid":4.6934},{"no":"244/A/NBP/2022","effectiveDate":"2022-12-19","mid":4.6886},{"no":"245/A/NBP/2022","effectiveDate":"2022-12-20","mid":4.6804},{"no":"246/A/NBP/2022","effectiveDate":"2022-12-21","mid":4.6648},{"no":"247/A/NBP/2022","effectiveDate":"2022-12-22","mid":4.6551},{"no":"248/A/NBP/2022","effectiveDate":"2022-12-23","mid":4.6364},{"no":"249/A/NBP/2022","effectiveDate":"2022-12-27","mid":4.6558},{"no":"250/A/NBP/2022","effectiveDate":"2022-12-28","mid":4.6938},{"no":"251/A/NBP/2022","effectiveDate":"2022-12-29","mid":4.6969},{"no":"252/A/NBP/2022","effectiveDate":"2022-12-30","mid":4.6899}]
But I don't have values for all days of the month - for example 2022-12-03, 2022-12-04 etc.
What I would like to achieve is assign last known value ("mid"), so for example for 2022-12-03 it should be 'mid' value from 2022-12-02, for 2022-12-04 it should also be value from 2022-12-02
This is a piece of code I have to convert abouve response to dictionary: date->mid:
exchange_rates = {}
response = requests.get("https://api.nbp.pl/api/exchangerates/rates/a/eur/2022-12-01/2022-12-31/?format=json")
rates = response.json()['rates']
for i in range(len(rates)):
exchange_rates[rates[i]['effectiveDate']]=rates[i]['mid']
I have no idea how the algorithm should look like... Any hint is much appreciated.
We can use a for loop:
exchange_rates = {}
response = requests.get("https://api.nbp.pl/api/exchangerates/rates/a/eur/2022-12-01/2022-12-31/?format=json")
rates = response.json()['rates']
for i in range(len(rates)):
exchange_rates[rates[i]['effectiveDate']]=rates[i]['mid']
# since 2022-12-01 has a rate, we can use it as the initial value
prev_rate = exchange_rates['2022-12-01']
# use a for loop to go from 2022-12-02 to 2022-12-31
for i in range(2, 32):
date = '2022-12-' + str(i).zfill(2)
if date in exchange_rates:
prev_rate = exchange_rates[date]
else:
exchange_rates[date] = prev_rate

Python function to perform calculation among each group of data frame

I need to have a function which performs below mentioned action ;
The dataset is :
and output expected is value in 'Difference' column , where remaining are input column.
Please note that within each group we first need to identify the maximum 'Closing_time' and the corrosponding amount will be the maximum value for that period , and then each row value will be subtracted from maximum detected value of previous period and result would be difference for that cell.
Also in case if the record do not have previous period then max value will be NA and difference caculation would be NA for all record for that period,
Adding points - within in each group (Cost_centre, Account, Year, Month) - Closing_time values are like ( D-0 00 CST is min and D-0 18 CST is maximim , similary within D-0,D+1, D+3 etc - D+3 will be maximum)
I tried to find first if previous value exist for each of the group or not and then find maximum time within each period and then crrosponding amount value to it.
Further using the maximum value , tried to subtract record Amount from Maximum value ,
but not getting how to implement , kindly help.
post sharing the above question i came up for this solution.
I splitted this in 3 part -
a) First find previous year and month for each of cost_center and account
b) Find maximum Closing_time within each group of cost_cente,account, year and month. Then pick corrosponding Amount value as amount .
c) using amount coming from b , subtract current amount with b to get diffrence.
def prevPeriod(df):
period =[]
for i in range(df.shape[0]):
if df['Month'][i]==1:
val_year = df['Year'][i]-1
val_month = 12
new_val =(val_year,val_month)
period.append(new_val)
else:
val_year = df['Year'][i]
val_month = df['Month'][i]-1
new_val =(val_year,val_month)
period.append(new_val)
print(period)
df['Previous_period'] = period
return df
def max_closing_time(group_list):
group_list = [item.replace('CST','') for item in group_list]
group_list = [item.replace('D','') for item in group_list]
group_list = [item.split()[:len(item)] for item in group_list]
l3 =[]
l4 =[]
for item in group_list:
l3.append(item[0])
l4.append(item[1])
l3 =[int(item) for item in l3]
l4 = [int(item) for item in l4]
max_datevalue = max(l3)
max_datevalue_index = l3.index(max(l3))
max_time_value = max(l4[max_datevalue_index:])
maximum_period = 'D+'+str(max_datevalue)+' '+str(max_time_value)+' '+'CST'
return maximum_period
def calculate_difference(df):
diff =[]
for i in range(df.shape[0]):
prev_year =df['Previous_period'][i][0]
print('prev_year is',prev_year)
prev_month = df['Previous_period'][i][1]
print('prev_month is', prev_month)
max_closing_time = df[(df['Year']==prev_year)& (df['Month']==prev_month)]['Max_Closing_time']
print('max_closing_time is', max_closing_time)
#max_amount_consider = df[(df['Year']==prev_year)& (df['Month']==prev_month) &(df['Max_Closing_time']==max_closing_time)]['Amount']
if bool(max_closing_time.empty):
found_diff = np.nan
diff.append(found_diff)
else:
max_closing_time_value = list(df[(df['Year']==prev_year)& (df['Month']==prev_month)]['Max_Closing_time'])[0]
max_amount_consider = df[(df['Cost_centre']==df['Cost_centre'][i])&(df['Account']==df['Account'][i])&(df['Year']==prev_year) & (df['Month']==prev_month) &(df['Closing_time']==str(max_closing_time_value))]['Amount']
print('max_amount_consider is',max_amount_consider)
found_diff = int(max_amount_consider) - df['Amount'][i]
diff.append(found_diff)
df['Variance'] = diff
return df
def calculate_variance(df):
'''
Input data frame is coming as query used above to fetch data
'''
try:
df = prevPeriod(df)
except:
print('Error occured in prevPeriod function')
# prerequisite for max_time_period
df2 = pd.DataFrame(df.groupby(['Cost_centre','Account','Year','Month'])['Closing_time'].apply(max_closing_time).reset_index())
df = pd.merge(df,df2, on =['Cost_centre','Account','Year','Month'])
# final calculation
try:
final_result = calculate_difference(df)
except:
print('Error in calculate_difference')
return final_result

Running python scripts repeatedly using the datetime module

I would like to execute a portion of script once daily for about 7 days. I used the datetime module in getting the current date, the timedelta module in calculating the runtime of the program, and the localtime() in specifying a particular time the code is to run daily. The first time I executed it, the balance doesn't add up automically. I think it keeps reassigning the balance variable.
Here is a portion of my code.
balance = 0
percentage = 5
deposit = 0
profit = 0
active = True
while active:
if current_date < expiring_date:
balance = deposit + percentage
current_date = current_date + timedelta(hours=24)
if time.localtime().tm_hr == 2:
balance += percentage
else:
active = False
Then, I modified the code by using conditionals to check if the initial balance is 0, to prevent the reassign ing. Currently the code executes at once, which is not what I want. I want it to run daily, and for each run, it should add the percentage to the current balance till the codition evaluates to False. I also want to keep a track of balance, and return the new balance at the end of each day. Is there a better way of doing it without keeping the loop running for days,and consuming power.
while active:
if current_date < expiring_date:
if balance <= 0:
balance = deposit + percentage
current_date = current_date + timedelta(hours=24)
else:
if time.localtime().tm_hr == 2:
balance += percentage
current_date = current_date + timedelta(hours=24)
else:
active = False

Output formate for calendar in Python 3.6

I would like to format the output in terms of calendar format. I have tried with print statement, but could not achieve as I expected because rows and column is not aligned properly.Could anyone help me to format and align the output? Here I have shared my entire code which is written in Python 3.6. the same question I have asked before but could not get any reply. but this code is little better than my previous code.
import calendar
import datetime
tamil_day = ('Monday','Tuesday','Wednesday','Thusday','Friday','Saturday','Sunday')
tamil_month = ('Chithirai','Vaikasi','Aani','Aadi','Aavani','Puratasi','Ipasi','Karthikai','Maargali','Thai','Masi','Panguni')
'''SAKA year Each month starting day in AD year 1st position for common year and 0th position for leap year'''
saka_month_starting_day_in_ad = (21,22,21,22,22,23,23,23,23,22,22,21,20)
'''equal month in AD year for SAKA month starting'''
ad_month = (3,3,4,5,6,7,8,9,10,11,12,1,2)
''' number of days in each month in SAKA year. add one ine more day each month for calculation'''
no_days_in_saka_month = (31,30,31,31,31,31,31,30,30,30,30,30,30)
def saka_month(saka_year,month):
ad_year = saka_year+78
saka_month = []
temp = 0
if month == 1 and calendar.isleap(ad_year):
first_day = datetime.date(ad_year,ad_month[month],saka_month_starting_day_in_ad[month-1]).weekday()
else:
first_day = datetime.date(ad_year,ad_month[month],saka_month_starting_day_in_ad[month]).weekday()
while first_day != temp:
saka_month.append(str(' '))
temp+=1
for day in range(1,(no_days_in_saka_month[month]+1)):
saka_month.append(str(day))
if day == no_days_in_saka_month[month] and calendar.isleap(ad_year):
saka_month.append(str(day+1))
for i in range(0,42,7):
print(*saka_month[i:i+7],sep=' ',end='\n')
print('\n')
def saka_year_print(saka_year):
for month in range(0,12):
print('{:*^80}'.format(tamil_month[month]))
print('\n')
print(*tamil_day,sep=' ')
print('\n','\n','\n')
saka_month(saka_year,month)
i have found the solution to my problem. just add str.center() for every list element. in my code at line no.47,50 and 52 you can add the center() function so that we can get aligned matrix kind of calendar in month view.
thank you

suggest a better way to handle exception in case

I am doing an assignment for class where we turn military time into standard time and thought I would be clever to have separate functions for getting input and checking the input -- my reasoning being that if the check_input function failed I could keep looping through the get_inputs function until the user entered it in the correct format.
However, when I enter jibberish like "jklfd" my get_input function crashes because it can't turn it into a list which is part of the function.
Is there a better way to handle exceptions in this case? Also any general tips or advice is always appreciated. Thanks in advance for your help!
__author__ = 'Ethan'
#This program takes input in military time in the format hour:minutes and outputs
#the time in standard time hour:minute AM/PM
def main():
print_intro()
while True:
mil_h, m = get_inputs()
if check_input(mil_h,m):
break
reformat_time(mil_h,m)
def print_intro():
print("This program takes input as military time from user")
print("in format hour:minute ex. 23:34")
print("and outputs the time in standard AM/PM format")
print("ex. from above 11:34 PM")
def get_inputs():
raw = input("Enter time: ")
time_list = raw.split(":")
mil_h = int(time_list[0])
m = int(time_list[1])
return mil_h, m
def check_input(mil_h,m):
try:
if mil_h >= 24 or mil_h <0:
print("Time must be in format hh:mm")
print("Hour must be in range 0 to 23")
return False
elif m >= 60 or m <0:
print("Time must be in format hh:mm")
print("Minute must be in range 0 to 59")
return False
else:
return True
except:
print("Input must be in military time in format hh:mm")
def reformat_time(mil_h,m):
am_pm = "AM"
if mil_h == 12:
am_pm = "PM"
stand_h = 12
elif mil_h > 12:
am_pm = "PM"
stand_h = mil_h % 12
else:
stand_h = mil_h
print(stand_h,':', m,' ', am_pm, sep='')
main()
Before splitting the string use an if statement,
if(raw.contains(":")&& raw.length()>=3 && raw) {
list=raw.split(":")
//rest of code
} else { throw exception}
The code for the exception should be edited to look like this:
except:
println("Code must be in military format")
get_inputs()
//recall the check_input method for the values found in get_inputs
check_input()
This way you know that raw is in the right format, you may want to add more prerequisites for raw (like making sure it only contains numbers), so that the program won't crash with unwanted input. (Sorry for the syntax, I don't know python explicitly)

Resources