patternpythonMinor
Validate parameters within a range
Viewed 0 times
validaterangeparameterswithin
Problem
Function to use several blocks of
```
def rfc_3339_str(minutes = 0, year = 1999, month = 1, date = 1, secs = 0, time_zone = 0):
'''Takes minutes and builds RFC 3339 timeDate string.
yyyy-mm-ddTHH:MM:ss[.mmm][+/-HH:MM]. Does not support milliseconds.
All params optional. Timezone format is number in range
[-12:12] (hours only). All numbers expect integers.
Minutes > 1439 (23 hours 59 minutes) wrap around to zero,.
Date defaults to 1/1/1999. Supported years 1000-2035 CE. Date allows
range 0-31 inclusive for all months. Negative times are not supported.
Incorrect params return error description'''
plus = '+'
minus = '-'
date_time_split = 'T'
date_split = '-'
time_split = ':'
time_zone_mins = ':00'
MAX_MINUTES = 1440
yyyy = None
mm = None
dd = None
HH = None
MM = None
SS = None
zone_sign = plus
zz = None
#validate inputs
if 1000 > year > 2035:
return 'year_out_of_range'
else:
yyyy = str(year)
if month in range(1,10):
mm = '0' + str(month)
elif month in range(10,13):
mm = str(month)
else:
return 'month_out_of_range'
if date in range(1, 10):
dd = '0' + str(date)
elif date in range(10, 32):
dd = str(date)
else:
return 'date_out_of_range'
if minutes MAX_MINUTES:
minutes = minutes - MAX_MINUTES
hours_int = int(minutes / 60)
mins_int = int(minutes % 60)
if hours_int in range(0,10):
HH = '0' + str(hours_int)
elif
if:elif:else: that all take slightly different conditional statements. I'm trying to format integers into a 2 digit string, adding a leading 0 for single digits. It is working great, but there has to be DRY way of doing the same thing. Also, the timezone formatting is a bit of a mess. After struggling to come up with a more elegant solution, I just went with what was obvious and working.```
def rfc_3339_str(minutes = 0, year = 1999, month = 1, date = 1, secs = 0, time_zone = 0):
'''Takes minutes and builds RFC 3339 timeDate string.
yyyy-mm-ddTHH:MM:ss[.mmm][+/-HH:MM]. Does not support milliseconds.
All params optional. Timezone format is number in range
[-12:12] (hours only). All numbers expect integers.
Minutes > 1439 (23 hours 59 minutes) wrap around to zero,.
Date defaults to 1/1/1999. Supported years 1000-2035 CE. Date allows
range 0-31 inclusive for all months. Negative times are not supported.
Incorrect params return error description'''
plus = '+'
minus = '-'
date_time_split = 'T'
date_split = '-'
time_split = ':'
time_zone_mins = ':00'
MAX_MINUTES = 1440
yyyy = None
mm = None
dd = None
HH = None
MM = None
SS = None
zone_sign = plus
zz = None
#validate inputs
if 1000 > year > 2035:
return 'year_out_of_range'
else:
yyyy = str(year)
if month in range(1,10):
mm = '0' + str(month)
elif month in range(10,13):
mm = str(month)
else:
return 'month_out_of_range'
if date in range(1, 10):
dd = '0' + str(date)
elif date in range(10, 32):
dd = str(date)
else:
return 'date_out_of_range'
if minutes MAX_MINUTES:
minutes = minutes - MAX_MINUTES
hours_int = int(minutes / 60)
mins_int = int(minutes % 60)
if hours_int in range(0,10):
HH = '0' + str(hours_int)
elif
Solution
First off, I would like to point you to the time module which has functions that are similar to what you want to accomplish.
Now as for DRYing your code up a bit. You were right to notice that you have blocks of:
I don't agree with your
This is more readable, and more Pythonic.
Back to the code block, if we take each of the variant parts as arguments into a super function we get:
This is trying to emulate the functional programming style of Lisp, Scheme, Racket and etc, which something that is generally avoided in Python code due to the final unreadability of the code.
Let's think of something else, such as checking all the conditions ahead of time, before doing any processing. This speeds up execution for failed inputs (as any failing input would fail as fast as possible), and simplifies the logic.
This would look something like this:
and so on. This can also be done via assert statements of the unittest module for even more compact code.
Then afterwards you will have blocks of the form:
This is easily wrapped into a ternary operator:
Which will eliminate a lot of lines from your code.
Now as for DRYing your code up a bit. You were right to notice that you have blocks of:
if var in range1:
func1(var)
elif var in range2:
func2(var)
else:
return 'blah_out_of_range'I don't agree with your
else block code. You are returning an error statement, which should actually be an exception such as a ValueError like so:raise ValueError("blah out of range")This is more readable, and more Pythonic.
Back to the code block, if we take each of the variant parts as arguments into a super function we get:
def process(var, cond1, func1, cond2, final):
# ugly code hereThis is trying to emulate the functional programming style of Lisp, Scheme, Racket and etc, which something that is generally avoided in Python code due to the final unreadability of the code.
Let's think of something else, such as checking all the conditions ahead of time, before doing any processing. This speeds up execution for failed inputs (as any failing input would fail as fast as possible), and simplifies the logic.
This would look something like this:
if year not in range(1001, 2035):
raise ValueError("year not in range")
if month not in range(1, 13):
raise ValueError("month not in range")and so on. This can also be done via assert statements of the unittest module for even more compact code.
Then afterwards you will have blocks of the form:
if cond1:
func1
else:
func2This is easily wrapped into a ternary operator:
func1 if cond1 else func2Which will eliminate a lot of lines from your code.
Code Snippets
if var in range1:
func1(var)
elif var in range2:
func2(var)
else:
return 'blah_out_of_range'raise ValueError("blah out of range")def process(var, cond1, func1, cond2, final):
# ugly code hereif year not in range(1001, 2035):
raise ValueError("year not in range")
if month not in range(1, 13):
raise ValueError("month not in range")if cond1:
func1
else:
func2Context
StackExchange Code Review Q#60622, answer score: 4
Revisions (0)
No revisions yet.