2015/05/31

Python Tips:変数が定義されたかどうかを調べたい

Python で変数が定義されているかどうかをチェックする方法をご紹介します。

最もシンプルなのは例外をキャッチする方法かと思います。

# 変数 abc があるかどうかをチェック
try:
    abc
except NameError:
    # なかった場合の処理

ただ変数がそのスコープにあるかどうかだけでなく、もう少し厳密にチェックしたい場合には locals() globals() が使えます。 locals() はローカルスコープの名前を、 globals() はグローバルスコープの名前一覧を格納したリストです。

# ローカルスコープでチェック
if 'abc' in locals():
    # あった場合の処理
else:
    # なかった場合の処理

# グローバルスコープでチェック
if 'abc' in globals():
    # あった場合の処理
else:
    # なかった場合の処理

ちなみに、変数名ではなく、クラスが特定の名前のプロパティやメソッドを持つかどうかをチェックしたい場合には hasattr() や dir() が利用できます。

class C(object):
    def __init__(self):
        self.abc = 0

c = C()

# c に abc というメンバがあるかどうかをチェック
if hasattr(c, 'abc'):
    print(c.abc)

# 同上
if 'abc' in dir(c):
    print(c.abc)

以上です。

2015/05/26

Python Tips:文字列の中の文字をカウントしたい

Python で文字列中の各文字の出現回数をカウントする方法をご紹介します。

dict でカウント

まずは、最もシンプルな dict 型を使った方法から。

string = 'supercalifragilisticexpialidocious'

counter = {}
for c in string:
    if not c in counter:
        counter[c] = 1
    else:
        counter[c] += 1

print(counter)  # => {'a': 3, 'c': 3, 'e': 2, ...

defaultdict でカウント

つづいて、 collections ライブラリの defaultdict を使った方法。デフォルト値を決められる分、よりシンプルに書くことができます。

from collections import defaultdict

string = 'supercalifragilisticexpialidocious'

# デフォルト値が 0 の辞書を定義してカウンタとして使う
counter = defaultdict(lambda: 0)
for c in string:
    counter[c] += 1

print(dict(counter))  # => {'a': 3, 'c': 3, 'e': 2, ...

Counter でカウント

さらに Python 2 系では Python 2.7 から導入された Counter クラスを使った方法もあります。
こちらは Counter の名前のとおり、カウンタとしてそのまま利用できる機能を備えたクラスなので、さらにシンプルにカウンタを実現することができます。

from collections import Counter

string = 'supercalifragilisticexpialidocious'

# string を渡して Counter インスタンスを生成
counter = Counter(string)

print(counter['a'])  # => 3
print(dict(counter))  # => {'a': 3, 'c': 3, 'e': 2, ...

以上です。


参考
Python Tips:辞書にアイテムが存在しない場合のデフォルト値を設定したい
defaultdict — Python 公式ドキュメント
Counter — Python 公式ドキュメント
Counting repeated characters in a string in Python - Stack Overflow

2015/05/20

Python Tips:標準入力からパスワード入力を受け付けたい

Python で標準入力でパスワードを入力してもらう方法をご紹介します。

パスワードを入力させるときには、通常標準入力を受け付けるときとは異なり、入力内容を画面に表示しないようにしたいものです。

パスワードを入力してもらうときには標準添付の getpass ライブラリを使うのが便利です。

[getpass — Portable password input — Python 公式ドキュメント](https://docs.python.org/2/library/getpass.html)

getpass ライブラリには raw_input() 関数と同じような形で使える getpass() が入っています。

# coding: utf-8
from getpass import getpass

# 名前とパスワードの入力を受け付ける
name = raw_input('your name: ')
password = getpass('your password: ')

以上です。

余談ですが、 raw_input() は Python 2 の関数です。
Python 3 で同様のことをするには input() 関数を使うとよいでしょう。

2015/05/07

Python Tips:辞書にアイテムが存在しない場合のデフォルト値を設定したい

Python で辞書にアイテムが存在しない場合のデフォルト値の設定方法をご紹介します。

Python の辞書を使っていると、次のような処理をしたくなるときがあるかと思います。

# 各朝食メニューの回数を調べる
breakfast = ['kome', 'pan', 'kome', 'kome', 'cereal', 'pan', 'kome']

numbers = dict()
for b in breakfast:
    if b in numbers:
        numbers[b] += 1
    else:
        numbers[b] = 1

print(numbers)
# => {'pan': 2, 'kome': 4, 'cereal': 1}

この処理はもちろん間違っていませんが、もっとシンプルにわかりやすく書きたい場合はデフォルト値を使うのが便利です。デフォルト値を使うにはいくつかの方法があります。 2 つの方法を以下にご紹介します。

方法その 1. get メソッドを使う方法


辞書の get メソッドを使うと上記の for ループは次のようにコンパクトに書き換えることができます。

for b in breakfast:
    numbers[b] = numbers.get(b, 0) + 1

get メソッドは、第 1 引数に取得したいアイテムのキーを、第 2 引数にそのアイテムが見つからなかった場合のデフォルト値を受け取ります。戻り値は [] と同じです。

方法その 2. defaultdict


もうひとつの方法は、その名も defaultdict というデフォルト値つきの辞書型を利用する方法です。 defaultdict は組み込みの collections ライブラリに含まれています。 defaultdict を使うと上記のコードは次のように書き換えることができます。

# 各朝食メニューの回数を調べる
from collections import defaultdict

breakfast = ['kome', 'pan', 'kome', 'kome', 'cereal', 'pan', 'kome']

numbers = defaultdict(lambda: 0)
for b in breakfast:
    numbers[b] += 1

print(dict(numbers))
# => {'pan': 2, 'kome': 4, 'cereal': 1}

defaultdict を生成する際に関数やクラスなど callable なオブジェクトを渡すと、キーが見つからなかった場合にそのオブジェクトが呼び出されます。 numbers = defaultdict(lambda: 0) のところは次のように書き換えることも可能です。

numbers = defaultdict()
numbers.default_factory = lambda: 0

参考
dict.get — Python 公式ドキュメント
collections.defaultdict — Python 公式ドキュメント

2015/05/02

import の使い方

Pythonの import の使い方をご紹介します。

Pythonで他のモジュールやパッケージを読み込む方法といえば import ですが、その import にもいろいろな使い方があります。

以下、代表的な使い方を見てみましょう。

xyz ライブラリ全体を読み込む


import xyz

xyz.a_func()  # xyz の中で定義された関数 a_func() を呼び出す

xyz ライブラリのうち一部の名前だけ読み込む


from xyz import a_func

a_func()  # xyz の中で定義された関数 a_func() を呼び出す

xyz ライブラリの中にある名前をすべて読み込む


* を使うと、そのライブラリの中のすべての名前をインポートしてくることができます。ただしアンダースコア 2 つで囲われた __abc__ という形の名前は対象外となります。

from xyz import *

a_func()  # xyz の中で定義された関数 a_func() を呼び出す

また、この方法は言語仕様として可能は可能なのですが、 Python PEP20 の「 explicit rather than implicit 」(「暗黙」よりも「明示」)というポリシーを尊重するなら一切使うべきではありません。

独自の名前をつけて読み込む


as というキーワードをつけると、インポートしてくる名前に別名をつけることができます。名前の衝突を防ぎたい場合や短縮形を使いたい場合に便利です。

from xyz import a_func as f

f()  # xyz の中で定義された関数 a_func() に別名 f() をつけて呼び出す

その他の方法


その他の使い方もご紹介しておきます。ただ、めったなことでは使わないのかな、と思います。

相対パスを使って読み込む

Python 2.5 からは一応相対パスを使うこともできます。

次のようなディレクトリ構造で、 main から b.py を呼び出し、その b.py の中から a.py を利用したい場合を考えます。

main.py
lib/
  __init__.py
  a.py
  subdir/
    __init__.py
    b.py

この場合、 main の中で b.py を読み込む部分と b.py の中で a.py を読み込む部分は次のように書くことができます。

# main.py
from lib.subdir import b

# b.py
from .. import a

ただしこの方法は __init__.py を使ってパッケージ化されている場合でないと使えないようです。

普通のスクリプトの中でどうしてもひとつ上の階層の Python ファイルを読み込みたい場合にはパスを追加する形で実現することができます。

import os
import sys

path = os.path.join(os.path.dirname(__file__), '../')
sys.path.append(path)

ただしこの方法は推奨されていないようなので、「どうしてもやむなく」という場合のみとするのがよさそうです。

import キーワードではなく関数を使って読み込む

import キーワードと同等の働きをする import.import_module という関数を使うこともできます。
ライブラリをまとめて読み込みたい場合なんかに便利(?)でしょうか。

import importlib

# 3 つのライブラリを読み込む
libs = ['sys', 'os', 'math']
for lib in libs:
    importlib.import_module(lib)

以上です。


参考
- 6. Simple statements — Python 2.7.8 documentation
- 30.2. importlib – Convenience wrappers for __import__() — Python 公式ドキュメント
- Python - how to refer to relative paths of resources when working with code repository - Stack Overflow
- Relative paths in Python - Stack Overflow
- Python: Get relative path from comparing two absolute paths - Stack Overflow
- Python Packages and You - _habnablog