2014/02/27

Python Tips:オブジェクトのアトリビュートを確認したい

Pythonで特定のオブジェクトのアトリビュートを確認する方法についてご紹介します。

オブジェクトのアトリビュートの一覧を取得するには dir() 関数を使います。

s1 = "hello"
n1 = 5

print dir(s1)
# str型のオブジェクトのアトリビュート/メソッド一覧を表示

print dir(n1)
# int型のオブジェクトのアトリビュート/メソッド一覧を表示

dir(obj) は、そのオブジェクトの中にある名前一覧を配列に格納して返してくれます。


dirが具体的にどういう動きをしているかなどの詳細は参考リンクをご覧ください。

参考
python - How to get a complete list of object's methods and attributes? - Stack Overflow

2014/02/24

Pythonの staticmethod と classmethod のちがい

Python には staticmethodclassmethod というよく似たふたつのデコレータが存在します。一見わかりづらいこれらのちがいについて今回は見ていきます。

結論からざっくり言うと両者のちがいは次のとおりになるかと思います。

  • staticmethod の高機能版が classmethod
  • ふたつのちがいは「引数の扱い」
  • staticmethod ではメソッドは実引数をそのまま受け取る
  • classmethod ではクラス自身が暗黙的に第一引数として挿入される

ことばだけではわかりづらいので、例を見てみましょう。

class MyClass(object):
    @staticmethod
    def static_method(*args):
        print(*args)

    @classmethod
    def class_method(*args):
        print(*args)

MyClass.static_method(1, 3, 5)
# => 1 3 5
# 渡された引数がそのまま順に表示される

MyClass.class_method(1, 3, 5)
# => <class '__main__.MyClass'> 1 3 5
# 渡された引数の前に「クラスそのもの」が表示される

staticmethod でデコレートされたメソッドは、引数を print() すると実引数がそのまま順番に表示されます。一方、 classmethod でデコレートされたメソッドには、実引数の前にクラスをあらわすオブジェクトが渡されていることが確認できます。

・・・ということからわかるように、 classmethod では第一引数に暗黙的にクラスそのものが渡される仕組みとなっています。

この classmethod のふるまいは、インスタンスメソッドの場合と同じです。

インスタンスメソッドの場合は暗黙的に第一引数にインスタンスが挿入されるので、定義する際は、第一引数を self とするのがきまりとなっています。 classmethod を使う場合もそれと同じように、第一引数を cls とすることが慣習となっています。

    @classmethod
    def class_method(cls, args):
        ...

以上です。

ちなみに staticmethodclassmethod もインスタンスから呼び出すこともできます。


参考
decorator - What is the difference between @staticmethod and @classmethod in Python? - Stack Overflow

2014/02/18

ライブラリ:virtualenvwrapper

Pythonのコマンドラインツールである「virtualenvwrapper」についてご紹介します。

virtualenvwrapper とは、その名前のとおり virtualenv の wrapper で、便利な virtualenv をより使いやすくしてくれるツールです。ちなみにWindowsには対応しておらず、LinuxとMac限定のツールとなっています。

以下に、特徴と初期設定、基本的な使い方を説明します。

特徴

virtualenvwrapper の特徴として次の6つが公式ドキュメントにあげられています(意訳です)。

  • すべての virtualenv 環境を一元管理できる
  • 便利な各種コマンド
  • 環境の切り替えがコマンドひとつで
  • タブによるコマンド補完
  • カスタマイズ可能なフック
  • 拡張機能も自由に開発可


初期設定

まずは virtualenvwrapper そのものをインストールします。その前に virtualenv がインストールされていなければ先にインストールしておきます。

pipがインストールされていれば virtualenvwrapper のインストールは pip install で可能です。
$ pip install virtualenvwrapper

インストールが完了したら virtualenvwrapper を有効化します。具体的には、環境変数 WORKON_HOME を設定し、 virtualenvwrapper.sh を実行します。
$ export WORKON_HOME=$HOME/.virtualenvs
$ source (適切なパス)/virtualenvwrapper.sh

ここで、 WORKON_HOME は virtualenv 環境を一元管理するディレクトリを指定するための変数です。ここではユーザホーム直下の .virtualenvs というディレクトリを使っていますが、場所はどこにおいても大丈夫です。管理の都合を考えると $HOME 直下に専用のディレクトリを作ってそこにまとめるのがよろしいかと思います。

virtualenvwrapper.sh は virtualenvwrapper を有効化するためのシェルスクリプトです。システムのPythonと同じディレクトリに virtualenvwrapper を入れた場合は /usr/local/bin あたりにあることが多いようです。

ここまで無事に準備が済んでいれば「workon」コマンドが使えるようになっています。
$ workon --help

ちなみに、この WORKON_HOME の設定と virtualenvwrapper.sh の読み込みのコマンドは、いつでも使えるようにターミナルの起動スクリプト(.bashrc など)に入れておくと便利です。

基本的な使い方

基本的な使い方として、virtualenv 環境の作成、一覧、切り替え、削除などを見ていきます。

virtualenv 環境の作成は mkvirtualenvwrapper コマンドを使います。
$ mkvirtualenvwrapper 環境名
数多くのオプションがあるため、詳しくは公式ドキュメントの該当箇所をご覧ください。オプションの一部としては、次のようなものがあります。

  • --python=使用するPythonへのパス 使用するPythonのバージョンを指定する
  • --no-site-packages グローバルのパッケージは使わない設定にする


mkvirtualenvwrapper で環境の作成に成功したら、自動的にその環境が有効化されます。どの環境が有効化されているかはターミナルのプロンプトよりわかります。プロンプトの先頭に (環境名) が付いていればその環境に入っている証拠となります。

これまでに作成され現在も存在する環境を一覧するには workon コマンドを使います。
$ workon

virtualenv 環境を複数作っている場合の環境の切り替えも workon コマンドで行います。
$ workon 環境名

有効化された環境から抜けるには deactivate コマンドを使います。
$ deactivate

最後に、環境の削除方法について。存在する環境を削除するには rmvirtualenv コマンドを使います。
$ rmvirtualenv 環境名

基本的な操作はこの4つのコマンドを押さえておけば大丈夫かと思います。ただ、この他にも豊富なコマンドが用意されているので、もっと詳しく知りたい方は公式のコマンドリファレンスをご覧ください。
Command Reference — virtualenvwrapper documentation

以上です。


参考
virtualenvwrapper
virtualenvwrapper — ドキュメント日本語翻訳
virtualenvwrapper documentation
virtualenvwrapper : Python Package Index
virtualenvwrapper | Doug Hellmann

Macでシステム以外のPythonをメインで使う設定にしたい場合は、こちらのページがたいへんわかりやすく参考になります。
Mac で Python の開発環境構築(2013.11) - methaneのブログ

2014/02/11

Pythonのスコープ その3

その 1その 2 に引き続き Python のスコープについて見ていきます。

みっつめのポイントは「スコープ内で使われる名前はスコープの先頭で作られる」というものです。

スコープ内で使われる名前はスコープの先頭で作られる


これは文章のとおりそのままなのですが、ことばだけでは説明しづらいので例をご覧ください。

C = 10

def myfunc1():
    print C

def myfunc2():
    print C
    if False:
        C = 100

myfunc1() # => 10
myfunc2()
# => UnboundLocalError: local variable 'C' referenced before assignment

ここで myfunc1() の呼び出しは問題なく動作しますが、 myfunc2() の呼び出しではエラーが上がります。

2 つの関数の違いとしては、 myfunc1() では単純に変数 C が参照されていますが、 myfunc2() の方では C が参照された後に条件付きで C が定義されている、という点が異なります。

ポイントは、 myfunc2() の中の if 文の評価結果は False なので実際には C = 100 の行には処理は到達しないという点です。

エラーの意味は「代入の前に C という名前を参照していますよね、それはできません」ということなのですが、こういうエラーが上がるということはつまり、「 myfunc2() の中の print C の行のところですでに C という名前が確保されており、グローバル空間の C への参照は失われている」ということを表します。

Python ではこのように、特定のスコープの中で定義された「名前」は巻き上げられ、スコープの先頭で確保される形になっているようです。

以上です。

ちなみに、 Python の場合にこの用語を使うかはわかりませんが、この「巻き上げ」処理のことを英語では「 hoisting 」(ホイスティング)と呼ぶそうです。

その 1 、その 2 の分とあわせて、この 3 つのポイントで、 Python のスコープに関するルールは大方押さえられるかと思いますので、参考にしてみてください。


おまけ

現在のスコープの中に存在する名前とそこにひもづけられた参照をチェックする関数として次のふたつの関数が用意されています。

  • locals()
  • globals()

たとえば次のようにするとローカル空間、グローバル空間に存在する名前を辞書として確認することが可能です。

def show_names():
    x = 5
    y = 6
    print locals()  # => {'x': 5, 'y': 6}
    print globals() # => グローバルの名前一覧

2014/02/07

Pythonのスコープ その2

その 1 につづいて、 Python のスコープのルールについて見ていきたいと思います。

ふたつめのポイントは「参照の順番は「 LEGB 」」というものです。

2. 参照の順番は「 LEGB 」


名前空間が関数やクラスで区切られるのはその 1 で見たとおりですが、名前を「参照する」という面においては「スコープチェーン」とも言えるような仕組みが Python には用意されています。

たとえば、次のコードを見てみましょう。

def outer_func():
    Const = 10

    def inner_func():
        # 外側のConstを利用する
        return Const

    return inner_func()

print outer_func()  # => 10

Python では関数内関数ーーいわゆる「関数のネスト」が可能となっていますが、ここで、内側の関数内では、その外側にある関数の変数を「参照」することができます。

具体的には、 inner_func() の中で Const という名前が使われていますが、これが参照されたときには inner_func() の中には Const という名前は存在しません。この場合 Python インタプリタは inner_func() のひとつ外側ーーつまり outer_func() の名前空間を探索しにいきます。そしてそこには Const という名前が存在するので、その値を利用します。

このようなスコープの拡大、名前探索の順序のルールを表したことばが「 LEGB 」です。 LEGB とは次の 4 つの単語の頭文字です。

  1. L: Local
  2. E: Enclosing function local
  3. G: Global
  4. B: Built-in

意訳すると次のような感じでしょうか。

  1. L: ローカル空間
  2. E: ひとつ外側にある関数のローカル空間
  3. G: グローバル空間(モジュール空間)
  4. B: 組み込み空間


意味合いとしては、名前を探索する順番が、最初にローカル空間、続いて外側にある関数のローカル空間、そこになければグローバル空間(モジュール空間)、それでもダメなら組み込み空間、というところになります。

かんたんな例を見てみましょう。

sho = 1

def outer():
    chiku = 2

    def inner():
        bai = 3

        print bai    # Lで発見
        print chiku  # Eで発見
        print sho    # Gで発見
        print abs    # Bで発見

inner() 関数の中でいろいろな名前を参照しています。 bai だけは同じ関数の中(ローカル空間)にその名前があるためそこで解決が済みますが、その他の名前はすべて異なる場所で参照を解決しています。

chiku はひとつ外側の関数、 sho はモジュールのトップレベル、 abs は組み込みの名前によって、参照先の値を取得しています。

・・・以上が、 Python のスコープに関するふたつめのルール「 LEGB 」です。

ちなみに、 global キーワードを使うと、グローバル空間にある名前を直接指定して参照や代入を行うことが可能となります。

C = 5

def outer():
    C = 10

    def inner():
        global C
        print C  # => 5
        C = 100

    inner()

outer()
print C  # => 100

さらに、 Python 3 では、 global に加えてひとつ外側の関数のローカル空間の名前を指定する nonlocal というキーワードが追加されています。

つづいて、みっつめのポイント「スコープ内で使われる名前はスコープの先頭で作られる」について見ていきます。

Pythonのスコープ その3


参考
scope - Short Description of Python Scoping Rules - Stack Overflow
closures - Python nonlocal statement - Stack Overflow

2014/02/04

Pythonのスコープ その1

何回かに分けて、 Python のスコープのルールについて見ていきたいと思います。

Python の変数がどの範囲でアクセスできるかという「スコープ」に関するルールは、まとめると次の 3 ポイントになるかと思います。

  1. 関数/クラス/モジュールで区切られる
  2. 参照の順番は「 LEGB 」
  3. 宣言はスコープの先頭に巻き上げられる

順に説明していきます。

1. 関数/クラス/モジュールで区切られる


Python には、関数、クラス、モジュールというコードの単位がありますが、それらがスコープの区切り目になります。

具体的には、関数の中と外、クラスの中と外、モジュールの中と外でスコープが異なります。

たとえば、次のコードを見てましょう。

margin = 10

def add_margin(x):
    margin = 50
    return x + margin
    
print add_margin(30)  # => 80

print margin  # => 10

このコードでは margin という名前が add_margin() という関数の外側と内側に存在しますが、関数の外と中は別の名前空間となるため、これらはまったくの別物です。

クラスの場合も同様です。

Const = 3

class MyMath(object):
    Const = 3.14

print Const  # => 3 

MyMath の中の Const と外の Const は別物です。

モジュールというのは、ここではスクリプトファイルのことを指して言っています。

たとえば、次のような moduleA.py と moduleB.py 、 2 つのファイルがある場合を考えてみましょう。

# moduleA.py
greeting = "Hi!"

# moduleB.py
greeting = "Ciao!"

次の main.py からそれらを import してみます。

# main.py
import moduleA
import moduleB

print greeting  # => エラー
print moduleA.greeting  # => Hi!
print moduleB.greeting  # => Ciao!

すると、 moduleAmoduleB の中のトップレベルに置かれた greeting という名前はそれぞれ moduleA.greetingmoduleB.greeting でアクセスすることとなります。つまり、モジュール単位で名前空間が区切られます。

from moduleA import greeting というように from ... import ... を使ってインポートをしてきた場合は名前を衝突させることができますが、基本的には名前空間はモジュール単位で別々になります。

つづいて、「2. 参照の順番は「LEGB」」というポイントについて見ていきましょう。

Pythonのスコープ その2