本書籍の特徴はタイトルの通り様々な側面から悪いサンプル(Harmful)をまず示した上でPythonicなサンプル(Idiomatic)を示して、どこが悪いかどこを直すべきかが分かりやすく解説されています。今回は4章「Control Structures and Functions」で参考になったTipsをメモしておこうと思います。
※ここで紹介してるのはごく一部なので興味あれば一度本書席をチェックしていただければと思います。
4.1 If Statement
4.1.2 Avoid repeating variable name in compound in statement
# Harmful
is_generic_name = False
name = 'Tom'
if name == 'Tom' or name == 'Dick' or name == 'Harry':
is_generic_name = True
# Idiomatic
name = 'Tom'
is_generic_name = name in ('Tom', 'Dick', 'Harry')
4.2 For Loops
4.2.3 Use else to execute code after a for loop concludes
# Harmful
for user in get_all_users():
has_malformed_email_address = False
print ('Checking {}'.format(user))
for email_address in user.get_all_email_addresses():
if email_is_malformed(email_address):
has_malformed_email_address = True
print (u'email addressが不正な形式です!')
break
if not has_malformed_email_address:
print ('All email address are valid!')
# Idiomatic
for user in get_all_users():
print ('Checking {}'.format(user))
for email_address in user.get_all_email_addresses():
if email_is_malformed(email_address):
print(u'email addressが不正な形式です!')
break
else:
print('All email address are valid')
4.3 Functions
4.3.2 Use *args and **kwargs to accept arbitrary arguments
# Harmful
def make_api_call(foo, bar, baz):
if baz in ('Unicorn', 'Oven', 'New York'):
return foo(bar)
else:
return bar(foo)
# I need to add another parameter to 'make_api_call'
# without breaking everyone's existing code.
# I have two options...
def so_many_options():
# I can tack on new parameters, but only if I make
# all of them optional ...
def make_api_call(foo, bar, baz, qux=None, foo_polarity=None,
baz_coefficient=None, quux_capacitor=None,
file_not_fould=None):
# ... and so on ad infinitum
return file_not_found
def version_graveyard():
# ... or I can create a new function each time the signature
# hanges.
def make_api_call_v2(foo, bar, baz, qux):
return make_api_call(foo, bar, baz) - qux
def make_api_call_v3(foo, bar, baz, qux, foo_polarity):
if foo_polarity != 'reserved':
return make_api_call_v2(foo, bar, baz, qux)
return None
def make_api_call_v4(foo, bar, baz, qux, foo_polarity,
baz_coefficient):
return make_api_call_v3(foo, bar, baz, qux, foo_polarity) * baz_coefficient
def make_api_call_v5(foo, bar, baz, qux, foo_polarity,
baz_coefficient, quux_capacitor):
# I don't need 'foo', 'bar', or 'baz' anymore, but I have to keep
# supporting them...
return baz_coefficient * quux_capacitor
# ...
# Idiomatic
def make_api_call(foo, bar, baz):
if baz in ('Unicorn', 'Oven', 'New York'):
return foo(bar)
else:
return bar(foo)
# I need to add another parameter to 'make_api_call'
# without breaking everyone's existing coe.
# Easy ...
def new_hotness():
def make_api_call(foo, bar, baz, *args, **kwargs):
# Now I can accept any type and number of arguments
# without worring about breaking existing code.
baz_coefficient = kwargs['the_baz']
# I can even forward my args to a different fucntion
# without knwoing their contents!
return baz_coefficient in new_functions(args)
4.4 Exceptions
4.4.2 Use Exceptions to Write Code in an "EAFP" Style
※EASP→Easier to Ask for Forgiveness than Permission( which assumes things will go well and catches exceptions if they don't.)
# Harmful
def get_log_level(config_dict):
if 'ENABLE_LOGGING' in config_dict:
if config_dict['ENABLE_LOGGING'] != True:
return None
elif not 'DEFAULT_LOG_LEVEL' in config_dict:
return None
else:
return None
# Idiomatic
def get_log_level(config_dict):
try:
if config_dict['ENABLE_LOGGING']:
return config_dict['DEFAULT_LOG_LEVEL']
except KeyError:
# if either value wasn't present,
# a KeyError will be raised, so return None
return None
4.4.3 Avoid "Swallowing(無条件で受け入れる)" Useful Exceptions With Bare Except Clauses
# Harmful
import requests
def get_json_response(url):
try:
r = requests.get(url)
return r.json()
except:
print('Oops, something went wrong!')
return None
# Idiomatic
import requests
def get_json_response(url):
return requests.get(url).json()
# If we need to make note of the exception, we
# would write the function this way ...
def alternate_get_json_response(url):
try:
r = requests.get(url)
return r.json()
except:
# do some logging here, but don't handle the exception ...
raise
0 件のコメント:
コメントを投稿