Updating code to better structure in python - python-3.x

I have a code that calculates some stuff and has a lot of hardcoded values and duplicity, I just need help in arranging it in such a way It wouldn't look messy.
This is not my actual code but basic structure of my code
def my_code():
a = [func1(x),func2(x),func3(x)]
return a
def func1(x):
func1_x = #calculation using x formula
func1_dict = {}
func1["name"] = #some f1hardcoded name
func1["school"] = "some f1hardcoded value"
func1["school_address"] = "some f1hardcoded value"
func1["score_in_written"] = f" func1 student scored {func1_x} percentage "
func1["score_in_perc"] = func1_x
def func2(x):
func2_x = #some calculation using y formula
func2_dict = {}
func2["name"] = #some f2hardcoded name
func2["school"] = "some f2hardcoded value"
func2["school_address"] = "some f2hardcoded value"
func2["score_in_written"] = f" func1 student scored {func2_x} percentage "
func2["score_in_perc"] = func2_x
def func3(x):
func3_x = #some calculation using z formula
func3_dict = {}
func3["name"] = # f3 related some hardcoded name
func3["school"] = " f3 related some hardcoded value"
func3["school_address"] = " f3 related hardcoded value"
func3["score_in_written"] = f" func1 student scored {func3_x} percentage "
func3["score_in_perc"] = func3_x
Hardcoded values basically would not be changed for any x value in a particular function, only the score in percentage and score_in_written would change.
As I have many functions like this (till func9), is there any way I can change this into better code structure?
Is there any way I can make this code a little tidy and clean?

You can use a class to structure the repeated values like this:
class StudentAcademics:
def __init__(self, name, school, schoolAddress, score):
self.name = name
self.school = school
self.schoolAddress = schoolAddress
self.scoreInWritten = f" func1 student scored {score} percentage "
self.scoreInPercent = score
score = #calculation using x formula
student_academics_1 = StudentAcademics("John", "xyz school", "xyz address", score)
score = #calculation using y formula
student_academics_2 = StudentAcademics("Tom", "abc school", "abc address", score)
score = #calculation using z formula
student_academics_2 = StudentAcademics("Bill", "jkl school", "jkl address", score)
Now when you want to access the data again you can simply do:
print("name {} studied at {}".format(student_academics_1.name, student_academics_1.school))
Let me know if you have any questions further.

What you could be looking at is creating multiple classes with having a class for each subsection of similar operations. Then create the main class that combines all these classes. That way it looks clean and structured. Just read yourself into python classes and how to create objects.

Related

How do you implement a weighted sum transform primitive in Featuretools?

I'm trying to figure how to implement a weighted cum sum primitive for Featuretools. The weighting shall depend on time_since_last like
cum_sum (amount) = sum_{i} exp( -a_{i} ) * amount_{i}
where i are rolling 6 Month periods....
above you find the original question. after a while of try and error I came up with this code for my purpose:
using the data and initial setup for entity and relation from here
def weight_time_until(array, time):
diff = pd.DatetimeIndex(array) - time
s = np.floor(diff.days/365/0.5)
aWidth = 9
a = math.log(0.1) / ( -(aWidth -1) )
w = np.exp(-a*s)
return w
WeightTimeUntil = make_trans_primitive(function=weight_time_until,
input_types=[Datetime],
return_type=Numeric,
uses_calc_time=True,
description="Calc weight using time until the cutoff time",
name="weight_time_until")
features, feature_names = ft.dfs(entityset = es, target_entity = 'clients',
agg_primitives = ['sum'],
trans_primitives = [WeightTimeUntil, MultiplyNumeric])
when I does above I came close to the feature I want but at the end I did not get it right which I do not understand. So I got feature
SUM(loans.WEIGHT_TIME_UNTIL(loan_start))
but not
SUM(loans.loan_amount * loans.WEIGHT_TIME_UNTIL(loan_start))
What did I miss here???
I tried further....
My guess was a type miss match! but the "types" are the same. Anyway I tried the following:
1) es["loans"].convert_variable_type("loan_amount",ft.variable_types.Numeric)
2) loans["loan_amount_"] = loans["loan_amount"]*1.0
For (1) as well for (2) I get the more promising resulting feature:
loan_amount_ * WEIGHT_TIME_UNTIL(loan_start)
and also
loan_amount * WEIGHT_TIME_UNTIL(loan_start)
but only when I have the target value = loans instead of clients which actually was not my intention.
This primitive doesn't currently exist. However, you can create your own custom primitive to accomplish this calculation.
Here is an example calculating the rolling sum, which can be updated to do a weighted sum using the appropriate pandas or python method
from featuretools.primitives import TransformPrimitive
from featuretools.variable_types import Numeric
class RollingSum(TransformPrimitive):
"""Calculates the rolling sum.
Description:
Given a list of values, return the rolling sum.
"""
name = "rolling_sum"
input_types = [Numeric]
return_type = Numeric
uses_full_entity = True
def __init__(self, window=1, min_periods=None):
self.window = window
self.min_periods = min_periods
def get_function(self):
def rolling_sum(values):
"""method is passed a pandas series"""
return values.rolling(window=self.window, min_periods=self.min_periods).sum()
return rolling_sum

Extracting text embedded within <td> under some class

Table from data to be extractedExtract text within under specific class and store in respective lists
I am trying to extract data from "https://www.airlinequality.com/airline-reviews/vietjetair/page/1/" . I am able to extract the summary, review and user info, but unable to get the tabular data. Tabular data needs to be stored in respective lists. Different user reviews have different number of ratings. Given in the code below are couple of things which I tried. All are giving empty lists.
Extracted review using xpath
(review = driver.find_elements_by_xpath('//div[#class="tc_mobile"]//div[#class="text_content "]') )
following are some xpaths which are giving empty list. Here I m=am trying to extract data/text corresponding to "Type Of Traveller "
tot = driver.find_elements_by_xpath('//div[#class="tc_mobile active"]//div[#class="review-stats"]//table[#class="review-ratings"]//tbody//tr//td[#class="review-rating-header type_of_traveller "]//td[#class="review-value "]')
tot1 = driver.find_elements_by_xpath('//div[#class="tc_mobile"]//div[#class="review-stats"]//table//tbody//tr//td[#class="review-rating-header type_of_traveller "]//td[#class="review-value "]')
tot2 = driver.find_elements_by_xpath('//div//div/table//tbody//tr//td[#class="review-rating-header type_of_traveller "]//td[#class = "review-value "]')
This code should do what you want. All the code is doing at a basic level is following the DOM structure and then iterating over each element at that layer.
It extracts the values into a dictionary for each review and then appends that to a results list:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.airlinequality.com/airline-reviews/vietjetair/page/1/")
review_tables = driver.find_elements_by_xpath('//div[#class="tc_mobile"]//table[#class="review-ratings"]//tbody') # Gets all the review tables
results = list() # A list of all rating results
for review_table in review_tables:
review_rows = review_table.find_elements_by_xpath('./tr') # Gets each row from the table
rating = dict() # Holds the rating result
for row in review_rows:
review_elements = row.find_elements_by_xpath('./td') # Gets each element from the row
if review_elements[1].text == '12345': # Logic to extract star rating as int
rating[review_elements[0].text] = len(review_elements[1].find_elements_by_xpath('./span[#class="star fill"]'))
else:
rating[review_elements[0].text] = review_elements[1].text
results.append(rating) # Add rating to results list
Sample entry of review data in results list:
{
"Date Flown": "January 2019",
"Value For Money": 2,
"Cabin Staff Service": 3,
"Route": "Ho Chi Minh City to Bangkok",
"Type Of Traveller": "Business",
"Recommended": "no",
"Seat Comfort": 3,
"Cabin Flown": "Economy Class",
"Ground Service": 1
}

How do I store the value of an indexed list in a global variable and call at it through a formatted function?

How do I store the value of an index and then use that value in a formatted exec function to print me the second results of each list under class Animal(): Dog list, which is what I expect to print. A simplified version of the essence of my problem along with further clarification below:
class Global():
str_list = []
current_word = ""
adj_word = 'poofy'
adj_int = 0
size = 0
pounds = 0
dog_years = 0
class Animal():
##### Formatted like so:[[visual size],[pounds],[age in dog years],[almost dead]] #####
dog = [['small', 'poofy'],[7, 45],[18, 101],[0, 1]]
input = 'dog'
def done():
print(Global.adj_int)
print(str(Global.size), str(Global.pounds), str(Global.dog_years))
def split_str():
Global.str_list = input.split()
split_str()
def analyze():
Global.current_word = Global.str_list.pop(0)
exec(f"""if Global.adj_word in Animal.{Global.current_word}[0]:
Global.adj_int = Animal.{Global.current_word}[0].index('{Global.adj_word}')
Global.size = Animal.{Global.current_word}[1][{Global.adj_int}]
Global.pounds = Animal.{Global.current_word}[2][{Global.adj_int}]
Global.dog_years = Animal.{Global.current_word}[3][{Global.adj_int}]""")
if len(Global.str_list) == 0:
done()
analyze()
it returns:
1
7 18 0
When I expect it to return "45 101 1" for size, pounds, dog_years because I am storing the .index value of 'poofy' for Animal.dog list in Global.adj_int. which in this case is '1'. Then I try to format the code so it uses that value to print the second values of each list but for some reason it will not print the expected results(under def analyze():... exec(f""".... Does anyone have an answer to this question?? This is a much more simple version of what I originally have but produces the exact same result. when I try to use the formatted code it acts as if adj_int = 0 when really it's adj_int = 1 (and I know it is stored as 1 like it should be because I print adj_int at the end to check) or I am not able to format the code in this way? But I need a work around regardless.
The problem is that the string argument to exec is being evaluated before it is executed. So, when you are calling exec this is what is called:
exec(f"""if Global.adj_word in Animal.dog[0]:
Global.adj_int = Animal.{dog}[0].index('poofy')
Global.size = Animal.dog[1][0]
Global.pounds = Animal.dog[2][0]
Global.dog_years = Animal.dog[3][0]""")
And after this, Global.adj_int becomes 1. The control flow and the structure of your code is incredibly complex comparing to its simplicity so I would carefully rethink its design, but for a quick fix, you probably want to first execute the part that sets the adj_int and then the rest, like this:
exec(f"""if Global.adj_word in Animal.{Global.current_word}[0]:
Global.adj_int = Animal.{Global.current_word}[0].index('{Global.adj_word}'"""))
exec(f"""if Global.adj_word in Animal.{Global.current_word}[0]:
Global.size = Animal.{Global.current_word}[1][{Global.adj_int}]
Global.pounds = Animal.{Global.current_word}[2][{Global.adj_int}]
Global.dog_years = Animal.{Global.current_word}[3][{Global.adj_int}]""")
Even after stating that your program is unnecessarily complex, let me additionally point out that using a global, mutable state is a really really bad practice, which makes your programs hard to follow, maintain & debug. The same concern relates to using exec.

Using dictionaries to create a variable as a variable name

I've been researching this for a while, and have seen some questions similar to mine, but I don't quite understand / think they're what I'm looking for. I'm trying to do something like this:
def run():
cost = input("enter cost")
size = input("enter size")
print("For color, 1 = red, 2 = blue, 3 = green, enter one")
color = input("enter color")
shoe1 = [cost, size, color]
repeat = input("Do you want to order another shoe? Y/N")
if repeat == "Y" or repeat == "y":
run()
But then, save shoe1 so that it isn't redefined when we re-run the function, and that a new list is defined, maybe shoe2 (Or any variable name). So that at the end we can list all the shoes, and specifications of the shoes that were ordered. Other questions said that a dictionary should be used for this, how might I do that?.All help appreciated, thanks a bunch!

How do I add a "noHigherStocks" function when there are no higher stocks in a list?

I am attempting to create a program that has 4 functions, getStocks, searchStocks, printStocks, and then the main function that uses the other three.
My issue is that I want to make it so that if the stock you searched for is the highest stock, I want the message "There are no higher stocks" to appear as the output instead of empty space, but I am unsure what and where I would need to add to do that. I have the "noHigherStocks" variable as the message I want displayed, but where am I to implement it? I feel as though I should use an else statement in the main function, but I can't think of where it would make sense to put it. Thanks for reading! any help or tips would be greatly appreciated :-)
def getStocks():
stockNames = []
stockPrices = []
name = str(input("What is the name of the stock?"))
price = int(input("what is the price of that stock?"))
while name != 'done':
stockNames.append(name)
stockPrices.append(price)
name = str(input("What is the name of the stock?"))
if name != 'done':
price = int(input("what is the price of that stock?"))
return (stockNames, stockPrices)
# returns a single value pertaining to the found price
def searchStocks(stockNames, stockPrices, s):
for i in range (len(stockNames)):
if stockNames[i] == s:
return stockPrices[i]
return -1
# print the names of stocks whose price is higher than p.
def printStock(stockNames, stockPrices, p):
i = 0
while i <len(stockPrices):
if p < stockPrices[i]:
print(stockNames[i])
i = i + 1
return
def main():
n,p = getStocks()
stock = str(input("what stock are you searching for?"))
price = searchStocks(n,p,stock)
printStock(n,p,price)
noStocksHigher = str('There are no stocks higher than',stock)
main()
This might be solved using the max() builtin. Since you already know the price of the stock for which you searched, you could just compare that price against the highest price in p, and if equal, print your message, otherwise search the list.
Starting where you call searchStocks:
price = searchStocks(n,p,stock)
if max(p) == price:
print('There are no stocks higher than',stock)
else:
printStock(n,p,price)
This should do the trick.

Resources