はじめに
堀川淳一郎先生のHoudiniチュートリアル「Spectrum Visualizer」を英語字幕化してみました。最近TouchDesignerやHoudiniベースのVJ映像にも興味を持ち始めたので。ネイティブライクですが日本人の英語ということで何となく聞き取りやすい気がします。約35分ある動画でHoudiniでのMIDIデータ制御の基礎を抑えるにはもってこいの内容で英語字幕化してみました。良ければご活用ください。
# Harmful
book_info = ' The Three Musketeers: Alexandre Dumas'
formatted_book_info = book_info.strip()
formatted_book_info = formatted_book_info.upper()
formatted_book_info = formatted_book_info.replace(':', ' by')
# Idiomatic
book_info = ' The Three Musketeers: Alexandre Dumas'
formatted_book_info = book_info.strip().upper().replace(':', ' by')
# Harmful
result_list = ['True', 'False', 'File not found']
result_string = ''
for result in result_list:
result_string += result
# Idiomatic
result_list = ['True', 'False', 'File not found']
result_string = ''.join(result_list)
# Harmful
def get_formatted_user_info_worst(user):
return 'Name: ' + user.name + 'Age: ' + str(user.age) + ', Sex: ' + user.sex
def get_formatted_user_info_slightly_better(user):
return 'Name: %s. Age: %i, Sex: %c' % (user.name, user.age, user.sex)
# Idiomatic
def get_formatted_user_info(user):
output = 'Name: {user.name}, Age: {user.age}, Sex: {user.sex}'.format(user=user)
return output
# Harmful
some_other = list()
some_list = list()
for element in some_other_list:
if is_prime(element):
some_list.append(element + 5)
# Idiomatic
some_other_list = range(10)
some_list = [element + 5
for element in some_other_list
if is_prime(element)]
# Harmful
# Pythonはswitch-case文がないので以下のようにしがちだが...
def apply_operation(left_operand, right_operand, operator):
if operator == '+':
return left_operand + right_operand
elif operator == '-':
return left_operand - right_operand
elif operator == '*':
return left_operand * right_operand
elif operator == '/':
return left_operand / right_operand
# Idiomatic
def apply_operation(left_operand, right_operand, operator):
import operator as op
operator_mapper = {'+': op.add, '-': op.sub, '*': op.mul, '/': op.truediv}
return operator_mapper[operator](left_operand, right_operand)
# Harmful
log_severity = None
if 'severity' in configuration:
log_severity = configuration['severity']
else:
log_severity = 'Info'
# Idiomatic
log_severity = configuration.get('severity', 'Info')
# Harmful
user_email = {}
for user in user_list:
if user.email:
user_email[user.name] = user.email
# Idiomatic
user_email = {user.name: user.email for user in user_list if user.email}
# Harmful
users_first_names = set()
for user in users:
users_first_names.add(user.first_name)
# Idiomatic
users_first_names = {user.first_name for user in users}
# Harmful
def print_employee_information(db_connection):
db_cursor = db_connection.cursor()
results = db_cursor.execute('select * from employees').fetchall()
# 基本的にこの手法だと情報取得して出力は不可能
for row in results:
print(row[1] + ', ' + row[0] + ' was hired on' \
+ row[5] + ' (for $' + row[4] + ' per annum) info the' \
+ row[2] + ' department and reports to ' + row[3])
# Idiomatic
# 'employees'テーブルは次のカラムを持ってるのを前提とする
# first_name, last_name, department, manager, salary, hire_date
employee_row = namedtuple('EmployeeRow', \
['first_name', 'last_name', 'department', 'manager', 'salary', 'hire_date'])
EMPLOYEE_INFO_STRING = '{last}, {first} was hired on {date} \
${sarlary} per annum) info the {department} department and reports to ager}'
def print_employee_information(db_connection):
db_cursor = db_connection.cursor()
results = db_cursor.execute('select * from employees').fetchall()
for row in results:
employee = employee_row._make(row)
# これでも間違った場所では出力はほとんど不可能ではある
print(EMPLOYEE_INFO_STRING.format(\
last=employee.last_name,\
first=employee.first_name,\
date=employee.hire_date,\
salary=employee.salary,\
department=employee.department,\
manager=employee.manager))
# Harmful
(name, age, temp, temp2) = get_user_info(user)
# temp, temp2が使われていない
if age > 21:
output = '{name} can drink!'.format(name=name)
# Idiomatic
(name, age, _, _) = get_user_info(user)
if age > 21:
output = '{name} can drink!'.format(name=name)
# Harmful
list_from_comma_separated_value_file = ['dog', 'Fido', 10]
animal = list_from_comma_separated_value_file[0]
name = list_from_comma_separated_value_file[1]
age = list_from_comma_separated_value_file[2]
output = ('{name} the {animal} is {age} years old'.format(animal=animal, name=name, age=age))
# Idiomatic
list_from_comma_separated_value_file = ['dog', 'Fido', 10]
(animal, name, age) = list_comma_separated_value_file
output = ('{name} the {animal} is {age} years old'.format(animal=animal, name=name, age=age))
# Harmful
from collections import Counter
STATS_FORMAT = """Statistics:
Mean: {mean}
Median: {median}
Mode: {mode}"""
def calculate_mean(value_list):
return float(sum(value_list) / len(value_list))
def calculate_median(value_list):
return value_list(int(len(value_list) / 2)]
def calculate_mode(value_list):
return Counter(value_list).most_common(1)[0][0]
values = [10, 20, 20, 30]
mean = calculate_mean(values)
median = calculate_median(values)
mode = calculate_median(values)
print(STATS_FORMAT.format(mean=mean, median=median, mode=mode))
# Idiomatic
from collections import Counter
STATS_FORMAT = """Statistics:
Mean: {mean}
Median: {median}
Mode: {mode}"""
def calculate_stastics(value_list):
mean = float(sum(value_list) / len(value_list))
median = value_list[int(len(value_list) / 2)]
mode = Counter(value_list).most_common[1)[0][0]
return (mean, median, mode)
(mean, median, mode) = calculate_stastics([10, 20, 20. 30])
print(STATS_FORMAT.format(mean=mean, median=median, mode=mode))
# Harmful
class Product():
def __init__(self, name, price):
self.name = name
self.price = price
# Idiomatic
class Product():
def __init__(self, name, price):
self.name
self._price = price
@property
def price(self):
return self._price * TAX_RATE
@price.setter
def price(self, value):
# "setter"関数はpropertyと同名である必要がある
self._price = value
# Harmful
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
print(p)
# 出力結果:'<__main__.Point object at 0x91ebd0>'
# Idiomatic
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return '{0}, {1}'.format(self.x, self.y)
p = Point(1, 2)
print(p)
# 出力結果:'1, 2'
# Harmful
# 例外発生したときにOpenしたファイルをCloseする術がない
file_handle = open(path_to_file, 'r')
for line in file_handle.readlines():
if raise_excepton(line):
print('No! An Excepton!')
# Idiomatic
# context manager経由で開くと__enter__, __exit__メソッドを定義する事で容易に処理ができる
with open(path_to_file, 'r') as file_handle:
for line in file_handle:
if raise_excepton(line):
print('No! An Exception!')
# Harmful
# list comprehensionは直ちに全要素を敷き詰めたリストを生成する
# 膨大なリストの場合、非常に多くのメモリを食う事になる
for uppercase_name in [name.upper() for name in get_all_usernames()]:
process_normalized_username(uppercase_name)
# Idiomatic
# 一方、generator expressionの場合、要求に応じた要素が都度生成される
for uppercase_name in (name_upper() for name in get_all_usernames()):
process_normalized_username(uppercase_name)
# Harmful
def get_twitter_stream_for_keyword(keyword):
imaginary_twitter_api = ImaginaryTwitterAPI()
if imaginary_twitter_api.can_get_stream_data(keyword):
return imaginary_twitter_api.get_stream(keyword)
current_stream = get_twitter_stream_for_keyword('#jeffknupp')
for tweet in current_stream:
process_tweet(tweet)
def get_list_of_incredibly_complex_calculation_results(data):
return [first_incredibly_long_calculation(data),\
second_incredibly_long_calculation(data),\
third_incredibly_long_calculation(data)
]
# Idiomatic
def get_twitter_stream_for_keyword(keyword):
"""この関数はgeneratorで'can_get_stream_data(user)'がFalse
になるまで反復可能なデータを生成し続ける
"""
imaginary_twitter_api = ImaginaryTwitterAPI()
while imaginary_twitter_api.can_get_stream_data(keyword):
yield imaginary_twitter_api.get_stream(keyword)
# generatorを呼び出してるので、クライアントが終了するまでプロセス続けてる
for tweet in get_twitter_stream_for_keyword('#jeffknupp'):
if got_stop_signal:
break
process_tweet(tweet)
def get_list_of_incredibly_complex_calculation_results(data):
yield first_incredibly_long_calculation(data)
yield second_incredibly_long_calculation(data)
yield third_incredibly_long_calculation(data)
# 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')
# 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')
# 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)
# 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
# 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






















