-
-
Save serhiitytarenko/1de02504e1f151ddb9bd2cb885bb5ca7 to your computer and use it in GitHub Desktop.
import re | |
import datetime | |
from collections import OrderedDict | |
def create_racer_abbreviations_dict(file_name): | |
"""Retrieves {'abbreviation': (name, team)}" format dict from abbreviations.txt""" | |
abbreviations_dict = {} | |
with open(file_name, 'r') as fn: | |
for line in fn: | |
matchObj = re.match(r'^(\w+)_([a-zA-Z\s]+)_([a-zA-Z\s]+)$', line) | |
# group(1) is abbreviation, i.e 'SVM' | |
abbreviations_dict[matchObj.group(1)] = ( | |
matchObj.group(2), # name of a pilot | |
matchObj.group(3).rstrip(), # team | |
) | |
return abbreviations_dict | |
# {'abbreviation of pilot': ('name of pilot, 'team')} | |
abbr_dict = create_racer_abbreviations_dict( | |
'abbreviations.txt') | |
# returns timing log from start.log or end.log in {'abbreviation': time} format | |
def retrieve_timings_from_log(file_name): | |
timing_log = {} | |
with open(file_name, 'r') as fn: | |
for line in fn: | |
# matches 2 groups: abbreviation of a racer and time | |
matchObj = re.match(r'^([A-Z]+).*(\d{2}:\d+:\d+\.\d+)$', line) | |
# converts time from a string to datetime object | |
lap_time = datetime.datetime.strptime( | |
matchObj.group(2).rstrip(), '%H:%M:%S.%f') | |
# adds key, value to a timing_log | |
timing_log[matchObj.group(1)] = lap_time | |
return timing_log | |
start_timings = retrieve_timings_from_log('start.log') | |
end_timings = retrieve_timings_from_log('end.log') | |
def sorted_individual_results(start_timings_, end_timings_, abbr_dict_, reverse_order=False): | |
""" | |
Receives start and end timings and returns an OrderedDict with | |
{abbreviations:timedeltas} | |
""" | |
# creating dict with best lap results | |
lap_results = {key: end_timings_[key] - start_timings_.get(key, 0) | |
for key in start_timings_.keys()} | |
sorted_results = dict( | |
sorted(lap_results.items(), key=lambda x: x[1], reverse=reverse_order)) | |
return sorted_results | |
sorted_lap_results = sorted_individual_results( | |
start_timings, end_timings, abbr_dict) | |
# prints result board to a console | |
def print_result_board(sorted_lap_results_): | |
counter = 1 | |
for key, value in sorted_lap_results_.items(): | |
racer_name = abbr_dict[key][0] | |
team_name = abbr_dict[key][1] | |
best_time = str(value)[2:-3] | |
print(("{: <3} {: <18} | {: <30} | {}".format( | |
str(counter)+'.', racer_name, team_name, best_time))) | |
if counter == 15: | |
print( | |
'----------------------------------------------------------------------') | |
counter += 1 | |
print_result_board(sorted_lap_results) |
Function declaration and invocation should be separated in order not to split business logic
Consider putting program logic into
if __name__ == '__main__':
sorted_individual_results
should be renamed into sort_individual_results
create_racer_abbreviations_dict
doc string shouldn't contain hardcoded file name
In condition if counter == 15:
'15' looks like a magic number, please consider moving it's value to some constant
Also consider indicating function variables' names types to make functions logic more clear
Active items to improve code
-
Imports have to be in alphabetical order
-
Functions definition follow imports
-
Main logic follows functions definition
-
Replase commets before function definition with docstring
-
Keep unified variable naming (PEP8 advises snake_case ) (bed matchObj, good match_obj)
-
Good practice: variable names avoid words (dict, list, obj, object, so far).
-
Hardcoded repetitive strings (like in 11, 31 lines) have to be declared as CONSTANTS.
Add typing for functions: it will help better understand functions and IDE will able to provide hints and code completion.
Use python conventions for variables names:
Naming Conventions
it is better not to use names like matchObj
It will be nice to keep all functions at the top and move all logic that declared out of functions to a separated function for example main()
.
Add if __name__ == '__main__':
statement to show the entry point of the script.
- Add
if __name__ == '__main__':
as entry point - Bad naming in
with open(file_name, 'r') as fn:
- Regex should be declared as constants.
- Bad naming in variable matchObj. Should be snake_case (match_obj).
- Should be in one line:
abbr_dict = create_racer_abbreviations_dict(
'abbreviations.txt')
sorted_lap_results = sorted_individual_results(
start_timings, end_timings, abbr_dict)
sorted_results = dict(
sorted(lap_results.items(), key=lambda x: x[1], reverse=reverse_order))
print(
'----------------------------------------------------------------------')
- In 67 line best practice is using f-string. Not .format() method.
sorted_lap_results_
bad naming - _ in the end of name- Developer don`t use type hints.
- Imports should be in alphabetical order.
- Developer use others styles for docstrings.
create_racer_abbreviations_dict
:
- Use snake-case code style for all the variables;
- Check if string was matched to regular expression before adding items to the dictionary;
retrieve_timings_from_log
:
- Same thing here as above
sorted_individual_results
:
- abbr_dict_ variable is not used inside the function, consider removing it from arguments or check function logic for errors;
- Consider renaming function to
sort_individual_results
;
Overall:
- Split function definitions from actual logic (first all needed functions, then main logic);
- Use
if __name__ == '__main__':
construct to execute main logic of the file; - Comments above the functions could be moved into docstrings;
- Make file paths with input data configurable and check their existence before making any operations with them;
- Use code-specific exceptions and add reactions to them (like if the exception is critical to workflow or not);
Consider renaming your variables in order to naming convention https://www.python.org/dev/peps/pep-0008/#function-and-variable-names