背景:Pythonって簡単?
Pythonを触り始めてから約一年ほどが経ちますがPythonは簡単な部類に入るのでしょうか?
巷では入門のプログラミング言語におすすめ!簡単等の謳い文句があったりしますが本当にそうなのでしょうか?
確かに動くプログラムを作るという観点では雰囲気でコードを書いてもなんやかんや動いたりするのですがPythonの売りである可読性が失われてしまったり、そもそも非効率な動かしかたをしていたり…
そもそも気づけてない点がたくさんあるんじゃないかと思い”Effective Python”を読み始めることにしました。副題にPythonプログラムを改良する90項目とあるので一つずつ勉強して更新していこうと思います。
この記事の対象者としてはまったくの初心者ではないけどPythonなんもわからんって人向けです。
基本的には筆者の興味のある順に更新していくつもりです。
Effective Python 1章
項目1 使用するPythonのバージョンを知っておく
まず記念すべき第一項目はPythonのバージョンの話です。
残念ながらPython2使いの方はこのページそっとじでお願いします。
現在(R02/10/14)でのPythonの最新バージョンは3.9.0です。しかし本書では3.7を基本に、時に3.8に触れながらという形で進めていきます。
この項目のポイントはPython2じゃなくてしっかりサポートされてるPython3を使えよってことなので特に問題ない方は読み飛ばしてもらって大丈夫です。
ちなみにバージョンの確認の仕方は
python --version
で確認できます。
しかしデフォルトでPython2が入ってる方は
python3 --version
で行けるはずです。
項目2: PEP 8スタイルガイドに従う
PEP8とはPythonのコードをどのようにフォーマットすれば美しいのかというガイドラインです。
ぶっちゃけた話これを守らずとも文法さえ合ってれば動きますがコード書く人としてそれはどうなのってことである程度の一貫したスタイルを作るための指標です。
ちなみにですがこれは絶対というわけではありません。もちろんこれに従うことでコードが読みにくくなるなど後方互換性を損なうのであればそれは考えなければなりません。
ただ私はPyCharmを使ってるのでその辺りは補完してくれます笑
空白
Pythonでは空白が構文情大きな意味を持ちます。
- インデントにはタブではなく空白を使う。
- 構文上意味を持つレベルでのインデントには、4個の空白使う
- 各行は長さ79字まで
- 長い式を避けるときは次の行でさらに4個の空白を入れる
- ファイルでは関数とクラスの間で空白2行を入れる
- クラスの中ではメソッド間に空白1行を入れる
- 辞書ではキーとコロンの間には空白を置かず、同じ行にかく場合は値の前に空白を1つ入れる。
- 変数代入の前後は空白一つ入れる。
こんな感じでずらずらと並べましたが意外なのはインデントを使うなってところですかね。
なんでダメなんでしょうか…?
命名規則
名前を見た時にその属性がパッと見でわかるといいですよねというお話
- 関数、変数、属性は小文字かつアンダースコアで挟む。ex)lowercase_underscore
- プロテクテッド属性はアンダースコアで始める。ex)_leading_underscore
- プライベート属性は二つのアンダースコアで始める。ex)__double_underscore
- クラスと例外は先頭を大文字にする。ex)Capitalization
- モジュールでの定数は全て大文字。ex)ALL_CAPS
- クラスのインスタンスメソッドは第一パラメータの名前にselfを使う。
- クラスメソッドは第一パラメータの名前にclsを使う
最後の二つをよく知らなかったので少し解説
参考記事Pythonのクラスメソッド(@classmethod)とは?使いどころとメソッドとの違いを解説
メソッドとクラスメソッド
クラスメソッドはクラス.メソッド()で呼び出すことができます。
メソッドとの違いとしてクラスメソッドはインスタンス化しなくても使えます。
関数と大きな違いはありませんが
- 第一引数でクラスが取得できる
- クラスの中にあるので、クラスをインポートすれば使える。
というメリットがあり。
import Hogehogeとしたときにまとめてインポートできるかどうかの違い(クラスの中でまとめて管理できるかどうかの違い)が大きいです。
式と文
- 式の否定ではなく内側の項の否定を使う
if not a is b
ではなくif a is not b
を用いる。
- コンテナの長さを用いて空の値かどうかを確認しない。
if len(somelist) == 0
のような使い方で""
[]
を判断しない。
if somelist
においてsomelistが空の値なら暗黙的にFalseと評価されることを使う。
- 逆もまたしりsomelistが空でないならTrueと評価されることも使うべき。
- if文 for文 while文 except文は1行にまとめない。
- 式が1行に治らないときは改行する。\(バックスラッシュ)を使うのではなくカッコを使って式を囲むべき。
インポート
- import文は常にファイルの先頭におく。
- fromを使いましょう。
- 相対import の場合でも
from . import bar
のように明示的にするべき
一貫したスタイルを作りましょうねというお話です。
項目3: bytesとstrの違いを知っておく
一旦とばします。
項目6: インデックスではなく複数代入アンパックを使う
まず複数代入アンパックってなんぞやということですが以下のようにリストやタプルのようなシーケンスを展開して複数代入をすることをアンパックと言います。
これの何が嬉しいのかという話ですが本書ではバブルソートを例にとってその良さを説明しています。
バブルソートにおける要素の交換の部分が一時変数なしで書けてるのがスマートでしょっていう主張ですね。
もう一つ、forループ、内包表記におけるターゲットリストでもいいことがあります。
こっちの方がきれいだよね、Pythonicだよねという話です。
Effective Python 2章
項目11 シーケンスをどのようにスライスするか知っておく
まずプログラムと言うのは前提として機械に向いている反復作業を自動化するために描かれていことが多いです。
この時、リストと辞書が非常に重要になります。Pythonにはシーケンスをスライスする構文があるのでそれをみていこうと言うわけです。
※シーケンスとはlist型,string型などの複数の要素をまとめて扱える型のことです。
スライス(:)の基本構文はsomelist[start:end]
です。startの要素は含まれ、endの要素は含まれません。
マイナスを使うことで逆からの参照も可能です。例えばsomelist[-1]
とすることで配列のサイズにかかわらず最後の要素を取り出すことができます。
そしてスライスで重要なこととして取り出した配列は全く新しい配列であり、取り出す元の配列は変更されないということです。
項目12 1つの式にスライスとストライドを同時に使わない。
先ほどのスライスに加えてストライドと言う増分を指定するストライドと言う構文があります。
somelist[start:end:stride]
が基本の構文であり、
こんな感じで配列の偶数要素を取り出したり、逆順にしたりすることができます。
ただ分かりづらいと言うのがまず個人的な感想です。この構文が何を意味するのかを検索するのも一苦労でした笑
そしてEffective Pythonにおいてもそれは指摘されており、解決策として「スライスとストライドは同時に使わない」を推奨しています。
項目13 スライスではなくcatch-allアンパックを使う
catch-allアンパックとは項目6のアンパックと関係しています。アンパックするには基本的にシーケンスの長さが分かっていないと使えません。
例えば1つ目、2つ目を取り出し、それ以外をまとめて欲しい時場合があるとします。この時先の項目12のようにスライスを駆使することで実装を行うことができますがコードの保守性が低くなります。(スライスの片方の境界値のみを変更してもう片方の修正を忘れる等)
そこでcatch-allアンパックです。アスタリスク付きの引数を使うことでアンパックするシーケンスの「残り全て」を引き受けてくれます。例を見てもらう方が早そうです。
リストを重複なく分割するときにエラー、もしくは想定外の動作をするリスクを減らせますよというお話。
項目86 try,except,else,finaly の各ブロックを活用する。
Pythonで例外処理のしかたについて。
入力値によっては関数の中でエラーが起きてしまうということはよくある話です。製作者の意図しない入力に対しても頑鍵であることは大事です。
上の例では2つの値を引数にして割り算を行うものですが思いつくエラーとして
- 0で割ってしまう。
- そもそも引数が数値でない。
などが考えられます。
これらに対してあらかじめ手を打とうというのがこのtry,exceptという構文です。
コメント