こしごぇ(B)

旧:http://d.hatena.ne.jp/koshigoeb/

仕事で Python を使う様になってそろそろ一年

特に、好きになる事もなく、淡々とした関係が続いております。

最近は Rails 4.1 で仕事してるわけですが、やっぱり慣れてるという事もあって Ruby が落ち着きますね。

Python を使ってきて印象的なことはなんだろう。

  • KeyError は分かりやすい落とし穴
  • IndexError は見落としがちだった落とし穴
  • str, unicode のあたりは未だに整理がついてない(endode, decode)
  • logging モジュールは好き
  • MongoDB を直接 pymongo とか使って dict に変換すると KeyError ががが、、、

こうして振り返ると、なまくら刀が赤さびだらけでぼろっぼろになってる事がよく分かるな・・・。

条件を満たす最初の要素を返す(Python)

Ruby の Array#find を Python でどうやるのか悩んだ。

(0..4).find{|n| n > 3}

イテレータを作って next で次(最初)の要素を取って止めたら良いと言うことが分かった。

next(x for x in xrange(1,5) if x > 3)
next(x for x in xrange(1,5) if x > 4)

該当するものが無かった場合に StopIteration 例外を発生させないためには、ifilter を使うと良いらしい。

from itertools import  ifilter
next(ifilter(lambda x: x > 3, xrange(1,5)), None)

こういう細かいところで躓きまくるから、新しい知識が増えるのは良いんだけど、実装作業が若干ストレスフル。

追記

Ruby の Hash#key を Python で実現するにはどうしたらよいのか。

{a: 1, b: 2, c: 1}.key(1)

また next を使う?

next(k for k,v in {'a': 1, 'b': 2, 'c': 1}.items() if v == 1)

MongoDB でのツリー構造

ドキュメント指向のデータベース設計に慣れていないので、外部参照的なアプローチが妥当なのかすら分からず。

MongoDB のツリー構造に関するドキュメントを読んだ感じ、普通に参照で関連を持たせたらよさそう。

個人的には、Array of Ancestors パターンが好みかな。

Python の書式指定など

未だ手探り。

数値を3桁カンマ区切りに整形したい場合、言語組み込みの書式指定を使うのが簡単な模様。

>>> '{:,d}'.format(100000)
'100,000'

ロケールごとのセパレータを使いたい場合、d の代わりに n を使うと良いとのこと。

>>> import locale
>>> locale.setlocale(locale.LC_ALL, '')
>>> '{:n}'.format(100000)
'100,000'

文字列の切り詰め処理は、自前で用意するもの?

>>> s = u'あいうえおかきくけこさしすせそ'
>>> print s[:10] + '..' if len(s) > 10 else s
あいうえおかきくけこ..
>>> print s[:15] + '..' if len(s) > 15 else s
あいうえおかきくけこさしすせそ

5年ぶりくらいの Selenium

Selenium IDE 便利。

Selenium Server とブラウザドライバを使えば、Firefox アドオンの Selenium IDE から Chrome とか IE とかにテストを実行させる事ができる。しかも簡単に。 あいにく、Safari は自前で証明書を用意してドライバをビルドする必要があるとかで試せていない。

capybara とかからでも WebDriver を使う事はできるけど、ステップ実行とか操作しやすいのは Selenium IDE じゃないかなと思う。 さすがに CI とかで自動化する場合は capybara とかが便利だと思う。

問題は、Selenium Server 越しのテストでは waitForVisible とか verifyNotVisible とか一部のコマンドが期待通りに動いてくれない事。

あと、modern.IE のおかげで手軽に IE でのテストを実行出来るのもありがたい事です。 (日本語入力とか日本語表示とか、若干面倒なところはあるけれど。)

Python 再入門(3.2)

参考書籍

パーフェクトPython (PERFECT SERIES 5)

パーフェクトPython (PERFECT SERIES 5)

関数

  • 位置指定引数
  • キーワード引数
>>> def func(a, b, c, d, e):
...     print [a, b, c, d, e]
...
>>> func(1, 2, 3, 4, 5)
[1, 2, 3, 4, 5]
>>> func(1, 2, 3, e = 5, d = 4)
[1, 2, 3, 4, 5]
>>> bc = (2, 3)
>>> de = { 'd': 4, 'e': 5 }
>>> func(1, *bc, **de)
[1, 2, 3, 4, 5]
  • デフォルト引数
>>> def func(a, b = 2, c = 3):
...     print [a, b, c]
...
>>> func(1)
[1, 2, 3]
>>> func(1, '2')
[1, '2', 3]
  • 可変長引数
    • 可変長引数の後に他の変数を指定する事ができるのは Python 3.0 以降
>>> func(1, 2, 3, x = 4, y = 5)
[1, (2, 3), {'y': 5, 'x': 4}]
  • return
  • global
  • nonlocal
    • クロージャ

ジェネレータ関数

  • __next__ メソッドが呼び出される度に yield までが実行され、yield 式で指定された値を返す
  • send(), throw(), close()
  • サブジェネレータ: yield from ** Python 3.3 以降

高階関数と lambda 式

  • lambda

関数デコレータ

  • @デコレータ関数名
  • デコレータ関数は関数を受け取って関数を返す

ドキュメンテーション文字列

  • docstring """

関数アノテーション

  • Python 3 以降
  • : 注釈
  • -> 注釈
def add(left: '説明', right: '説明') -> '説明':
    return left + right

クラス

クラス定義

class Hoge:
    """"
    ...
    """

    def func(self, arg):
        ...

class Blank:
    pass
  • 属性を自由に追加・削除できる
>>> obj = Blank()
>>> obj.x = 1
>>> obj.x
1
>>> del obj.x
>>> obj.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Blank instance has no attribute 'x'

メソッド

  • 最低1つの引数(自分自身)を受け取る
    • この先頭の引数は慣習的に self と名付ける

コンストラクタ

  • __init__

デストラクタ

  • __del__
  • ほとんどの場合定義しない

インスタンスアロケータ

  • __new__
  • 第1引数はクラスオブジェクト
  • immutable な場合の初期化など

継承

class Base:
    pass

class Sub(Base):
    pass
  • super()

多重継承

class Hoge(A, B, C):
    pass

特殊メソッド

  • 特殊なメソッドをオーバーライドすることで、演算子オーバーロードなどが実現できる。

プライベートメンバ

  • アンダースコア2つで始まり、末尾がアンダースコアなしか1つの名前をつけると、外部からその名前で参照できなくなる。

ディスクリプタ

コンテキストマネージャ

  • with 文でコンテキストを提供するオブジェクトをコンテキストマネージャと呼ぶ
  • with 文の開始時にブロックの実行に必要なコンテキストを用意し、ブロック終了時にコンテキストを解放する
  • __enter__(self), __exit__(self, exc_type, exc_value, traceback)

プロパティ

  • 組み込みのデコレータ property を使ってアクセサメソッドを通常の属性アクセスの様に使える

クラスメソッド

  • デコレータ classmethod
  • デコレータ staticmethod
    • 第1引数への追加はない

クラスデコレータとメタクラス

  • クラスオブジェクトを受け取って、クラスオブジェクトを返すメソッド
  • クラス定義時にキーワード引数 metaclass でメタクラスを指定出来る
    • 省略時は type がメタクラスとなる
    • __new__(metacls, bases, classdict), __init__(cls, bases, classdict)
      • クラスオブジェクトの生成と初期化のために呼ばれる
      • bases: 基底クラスのタプル
      • classdict: クラスのメンバを格納した辞書

抽象基底クラス(Abstract Base Class: ABC)

  • Python 3.0 以降
  • ABCMeta
  • register()
  • abstractmethod デコレータ
    • 抽象基底クラスを基底クラスとするクラスでは、全ての抽象メソッドがオーバーライドされていなければインスタンスを生成できない

モジュールとパッケージ

モジュール

  • import モジュール名
  • from モジュール名 import メンバ名
  • import モジュール名 as 名前
  • sys.path でモジュールの検索パスを得られる
    • システム固有のデフォルトディレクトリと環境変数 PYTHONPATH で指定したディレクトリを含む
    • sys.path の先頭はスクリプトファイルのディレクトリ

パッケージ

  • 複数のファイルに分けて機能を提供する事ができる
パッケージ名/
┆
├\_\_init\_\_.py
├モジュール名.py
├モジュール名.py
└サブパッケージ名/
 └モジュール名.py
  • __init__.py は中身が空でもかまわない
  • パッケージ内のモジュールから同じパッケージ内の別のモジュールをインポートする場合、相対形式で指定出来る

名前空間パッケージ

  • Python 3.3 以降
  • __init__.py は置けない

モジュールの実行

  • python -m モジュール名
  • python モジュールディレクトリ
  • __main__.py