物理の観点

物理に関することから、自分が気になることまでいろいろ書いていくつもりです。

「リーダブルコード」きれいなコードを書くために

どんな本か?

この本の内容を一言でまとめると、いかにして可読性の高い読みやすいコードを書くかということを書いてある本です。

プログラミングの勉強をしていると、よく目にするのが

  • 可読性の高いコードを書くことが重要で~
  • 他人が見ても読みやすいコードを書くべき
のような言葉。確かに、言われなくてもぐちゃぐちゃなコードよりかはきれいに整ったコードのほうが良いのはわかります。でも果たして、良いコードとはどのようなコードなのか。「良いコード」に対して漠然としたイメージしか持てない方もいると思います。本書は、きれいなコードを書きたい、良いコードとはどのようなコードのことをいうのか理解したいという方にお勧めの一冊です。

理解しやすいコードとは?

リーダブルコードでは、わかりやすい、きれいなコードを書く方法を説明する前に「きれいなコードとはどんなコードか?」ということを定義するところから始めています。筆者の考えでは、

他人が最短時間で理解できるコード
が良いコードの条件。つまり、この考えこそがこの本の軸となる考え方で、今後の具体的な手法はこの考えを基礎としています。

最短時間で理解できるコードというのは、最も短いコードと等価ではありません。実際に本で紹介されているコードがこちらです。

// 短さに重点を置いたコード
assert((!bucket = FindBucket(key))) || !bucket->IsOccupied());
//行数は長いが、より短い時間で理解できるコード
bucket = FindBucket(key);
if (bucket != NULL) assert(!bucket->IsOccupied());
view raw Readable_Code_p4.c hosted with ❤ by GitHub
この2つのコードはどちらも同じことをしているC言語のコード。C言語をよく知らない人でも、2番目のコードのほうが読みやすいというのはわかると思います。これは読みやすいコードを書くために、わざとコードを2行に分けて書いています。

このような技法は、基本的なもので、指摘されなくてもできているような人も多いと思います。ここから第一章が始まり、様々な技法が紹介されます。

変数の名前をよく考える

皆さん、コードを書くときに変数名はどのように決めているでしょうか?変数が多いと考えるのがめんどくさくて「a, b, c」と順番につけてしまったり、サイトでよく使われているような「foo」や「tmp」などをついつい使ってしまうという人もいると思います。

これがいつでも間違いというわけではありません。tmpなどは名前の通り、寿命の短い、一時的な(temporary)変数に使うのであれば問題ありませんし、「a, b, c」でも、連続性が大事な場合にはこれがベストということもあるでしょう。しかし、深い理由もなしに適当に変数の名前を付けてしまうと、コードが読みづらくなったり、バグに気づきにくくなったりします。下に本の中に載っているコードを一つ引用します。

// ループを回す際の変数としてi, j, kを使っている
for (int i = 0: i < clubs.size(); i++)
for (int j = 0: j < clubs[i].members.size(); j++)
for (int k = 0: k < users.size(); k++)
if (clubs[i].members[k] == users[j])
cout << "user[" << j << "] is in club[" << i << "]" << endl;
// 変数に意味を持たせている
for (int club_i = 0: club_i < clubs.size(); club_i++)
for (int members_i = 0: members_i < clubs[i].members.size(); members_i++)
for (int uses_i = 0: users_i < users.size(); k++)
if (clubs[club_i].members[users_i] == users[members_i])
cout << "user[" << members_i << "] is in club[" << clubs_i << "]" << endl;
こちらも上下で同じことをしています。上のコードでは、ループを回すのによくある「i, j, k」を使っていて、下では、変数の中身を考えて、「clubs_i, members_i, users_i」という名前を使っています。

ところでこのコードを読んでいて気づいたことはないでしょうか。実はこのコードにはバグが入っています。上のコードでは5行目、下のコードでは13行目です。インデックスの指定が逆になっています。上のコードではこのバグは注意してみないとわかりません。しかし、下のコードだと

members[users_i]
と明らかに変なことがわかります。

リファクタリングの方法論

リファクタリングというのは、例えば、ある関数があるときにその中身を読みやすいように整理したり、繰り返し書いている部分をほかの関数として新たに定義してコードを簡潔にしたりする操作のことです。本書で著者がリファクタリングの際に重要だと主張しているのは主に以下の3点です。

  • プログラムの主目的と関係のない「無関係の下位問題」を抽出する
  • 関数には一度に1つのことをやらせる
  • 最初にコードを言葉で説明する。それをもとにしてきれいな解決策を考える
下の2つは何となく理解できると思います。しかし、最初のものは少し抽象的なのでこれだけ見てもよく分からないでしょう。例として、本に載っているコードを書いてみます。
business = Business()
business.name = request.POST["name"]
url_path_name = business.name.lower()
url_path_name = re.sub(r"['\.]", "", url_path_name)
url_path_name = re.sub(r"[^a-z0-9]+", "-", url_path_name)
url_path_name = url_path_name.strip("-")
business,url = "/biz/" + url_path_name
business.date_created = datetime.datetime.utnow()
business.save_to_database()
#無関係の下位問題を抽出
CHARS_TO_REMOVE = re.compile(r"['\.]+")
CHARS_TO_DASH = re.compile(r"[^a-z0-9]+")
def make_url_friendly(text):
text = text.lower()
text = CHARS_TO_REMOVE.sub('', text)
text = CHARS_TO_DASH.sub('-', text)
return text.strip("-")
business = Business()
business.name = request.POST["name"]
business.url = "/biz/" + make_url_friendly(business.name) #コードが簡潔になった
business.date_created = datetime.datetime.utnow()
business.save_to_database()
このコードはBusinessオブジェクトを作って、それに変数をセットすることをしていますが、nameから有効なURLを生成してからurlにセットするということをしています。これが無関係な下位問題です。このコードの目的はclass変数をセットすることであるのに、求めている形式に合わせるためのコードが紛れ込んでしまっています。下半分のコードではこの部分を関数としてまとめる(抽出する)ことによってコードを簡潔にしています。

このような抽出作業は、コードを見やすくすること以外にも恩恵をもたらします。例えば、関数として抽出することによって、このコードをほかの場所で再利用することができます。また、独立に関数として存在しているので、コードの改善がしやすくなります

テストを書く

プログラミングにおける、テストについてどれくらい知っているでしょうか?テストの技法は少なくともプログラミング言語の入門書では扱っていない分野だと思います。テストというと、テスト駆動開発(TDD)を想像する方も知ると思いますが、ここではテスト駆動開発自体については触れられていません。

ここで説明されているのは、どのようにテストコードを書くべきか、ということです。基本的な原則はここまでの章で説明したこととほとんど同じで、

  • 一度に一つのことをやる
  • 無関係の下位問題を抽出する
ということです。テストコードは、本体のコードのバグを見つける際に非常に重要になるコードなので、読みやすさというのは特に重要になります。また、テストコードに関しては、テストが失敗したときに表示されるエラーメッセージを工夫することによっても読みやすさを向上させることができます。

まとめ

ここまでで、「リーダブルコード」で紹介されているコードを読みやすくするテクニックのいくつかを紹介してきました。コードの読みやすさは、仲間と共同で大規模な開発を行っているときはもちろん、一人で趣味などで開発をしている人にとっても非常に重要なファクターです。自分が書いたコードでも時間がたてば他人が書いたコードと同じです。本書は、すべてのプログラマーにとって効率よく開発を進めていくための必読の書といえます。

紫外線から身を守るには

hideri今年も夏がやってきました。暑いですね。年々熱くなっている気がします...(;´Д`)

夏になると気になるのが「紫外線」ですよね。紫外線は日焼けを引き起こすほか、しわやシミの原因になるのでなるべく浴びたくないものです。そこで今回は紫外線を防ぐためにどのような道具を使うべきかまとめてみたいと思います。

紫外線の種類
最初に紫外線の種類について説明します。最近よく聞くようになりましたが、一口に紫外線といってもいくつか種類があります。これらは波長によって区別されます。波長というのは波の幅のことで、値が小さいほど大きなエネルギーを持ちます。紫外線の分類は下のようになっています。
  • A波(UV-A) : 波長400-315nm。肌の奥深くまで届く。シミやしわに大きな影響
  • B波(UV-B) : 波長315-280nm。日焼け(やけど)を引き起こす
  • C波(UV-C) : 波長280nm-。エネルギーが強く、殺菌作用あり。地上には届かない
幸いなことに一番エネルギーの高いUV-Cは大気に阻まれて地上にはほとんど届きません。なので紫外線対策で注意すべきなのはUV-AとUV-Bです。

身近な材料と紫外線

世の中には様々な紫外線対策グッズがあふれています。日傘や日焼け止めが代表的な例です。中には真夏なのに長袖・長ズボン、さらにはヘルメット並みに顔を覆うことのできる帽子にマスク、サングラスと全身を覆っているような人も見かけます。

このような人を見てふと思いました。

 普通に服で肌を覆ってやれば紫外線は防げるのか?

その人が着ている服が普通の服かどうかはわかりません。しかし、普通の服、普通の傘の紫外線に対する有効性は気になるところです。そこで、服や傘にもよく使われているナイロンがどれだけ紫外線を通すのか調べてみました。
nylon-UV
これはナイロンの透過率(縦軸)が波長(横軸)によってどれだけ変わるかというものを示したものです[1]。(a)のグラフが普通のナイロンです。紫外線の領域で透過率がどうなっているか見てみると、UV-Aの場合およそ80%とほとんど通過してきてしまうことがわかります。UV-Bは少しは防げて、透過率は10-40%になっています。つまり普通の服では、
  
  日焼け対策にはなってもシミ・しわ対策にはならない

と言えます。

さて、次にビニール傘の場合を考えてみましょう。ビニール傘なんて透明なんだから対策になるとは思えませんが、透明なのはあくまで可視光の領域の話で、紫外領域では案外ブロックするかもしれません。少し期待して調べてみました。

ビニール傘の材料は、一昔前まではポリ塩化ビニルでしたが、環境問題などによりポリオレフィン・エラストマー(POE)等が使われるようになっています。
POE-UV

これがポリオレフィンの透過率(青線)です[2]。確かに可視光領域(400-800nm)では80%以上が透過していて波長で透過率があまり変化しません(つまり無色透明に見えるということ)。しかし、紫外領域に入った瞬間に、透過率が急降下します。あまりに降下が激しいのでUV-A領域の波長が長い部分で透過率が高いのか・低いのか判別が難しいのですが、少なくともナイロンよりは紫外線を防ぐことができているように見えます。つまり結論は、

   
ビニール傘は意外と紫外線を防ぐ(?)

意外ですね...(本当か?)

いろいろな身近な材料の紫外線の透過率を見てみると、UV-Bは意外と何でも防げることがわかります。

紫外線対策

ではここからは具体的に紫外線対策をするにはどうすればよいか書いてみます。まず日焼け止めですが、最近では酸化亜鉛という物質が含まれているクリームが多く発売されているようです。酸化亜鉛は紫外線を効率的にカットできる物質で、紫外線に対する効果に関する研究が活発に行われているようです。

つぎに、日傘ですが、こちらにも大きく分けて2種類のタイプがあるようです。1つは紫外線防止コーティングされているものです。コーティングにはポリウレタンなどが使われます。また、もう1つがシルバーコートと呼ばれるものです。これは傘の外側もしくは内側に金属をコーティングしてあり、紫外線を反射することを想定したものです。コーティングに何の金属を使用しているのかはわかりませんが、金属によってはこれはあまり効果がないように思います。というのも、
UV-spectrum-of-metals
この図は、各種金属が各波長の光をどれだけ反射するかを示している図です[3]。アルミニウム(Al)を見てみると紫外線領域は90%近く反射します。しかし、もし仮に名前の通り銀(Ag)を使っているとするならば、紫外線領域の反射率は高くても20%程度です。

金属は人間の目には光を全部反射するように見えますが、紫外線領域は必ずしもそうとは限りません。銀のように紫外線領域に対してはスカスカな金属もあるということは知っておくべきでしょう。


参考文献
[1] https://www.researchgate.net/figure/UV-transmission-spectra-of-a-nylon-6-6-nano-fi-bers-b-seeded-nylon-6-6-nano-fi-bers_fig4_237144395
[2] https://www.sciencedirect.com/science/article/pii/S0927024815005206 (一部編集)
[3] https://physics.stackexchange.com/questions/72368/why-are-most-metals-gray-silver

数値計算のためのPython入門 第九回 プロット①



前回はPythonを用いて多項式処理をする方法を書きました。今回はグラフについて書きたいと思います。数式だけ見ていても状況がよくわからないということは多々あります。そのような時にはグラフ化して考えるとわかりやすくなるということがあります。ここでは、数値群をグラフにプロットする手法を説明します。

1.リストをプロット

一番簡単なのは、自分でリストを作ってそれをPythonにプロットしてもらうというものです。 例えば、点(1,1), (3,6), (6,3)をプロットしたい場合には2つのリスト

[1,3,6]: x座標を入れたリスト
[1,6,3]: y座標を入れたリスト

を作ってプロットします。 このとき使うライブラリは、numpymatplotlibです。コードは次の通り。

import numpy as np
import matplotlib.pyplot as plt

x = [1,3,6]    #x座標のデータ
y = [1,6,3]   #y座標のデータ

plt.plot(x,y)    #横軸にxの値を縦軸にyの値を持つ点をプロット
plt.show()     #グラフを表示

すると、次のような画面が現れると思います。

plot
この折れ線は上の3点を結んだものです。

場合によっては、線で結んでほしくないときもあります。そのような時には

plt.plot(x,y) →  plt.plot(x,y,'o')

とすれば丸になります(ちょっと切れてしまっていますが)。

plot
 切れているのが気持ち悪いという人は次のようにします。まずは

import matplotlib.pylab as pl
として、matplotlibの中のpylabというものをインポートします。そうすればpylabの中のxlimylimというコマンドが使えるようになります。

pl.xlim(0,7)
pl.ylim(0,7) 
とすれば、x軸y軸ともに0から7までの範囲に広がります。
 
2.プロットの種類を変える

今は、丸でプロットしましたがこれを四角や三角に変えることもできます。

plt.plot([1,2,3,6,2])       #デフォルト, 折れ線
plt.plot([2,4,1,7,3],'--')  #破線
plt.plot([1,3,2,3,5],'-.')  #一点破線
plt.plot([5,1,5,9,1],':')  #破線
plt.plot([1,2,5,7,2], ',')  # ドット
plt.plot([5,2,3,7,9], 'o')  # 円
plt.plot([10,8,2,1,8], 'v')  # 下向き三角
plt.plot([3,10,10,12,13], '^')  # 上向き三角
plt.plot([3,3,3,3,3], '<')  # 左向き三角
plt.plot([4,4,4,4,4], '>')  # 右向き三角
plt.plot([5,5,5,5,5], 's')  # 正方形
plt.plot([6,6,6,6,6], 'p')  # 五角形
plt.plot([7,7,7,7,7], 'h')  # 六角形 (縦)
plt.plot([8,8,8,8,8], 'H')  # 六角形 (横)
plt.plot([9,9,9,9,9], '+')  # 十字
plt.plot([10,10,10,10,10], 'x')  # バツ
plt.plot([11,11,11,11,11], 'd')  # 菱形
plt.plot([12,12,12,12,12], 'D')  # 正方形 (斜め)
plt.plot([13,13,13,13,13], '|')  # 縦線
plt.plot([14,14,14,14,14], '_')  # 横線
plt.plot([15,15,15,15,15], '-o')   # 折れ線 + 円
plt.plot([16,16,16,16,16], '--o')  # 破線 + 円

これをプロットしたものが次の図になります。

plot3

 だいぶ長くなってしまったので今回はここまでにします。次回は、プロットの色を変えたり、プロットの種類を変える方法を書くつもりです。

ライブドアブログでは広告のパーソナライズや効果測定のためクッキー(cookie)を使用しています。
このバナーを閉じるか閲覧を継続することでクッキーの使用を承認いただいたものとさせていただきます。
また、お客様は当社パートナー企業における所定の手続きにより、クッキーの使用を管理することもできます。
詳細はライブドア利用規約をご確認ください。