hollyさんのwiki

shell, perl以外まともに使えんので何となくpythonを勉強することにしてみた。perlと比較してpythonではこうやるんだ。ってのを書いておく

インストール

python

windowsはとりあえずおいといて、linuxだとrpmで入っているバージョンは古いので、ソースから最新のバージョンをインストールする
cd /usr/local/src
wget http://www.python.org/ftp/python/3.1.2/Python-3.1.2.tar.bz2
tar jxvf Python-3.1.2.tar.bz2
cd Python-3.1.2
./configure
make
途中で
Python build finished, but the necessary bits to build these modules were not found:
_curses            _curses_panel      _dbm
_gdbm              _hashlib           _sqlite3
_ssl               _tkinter           bz2
readline           zlib
とでたので、必要なものをインストール
yum install zlib-devel readline-devel sqlite-devel ncurses-devel openssl-devel gdbm-devel bzip2-devel tk-devel tcl-devel
インストールしてから
make
make install
標準でインストールされているpythonを使うこともあるので、
yum install python-devel
をした。C libraryが関係しているpythonモジュールをインストールする場合は必要になってくる

easy_install

perlでいうcpanっぽいものらしい。後々必要だと思うのでインストールしておくが、3.x系では公式のeasy_installはインストールできなさそうなので、以下の方法でインストール
http://code.google.com/p/python-incompatibility/do... から取得
wget http://python-incompatibility.googlecode.com/files/setuptools-0.7a1dev-r66.tar.gz
tar xvfz setuptools-0.7a1dev-r66.tar.gz 
cd setuptools-0.7a1dev-r66
python3.0 setup.py build
python3.0 setup.py install
PyPIからダウンロードしてインストールしてるんだと思う。ちなみにyumで入れるのなら(実際のところ、ほとんどのモジュールがpython3に対応していないように思う)
yum python-setuptools install
とする

pip

easy_installよりさらに便利なものらしい。とりあえずインストールだけしておく。http://pip.openplans.org/
easy_install pip

pyflakes

正しい文法チェックとかか?3.x系じゃ動かないので、標準pythonでインストールしてみる
/usr/bin/easy_install pyflakes
使い方はpython moduleねた参照

pythonbrew

ソースでpythonをインストールする場合はこっちが正解だろうなあ
インストール
wget -O -  http://github.com/utahta/pythonbrew/raw/master/pythonbrew-install | bash
$HOME/.pythonbrewにインストールされる。install pathを変えたい場合は
export PYTHONBREW_ROOT=/path/to/pythonbrew
などとする
設定
echo ". \$HOME/.pythonbrew/etc/bashrc" >> ~/.bashrc
. ~/.bashrc
patch
どうもmake testで固まってしまうので
--- /home/kurt/.pythonbrew/scripts/pythonbrew/installer.py.org  2011-01-01 00:18:34.000000000 +0900
+++ /home/kurt/.pythonbrew/scripts/pythonbrew/installer.py      2011-01-01 00:19:31.000000000 +0900
@@ -251,7 +251,7 @@
             s.check_call("make")
         else:
             s.check_call("make")
-            s.check_call("make test")
+            #s.check_call("make test")

     def make_install(self):
         version = self.pkg.version
としておく。ちなみに
pythonbrew install 3.2 -f
などとするとmake testを飛ばしてくれる(最近のからか?)
使い方
 pythonbrew help
usage: /home/kurt/.pythonbrew/bin/pythonbrew COMMAND [OPTIONS]

options:
  --version   show program's version number and exit
  -h, --help  Show help

Commands available:
  clean: Remove stale source folders and archives
  help: Show available commands
  install: Build and install the given version of python
  list: List the installed all pythons
  off: Disable pythonbrew
  py: Runs a named python file against specified and/or all pythons
  switch: Switch to the given version of python
  uninstall: Uninstall the given version of python
  update: Upgrades pythonbrew to the latest version
  use: Using the given version of python
  version: Show version

Further Instructions:
  http://github.com/utahta/pythonbrew
だいたいこれみればわかるだろう。インストールは
# v2.7.1 install
pythonbrew install 2.7.1
# v3.1.3 install
pythonbrew install 3.1.3
# v3.2 install どうやらURLで指定すればいけそうだ
pythonbrew install //www.python.org/ftp/python/3.2/Python-3.2.tgz
インストールしたpythonの切り替えは
pythonbrew switch 3.1.3
shabangに書く場合は
#!/usr/bin/env python

import sys
print(sys.version)
のように/usr/bin/pythonと書かないこと

virtualenv

隔離した開発環境を作成するためのもの。実質はpythonbrew + virtualenvで開発していくのがよさそうだ
インストール
pip install virtualenv
一応環境変数を用意しておく(virtualenvwrapperを入れていない場合はいらない?)
export WORKON_HOME=$HOME/.virtualenvs
echo "export WORKON_HOME=\$HOME/.virtualenvs" >> ~/.bash_profile
sandbox作成
virtualenv $WORKON_HOME/sandbox
とするとsandbox配下にpythonやpip, easy_installなどが準備されるので、これらを使用する。この時に
# グローバルな環境にインストールされているpython packageは使用できないようにする
--no-site-package
# distribute ってライブラリもインストールされる。たぶん
--distribute
とつけておくとよさそうだ。
# たとえばFlaskをインストール
$WORKON_HOME/sandbox/bin/pip install Flask
とする。この場合はsandbox/bin/pythonからじゃないとFlaskは使用できないことになる。
活性化
. $WORKON_HOME/sandbox/bin/activate
実行するとコンソールが以下のようになる
 (sandbox)[kurt@pennyroyal-tea ~]$
環境変数PATHを見るとsandboxの中が優先されているのがわかるはず。これでsandboxを意識しなくてもsandboxにインストールしたライブラリを使用することができる
不活性化
いらなくなった場合
deactivate
でよい。コンソールも元に戻るはず
activate_this.py
プログラムから使うとなるとactivate shellを実行せずにしたことにしないといけないので(たとえばmod_wsgiでvirtualenvを使うなど)、その場合は
here = os.path.dirname(os.path.abspath(__file__))
virtualenv = os.path.join(here, '..', 'bin/activate_this.py')
execfile(virtualenv, dict(__file__=virtualenv))
pathは環境によって違うがこのようにするとvirtualenv activateしたことにしてくれる

ソースコードの文字コード

1行目か2行目(#!/usr/bin/python とかを1行目に書くことを考えると2行目が妥当か)
# -*- coding: utf-8 -*- 
or
# vim:fileencoding=utf-8
でもよい

変数展開

% locals()ってやつ
# I love Nirvana. I love No.1
str = "Nirvana"
i = 1;
print("I love %(str)s. I love No.%(i)i" % locals())
文字列の後ろにはs、数値の場合はiなど。printfのフォーマットと同じ。たぶん。

標準入出力

print

基本形。改行を自動でいれてくれる
print("あいうえお")
改行を抑制
print("あいうえお", end=" ")
標準エラー出力
print("あいうえお", file=sys.stderr)
2.x系はsysを使わないといけない
sys.stderr.write("あいうえお\n")
printfみたいなの
たぶん他の言語のprintfのフォーマットと変わらない。たぶん
print("%i. %s" % (1, 'melvins'))

入力

一行入力
inputというものを使う。対話形式などを想定
name = input("Enter name: ")
print(name)
複数入力
sys.stdin使ったほうがいい。sysの項目参照

変数

scalar

普通の変数
s = 'hello world!'
str
数値を文字列に変換するなど。この関数使うのならstrって変数とかは使わないほうがいいかも
i = 1
# output is 101
print("10" + str(1))
repr
strと似ているが。str()関数は引数で与えた値を人間が読みやすい文字列に、repr()関数は引数で与えた値と等価な値を返すインタプリタ表現(リテラル表記)を文字列として返す。ということらしい。
rstrip
末尾の文字列を削除。引数を指定しなかった場合は空白文字が削除される。perlでいうchop/chomp
s.rstrip()
strip
ようはtrim。rstripと同じなので割愛
split
splitです。必須です
s = "a,b,c,d,e"
list = s.split(",")
正規表現でsplitしたい場合はreの項目参照
join
joinはarray methodだと思っていたら、stringだった
# 区切り文字をメインに考える
",".join(["nirvana', 'melvins', 'muse'])
# 文字列でよい。試してないけどtuble型でもいいとか
",".join(["1234567890'])
capitalize
先頭のアルファベットを大文字に変換して返す
# output is Nirvana
"nirvana".capitalize()
uppper
アルファベットすべてを大文字に変換して返す
# output is NIRVANA
"nirvana".uppper()
lower
uppperの反対。使い方は同じなので割愛
replace
文字列置換して返す。単純なものならreは使わなくてもよさそう
s = "i love nirvana"
s.replace("love", "hate")
int
文字列や数値を整数に変換。一応型があるということを知った。perlのintとさほどかわらないので、小数点切捨てとかの用途にもなる
a = "1"
# としないとTypeError
1 + int(a)
文字列のスライス
結構便利だね。これ
s = "hello world!"
# output is "h"
print(s[0])
# output is "hello"
print(s[0:5])
# output is "hello"
print(s[:5])
# output is "world!"
print(s[6:])
sprintfみたいなの
printfみたいなのと同じ
s = "%i. %s" % (1, 'melvins')

list

配列
a = ['one', 'two', 'three']
部分取り出し
perlだと@ary[0..1]。文字列のスライスと使い方は同じ
# output is ['one', 'two']
print(a[0:2])
これの応用で配列を空にすることもできる
a[:] = []
list
シーケンス型から配列に変換。tupleとかmap, filter objectなど。配列のコピーも可能
# from tuple to list
t = (1, 2, 3)
l = list(t)
文字列からも生成可能。一文字ずつ分割するときsplitとかしなくてもいい
s = "nirvana"
# output is ['n', 'i', 'r', 'v', 'a', 'n', 'a']
print(list(s))
loop
perlでいうforeach。shellっぽい
fluits = ['apple', 'banana', 'melon', 'orange', 'lemon']
for fluit in fluits:
    print(fluit)
enumrate
loopだが、indexも取得できる
a = ["melvins", "nirvana", "converge", "muse", "mars volta", "at the drive in"]
for i, v in enumerate(a): print("%i: %s" % (i, v))
append
最後に追加
fluits.append('dragon fluit')
pop
取り出し
fluits.pop()
indexを指定した場合はその指定したindexを除去する。以下はperlでいうshiftと同じ
fluits.pop(0)
insert
insert(index, data)。指定のindexの位置に挿入。以下はperlでいうunshiftと同じ
fluits.insert(0, 'dragon fluit')
appendと同じ
fluits.append(len(fluits), 'dragon fluit')
extend
配列同士を合体
fluits.extend(['mango', 'dragon fluit'])
ちなみに合体して新たなlistを作成する場合は以下のようにする
new_fluits = fluits + ['mango', 'dragon fluit']
del
indexを指定して要素を削除。popが使うことあんまりないような気がするが
# indexが1の要素を削除
del(fluits[1])
# スライスも利用可能
del(fluits[0:2])
remove
値を指定して削除
fluits.remove('banana')
存在しない値を指定した場合は例外(ValueError)が発生するようだ
like php function in_array
phpだとin_array。True or Falseが返ってくる
'apple' in fluits
count
指定した値が含まれている数を調べる。存在しない場合は0で返ってくる
# output is 1
print(fluits.count('lemon'))
reverse
ひっくり返す
a = [1, 100, 2, 4, 56, 3, 300]
a.reverse()
print(a)
# output is [300, 3, 56, 4, 2, 100, 1]
reverse methodは破壊的関数なので、変更した配列をコピーするには
b = reversed(a)
とする。ただし配列ではなくiteratorで返ってくるので、結果を配列として扱いたい場合は
b = [i for i in reversed(a)]
とする
sort
sortする
a = [1, 100, 2, 4, 56, 3, 300]
a.sort()
print(a)
# output is [1, 2, 3, 4, 56, 100, 300]
sort methodは破壊的に変更するので、変更した配列をコピーするには
b = sorted(a)
とする。独自な方法で並べ替えたい場合。例えばIPの4th octetの小さい順に並び変えたい場合
a = ["192.168.1.2", "192.168.1.50", "192.168.1.33", "192.168.1.122"]
a.sort(key=lambda x: int(x.split(".")[3]))
# b = sorted(a, key=lambda x: int(x.split(".")[3])) でもよい
のようにする。さらにこの例で大きい順に並べる場合は
a.sort(key=lambda x: int(x.split(".")[3]), reverse=True)
とする。keyに何をベースに比較を行うかを指定する。perlの独自sortなんかより直感的でよい
range
整数の数値からなるリストを生成したい場合
range(1, 11)
とすると1..10までのリストが生成される。10..1のように逆で生成したい場合は
range(10, 0, -1)
とする
zip
複数のリストの同じindexにあたる要素を合成してtupleで返す。あんま使うことないような気がするけど
a = ["alice in chains", "melvins", "brahman"]
b = ["apple", "melon", "banana"]
c = ["dog", "cat", "bear"]
for x in zip(a, b, c): print(x)
output
('alice in chains', 'apple', 'dog')
('melvins', 'melon', 'cat')
('brahman', 'banana', 'bear')
map
配列のそれぞれの要素に対して処理を行い、map objectを返す。perlだとこんな感じのことをしてみる
my @list = ("melvins", "nirvana", "muse", "converge", "mars volta");
foreach my $e (map { uc($_) } @list) {
    print "$e\n";
}
でpython
def touppers(word):
    return word.upper()

list = ["melvins", "nirvana", "muse", "converge", "mars volta"]
# すべて大文字にして出力する
for e in map(touppers, list): print(e)
関数ポインタを渡しているところはlambdaでもよい
for e in map(lambda x: x.upper(), ["melvins", "nirvana", "muse", "converge", "mars volta"]): print(e)
outputは
MELVINS
NIRVANA
MUSE
CONVERGE
MARS VOLTA
配列の部分分割もできそう。perlでいう@array[0,2,4]
a = ["melvins", "nirvana", "converge", "muse", "mars volta", "at the drive in"]
for word in map(lambda x: a[x], [0, 2, 4]): print(word)
出力は以下となる
melvins
converge
mars volta
filter
配列のそれぞれの要素に対して真偽の処理を行い、真となった要素だけを抽出したfilter objectを返す。perlだとこんな感じのことをしてみる
my @list = ("melvins", "nirvana", "muse", "converge", "mars volta");
# 先頭がmの要素だけ出力
foreach my $e (grep { /^m/ } @list) {
    print "$e\n";
}
でpython
import re

regex = re.compile(r"^m", re.IGNORECASE)

def filtering(x):
    return True if regex.search(x) else False

a = ["melvins", "nirvana", "muse", "converge", "mars volta"]
for e in filter(filtering, a): print(e)
関数ポインタを渡しているところはlambdaでもよい
#! python

# -*- coding: utf-8 -*-
import re

regex = re.compile(r"^m", re.IGNORECASE)
a = ["melvins", "nirvana", "muse", "converge", "mars volta"]
for e in filter(lambda x: True if regex.search(x) else False, a): print(e)
outputは
melvins
muse
mars volta
内包表記
一部の例で書いたが、このほうが処理効率がいいらしい
# 全部大文字にしたい
a = ["nirvana", "melvins", "akiko"]
b = []
for word in a:
    b.append(word.upper())
このようなのは
a = ["nirvana", "melvins", "akiko", "muse"]
b = []
for word in map(lambda x: x.upper(), a):
    b.append(word)
としてもあんまり変わらない。このような場合は
b = [ word.upper() for word in a ]
とするとよい。if文をはさむことも可能で
b = [ word for word in a if word != "akiko" ]
とすればakiko以外の配列のデータがbにコピーされる

dictionary

連想配列
d = {'nirvana': 'Kurt Cobain', 'melvins': 'King Buzzo', 'pealout': 'Tomohiro Kondo', 'muse': 'Matthew Bellamy'}
dict
連想配列に変換する。コピーも可能
# output is {'three': 3, 'two': 2, 'one': 1}
print(dict([["one", 1], ["two", 2], ["three", 3]]))
zipと組み合わせるとこういうやり方もあり。結果は同じ
print(dict(zip(["one", "two", "three"], [1, 2, 3])))
len
key/valueのセットの数を返す。別にmapじゃなくてもlenって配列とか文字列に対しても使えるね
# output is 4
len(d)
perlだとscalar+keysを組み合わせないといけない
update
結合
d.update({'ellegarden': 'Takashi Hosomi'})
exists
perlだとね。arrayの時と同じ。指定したkeyが存在するか
'muse' in d
存在しないか
'muse' not in d
keys
keyのリストを取り出す。が配列としてではなくview objectってやつで返って来るようだ
keys = d.keys()
# <dict_keys object at 0x00B01AA0>
print(keys)
配列ではないが、それなりに操作することは可能っぽい。たとえばよくある
for key in d.keys():
    print(key + ": " + d[key])

# output
nirvana: Kurt Cobain
melvins: King Buzzo
ellegarden: Takashi Hosomi
pealout: Tomohiro Kondo
muse: Matthew Bellamy
ということはできそうだ。arrayに変換したい場合は
keys = list(d.keys())
listという関数を使えばよい
values
値の一覧を返す。keys()と使い方は一緒なので割愛
items
key:valueのpairを返す
for (key, value) in d.items():
    print(key + ":" + value)
popitem
items()に似ているが取り出すたびにpairを削除していく
while len(dict) > 0:
    (key, value) = d.popitem()
    print(key + ":" + value)
pop
指定したkeyの値を取り出して、そのpairを削除
d.pop('muse')
clear
空にする
d.clear()
copy
コピーする。cloneではない。dictでもよい
d1 = {'one': 1, 'three': 3, 'two': 2}
d2 = d1.copy()
d1["four"] = 4

# output is
# {'four': 4, 'three': 3, 'two': 2, 'one': 1}
# {'one': 1, 'three': 3, 'two': 2}
print(d1)
print(d2)
del
配列と同じなので、詳細は割愛

tuple

listとは少し違うがほぼ同じ。関数からリストを返したい場合とかいい
# []ではない
t = ("nirvana", "melvins", "muse")
アクセスする場合も同じ
# nirvana
print(t[0])

# 1
print(t.count("muse"))

ループ処理もlistと同じ
for word in t:
    print(word)

代入はエラーとなる
# TypeError
t[0] = "converge"
sequenceから変換
tuple関数
list = ["muse", "nirvana", "melvins"]
t = tuple(list)

# strも可能。あんまりないと思うけど
# ("A", "B", "C", "D", "E")
t = tuple("ABCDE")

boolean

True or False

nontype

None。perlでいうundef。のようだ。falseとしても一応使えるようだ

scope

global
i = 1
def foo():
    i = 2

foo()
print(i)
この結果は1となってしまう。fooの中のiはlocal変数として認識されているため。
def foo():
    global i
    i = 2
とすればfoo実行後はiの結果は2となる。global変数の一覧を取得するには
globals()
# output is
# {'__builtins__': <module 'builtins' (built-in)>, '__package__': None, 'i': 2, '__name__': '__main__', 'foo': <function foo at 0x00BA1FA8>, '__doc__': None}
とするとよい
local
だいたいわかると思うので省略
def foo():
     global i
     i = 3
     k = 1
     print(locals())

foo()
# output is {'k' : 1}
となる

変数の型

type
# output is <class 'int'>
type(1)
# output is <class 'dict'>
type({"apple": "りんご"})
# output is <class 'bool'>
type(False)
これも同じ
{"apple": "りんご"}.__class__
さらにその変数の型名を取りたい場合
{"apple": "りんご"}.__class__.__name__
とする。perlのrefっぽい結果になる

define

定義されているかどうか。perlだとdefinedでundefじゃないかどうかを確認することができるがpythonはないので、
try:
    val
except:
    val = None

if val is None:
    # anything true execute
else:
    # anything false execute
などとすればよい

メンバー情報

モジュールで定義されているメソッドやプロパティ一覧を表示
dir()
['__builtins__', '__doc__', '__name__', '__package__']
builtinsをdirすると標準で使用できるメンバー一覧を取得できる
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'chr', 'classmethod', 'cmp', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
osモジュールのメンバー一覧とか
import os
dir(os)
['F_OK', 'MutableMapping', 'O_APPEND', 'O_BINARY', 'O_CREAT', 'O_EXCL', 'O_NOINHERIT', 'O_RANDOM', 'O_RDONLY', 'O_RDWR', 'O_SEQUENTIAL', 'O_SHORT_LIVED', 'O_TEMPORARY', 'O_TEXT', 'O_TRUNC', 'O_WRONLY', 'P_DETACH', 'P_NOWAIT', 'P_NOWAITO', 'P_OVERLAY', 'P_WAIT', 'R_OK', 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'TMP_MAX', 'W_OK', 'X_OK', '_Environ', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_copyreg', '_execvpe', '_exists', '_exit', '_get_exports_list', '_keymap', '_make_stat_result', '_make_statvfs_result', '_pickle_stat_result', '_pickle_statvfs_result', '_putenv', '_unsetenv', '_wrap_close', 'abort', 'access', 'altsep', 'chdir', 'chmod', 'close', 'closerange', 'curdir', 'defpath', 'device_encoding', 'devnull', 'dup', 'dup2', 'environ', 'errno', 'error', 'execl', 'execle', 'execlp', 'execlpe', 'execv', 'execve', 'execvp', 'execvpe', 'fdopen', 'fstat', 'fsync', 'getcwd', 'getcwdb', 'getenv', 'getpid', 'isatty', 'linesep', 'listdir', 'lseek', 'lstat', 'makedirs', 'mkdir', 'name', 'open', 'pardir', 'path', 'pathsep', 'pipe', 'popen', 'putenv', 'read', 'remove', 'removedirs', 'rename', 'renames', 'rmdir', 'sep', 'spawnl', 'spawnle', 'spawnv', 'spawnve', 'startfile', 'stat', 'stat_float_times', 'stat_result', 'statvfs_result', 'strerror', 'sys', 'system', 'times', 'umask', 'unlink', 'urandom', 'utime', 'waitpid', 'walk', 'write']

定数

file

現在のファイル名
__file__

name

空間名。よく使われるのはこんな感じ
if __name__ == "__main__":
    # anything to do...

比較

ありきたりなのはまあいいとして

is

同じものを参照しているか
x = [1, 2, 3]
y = [1, 2, 3]
if x is y:
    print("x is y = true")
else:
    print("x is y = false")

# x is y = false
例が
x = [1, 2, 3]
y = x
としている場合はtrueと判断されるはず。また文字列同士に対して行うとおかしなことになるようなので、あんまり使用しないほうがいいっぽい

in

listとかdictとかで使える。すでに例は出してるけど
x = [1, 2, 3]
print(1 in x)
# True

not

もちろん否定
is not
とか
not in

ファイル操作

基本中の基本だ。これわかってないと何もできない

よくあるパターン

open -> 1行ずつ読み込み close
file = "Book1.csv"
f = open(file, "r")
for line in f:
    print(line.rstrip())
f.close()
明示的にcloseしなくても
file = "Book1.csv"
for line in open(file, "r"):
    print(line.rstrip())
でもよい。この場合はfor loopを抜けた時点でガベージコレクションが働いて自動的にcloseしてくれるようだ

一気読み

read
string変数として
data = f.read()
readlines
配列として
data = f.readlines()

書き込み

普通の書き込み
flockはfcntlを呼び出さないといけないようだ。当たり前だがwindowsでは使えない
import fcntl

file = "test.txt"
f = open(file, "w")
fcntl.flock(f, fcntl.LOCK_EX)
print("melvins", file=f)
f.close()
writeというものが使えるようだ
import fcntl

# writeメソッドの場合は自分で改行を出力しないといけない
file = "test.txt"
f = open(file, "w")
fcntl.flock(f, fcntl.LOCK_EX)
f.write("melvins\n")
f.write("melvins\n")
f.close()
writelinesもあり。配列で指定する
lines = ["nirvana\n", "melvins\n", "converge\n"]
f = open(file, "w")
fcntl.flock(f, fcntl.LOCK_EX)
f.writelines(lines)
f.close()
追記
f = open(file, "a")
読み書き
ファイルの先頭に新しい行を挿入したい場合。seekやtruncateもついでに
f = open("test.txt", "r+")
lines = []
for line in f:
    lines.append(line.rstrip())
# ファイルポインタを元に戻して
f.seek(0, 0)
# ファイルを空にする
f.truncate(0)
# museを先頭に追加する
lines.insert(0, "muse")
for line in lines:
    print(line, file=f)
f.close()
ファイルディスクリプタ
fileno。メソッド
f.fileno()
閉じてるか調べる
closed。メソッドではなくプロパティ。True or False
if f.closed:
    print("already closed")
else:
    f.close()
ファイル名
name。プロパティ
f.name

encoding

unicodeの話にもつながってくるけど、日本語が含まれているファイルをopenしようすると
Traceback (most recent call last):
  File "hello.py", line 10, in <module>
    for line in f:
  File "C:\Program Files\Python30\lib\io.py", line 1739, in __next__
    line = self.readline()
  File "C:\Program Files\Python30\lib\io.py", line 1813, in readline
    while self._read_chunk():
  File "C:\Program Files\Python30\lib\io.py", line 1562, in _read_chunk
    self._set_decoded_chars(self._decoder.decode(input_chunk, eof))
  File "C:\Program Files\Python30\lib\io.py", line 1295, in decode
    output = self.decoder.decode(input, final=final)
UnicodeDecodeError: 'cp932' codec can't decode bytes in position 8-9: illegal multibyte sequence
こんなのがでるので、openする時のoptionに
f = open("test.txt", encoding = "utf-8")
のようにするとunicodeとなる。

unicode

python3系からはデフォルトでunicodeとなるようだ。perlだと
use utf8
をしてutf8 flagが有効になるあれ。標準で
str = 'あいうえお'
print(len(str))
とすると5となる。マルチバイトで文字列分割や正規表現などでいろいろ有効になる。byteとして扱いたい場合は
str = 'あいうえお'.encode('utf-8')
print(len(str))
encode(<encoding>)を使うとbyte列となりこの場合は15と結果が出力される

encode

もう少し説明追加しよう。byte sequenseに変換するってのが正解らしい
s = "あいうえお"
# b'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a'
print(s.encode("utf-8"))
変換できなかったときに備えて、第2引数に挙動の設定をすることができる
opt説明
strictdefault. 変換できなかった場合はエラー
ignore変換できなかった文字を無視
replace変換できなかった文字を?に変換。元データは消失
backslashreplace変換できなかった文字を\x \u \Uエスケープに変換される。(データは保持され、ASCIIに変換される)

encodeは以下と同じ意味。bytes型の変数を生成するbytesでおんなじことができるようだ
b = bytes("あいうえお", encoding="utf-8")

decode

指定したエンコーディングを使って、bytesを文字列にデコードする。ということらしい。実質の文字コード変換は
# from utf-8 to euc-jp
s = "あいうえお"
b = s.encode("euc-jp")
s1 = b.decode("euc-jp")

文字コード変換した値を出力

python2.x系なら
# -*- coding: utf-8 -*-

import sys, codecs

b = bytes("あいうえお", encoding="euc-jp")
s1 = b.decode("euc-jp")

sys.stdout = codecs.getwriter('euc-jp')(sys.stdout)
print(s1)
でいけるはずなのだが、python3.xだと
Traceback (most recent call last):
  File "./hello.py", line 11, in <module>
    print(s1)
  File "/usr/local/lib/python3.0/io.py", line 1487, in write
    s.__class__.__name__)
TypeError: can't write bytes to text stream
となってしまうのだが、http://d.hatena.ne.jp/kei10in/20090331/1238520386 に解決方法がのっていた。説明もちゃんと書いてくれている。すばらしい。
# -*- coding: utf-8 -*-

import sys, io

b = bytes("あいうえお", encoding="euc-jp")
s1 = b.decode("euc-jp")

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='euc-jp')
print(s1)
とすると変換した文字列をeuc-jpとして出力することが可能

with

ファイル操作だと以下のように書き換えられる
with open("test.txt", mode = "r") as f:
    for line in f:
        print(line.rstrip(), file=f)
同じくwithを抜けると自動的にf.close()してくれる

関数

perlだとsubとか

def

基本
def greeting (name):
    print("hello %s" % (name))
デフォルトで引数を指定しておく場合
def greeting (name=None):
    print("hello %s" % (name))
引数が不定数
def greetings(*names):
    print("hello " + ",".join(names))

greetings("buzz", "kurt")
こういうふうに渡すこともできる
a = ["banana", "melon", "apple"]
greetings(*a)

不定数のキーワード

def greeting(name=None, **kwds):
	
    if "uppercase" in kwds and kwds['uppercase'] == True:
        name = name.upper()

    print("hello %(name)s" % locals())

# hello BUZZ
greeting("buzz", uppercase=True)
# hello buzz
greeting("buzz", uppercase=False)
# hello buzz
greeting("buzz")

こういうふうに渡すこともできる
d = dict(apple="りんご", banana="ばなな")
greetings("buzz", **d)
結果を返す
他の言語とほぼ同じ
def greeting_str (name=None):
    return "hello %s" % (name)
alias
別名で使いたい。関数自身もオブジェクトなので
# greetingを別名で使用できるようにする
hello = greeting
hello("kurt")
とする。()なしで呼び出せば、実行されずにオブジェクトとして認識される
ドキュメンテーション
これはperlでいうpodだが、pythonのほうが洗練されている
testpackage.py
"""this is description
hello
yahho"""

def greeting(name=None):
    """this is greeting function
    greeting("kurt")
    # output is \"hello kurt\" """
    print("hello %s" %(name))

test.py
#! python

# -*- coding: utf-8 -*-
import testpackage

help(testpackage)
とすると
Help on module testpackage:

NAME
    testpackage

FILE
    d:\python\testpackage.py

DESCRIPTION
    this is description
    hello
    yahho

FUNCTIONS
    greeting(name=None)
        this is greeting function
        greeting("kurt")
        # output is "hello kurt"
すばらしい

lambda

無名関数
def greeting (name):
    print("hello %s" % (name))
greeting("kurt")
これを置き換えると
f = lambda name : print("hello %s" % (name))
f("kurt")
となる。基本は1行で書かないといけないっぽいので大きいlambdaは書けない。書けるのかもだけど。
# こういうことはできるみたいだた
lambda name : (
    print("hello %s" % (name)))

decorator

もう少し先で出てくるpropertyやclassmethodのところでも出てくるやつ。そういう文法だと思ってたが、裏ではこうなっていたらしい。
def hello(name="nanashi"):
    return "hello %(name)s" % locals()
という関数がある。とりあえず返す結果にdecorateしてみる関数を作る
def hello_decorator(orig_def):
    def decorated_def(*args):
        return "***" + orig_def(*args) + "***"
    return decorated_def
あとは
hello = hello_decorator(hello)
print(hello("kurt"))
とすると結果は
***hello kurt***
と出力される。今時な書き方だと
@hello_decorator
def hello(name="nanashi"):
    return "hello %(name)s" % locals()
このように書けば同じ意味になるようだ
functools
関数属性が内部関数になってしまうので、decorateされる関数の属性を保持したい場合
import functools
def deco(f):
    @functools.wraps(f)
    def wrapper(*args, **kwds):
         res = f(*args)
         return "*** %s ***" % res
   return wrapper
とすればdecoが返す関数オブジェクトの各属性はfのものになる
decoratorに引数をとる場合
def deco(arg):
        # print(">>" + arg)
        def wrapper(f):
                def _wrapper(*args, **kwds):
                        res = f(*args)
                        return "*** %s ***" % res
                return _wrapper
        return wrapper

@deco("deco")
def func(name=None):
        return "hello %s" % name
こうみるとわかりにくいがわかりやすくすると
f = deco("aaa")(func)
print(f("kurt"))
こういうことになる

三項演算子

なんかちょっと気持ち悪い書き方
# perlだとres = <match expression> ? <true value> : <false value>
res = <true value> if <match expression> else <false value>

文字列を実行式として評価

exec

外部コマンド実行ではない。注意
code = "f = lambda x: x * x"
exec(code)
# output is 9
print(f(3))

eval

perl使うひとならこっちのがしっくりくるのだが、execの例をevalですると
code = "f = lambda x: x * x"
eval(code)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    f = lambda x: x + 1
      ^
SyntaxError: invalid syntax
となる。代入式は評価できないようなので、
i = 100
code = "i * 100"
result = exec(code)
のように代入しようとしていたところを実際に受け取るようにしてあげれば、これでもよい。execのほうが融通がききそうだ

例外処理

try/catch

たとえばファイル処理の場合
with open("none.txt", mode="r") as f:
    for line in f:
        print(line.strip(), file=f)
と存在しないファイルを読もうとした場合
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python30\lib\io.py", line 278, in __new__
    return open(*args, **kwargs)
  File "C:\Python30\lib\io.py", line 222, in open
    closefd)
  File "C:\Python30\lib\io.py", line 619, in __init__
    _fileio._FileIO.__init__(self, name, mode, closefd)
IOError: [Errno 2] No such file or directory: 'foo.txt'
こんな感じが例外が発生する。この場合はIOError。これをtry/catchで捕捉できるようにすると
file = "foo.txt"

try:
    f = open(file, mode="r")

except IOError as e:
    print(e)
else:
    for line in f:
        print(line.strip())
こんなふうになる。この場合の出力結果は
[Errno 2] No such file or directory: 'foo.txt'
となる。ファイルがある場合はelse節のところが実行される。これは予想通りの結果。
Exceptionのプロパティなど
実際のところは
except IOError as e:
    print(type(e))
    print(dir(e))
のようにして調べるとよい。IOErrorの場合だと
['__cause__', '__class__', '__context__', '__delattr__', '__dict__', '__doc__','__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__','__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__traceback__', 'args', 'errno', 'filename', 'strerror', 'with_traceback']
こんだけある。それぞれの主要と思われるプロパティをみると
(2, 'No such file or directory')  # <- args
2                                 # <- errno
foo.txt                           # <- filename
No such file or directory         # <- strerror
と値がはいっていることが確認できる
expectに複数の例外クラス指定
こういう書き方をする
try:
    anything to do...
except (ZeroDivisionError, IOError) as e:
    ZeroDivisionErrorとIOErrorが発生した場合
else:
    anything to do...
expect自体を複数にわける
こういうことも可能
except IOError as e:
    print(e)
    print(type(e))
    print(dir(e))
    print(e.args)
    print(e.errno)
    print(e.filename)
except ZeroDivisionError as e:
    print(e)
else:
    anything to do...
Exception自体を指定しない場合
すべての例外クラスがExceptionを継承していることを利用して
except Exception as e:
としてしまう。もうひとつは
# python

import sys
from traceback import print_tb, print_exc

try:
    res = 1 / 0
except:

    e         = sys.exc_info()[1]
    traceback = sys.exc_info()[2]

    print(sys.exc_info())
    print("-" * 50)
    print(e)
    print("-" * 50)
    print_tb(traceback)
    print("-" * 50)
    print_exc()
とする。結果は
(<class 'ZeroDivisionError'>, ZeroDivisionError('int division or modulo by zero'
,), <traceback object at 0x00C0AD00>)
--------------------------------------------------
int division or modulo by zero
--------------------------------------------------
  File "hello.py", line 7, in <module>
    res = 1 / 0
--------------------------------------------------
Traceback (most recent call last):
  File "hello.py", line 7, in <module>
    res = 1 / 0
ZeroDivisionError: int division or modulo by zero
sys.exc_info()を使用して例外情報を取得。詳細はsysの項目参照
finally
finallyに記述した処理は必ず実行される
try:
    f = open("foo.txt", mode="r")
    for line in f:
        print(line.strip())
    f.close()
except Exception as e:
    print(e)
finally:
    print(">> this is final execution block <<");
raise
とりあえず適当に書いてみた
class MyError(Exception):
    """Base class for exceptions in this module."""
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)
try:
    raise MyError("raise exception test")
except MyError as e:
    print(e)
カスタム例外クラス
raiseのところでほとんど書いているので言うことないけど、強いて言うと自分で定義する場合は必ず****Errorと名前をつけること
モジュール読み込み失敗の場合
ちょっとしたtipsだけど役立ちそうだ
try:
    import nothing
except (RuntimeError, ImportError) as e:
    pass
    # or anything to do..

class

基本

perlと一緒でインスタンスメソッドを定義する場合は第1引数にselfを渡すといいようだ
class MyClass(object):
    """Plactice Class"""

    def hello(self, name="melvins"):
        print("hello %s" % (name))

x = MyClass()
x.hello()

constructor

initを使う
class MyClass(object):
    """Plactice Class"""

    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def greeting(self):
        print("myname is %s. age is %i" % (self.name, self.age))

x = MyClass("kurt cobain", 27)
x.greeting()
print(x.name)
print(x.age)

destructor

del
class MyClass(object):
    """Plactice Class"""

    def __init__(self, name, age):
        self.name = name;
        self.age  = age;
        print("%s create!\n" % (self.name))

    def __del__(self):
        print("%s destroy!\n" % (self.name))

obj = MyClass("kurt cobain", 27)
とするとどっかでガベージコレクションが働くので実行結果は
kurt cobain create!
kurt cobain destroy!
となる。http://www.python.jp/doc/2.4/ref/customization.htm... にその他のメソッドがのっている

getattr

perlでいうAUTOLOAD。とはいっても厳密にはそうじゃなくあくまで存在しないプロパティを呼び出そうとした場合のAUTOLOAD

class MyClass(object):
    """Plactice Class"""

    def __init__(self, name, age):
        self.name = name;
        self.age  = age;
        print("%s create!\n" % (self.name))

    def __getattr__(self, attr):
        print("non attribute [%s]\n" % (attr))

obj = MyClass("kurt cobain", 27)
obj.missing_attr
とすると
non attribute [missing_attr]
となる

setattr

getattrの反対
class MyClass(object):
    """Plactice Class"""

    def __init__(self, name, age):
        self.__dict__["_" + self.__class__.__name__ + "__name"] = name
        self.__dict__["_" + self.__class__.__name__ + "__age"] = age

    def __getattr__(self, attr):
        attrname = "_%s__%s" % (self.__class__.__name__, attr)
        return self.__dict__[attrname] if attrname in self.__dict__ else None

    def __setattr__(self, attr, val):
        attrname = "_%s__%s" % (self.__class__.__name__, attr)
        self.__dict__[attrname] = val

obj = MyClass("kurt cobain", 27)

print(obj.name);
print(obj.age);
obj.rock = "grunge"
print(obj.rock)
とするとプライベート変数にアクセスしたけど、直接プロパティにアクセスしたようにみえる。外からprivate変数をpublic変数っぽく宣言することができる

dict

プロパティに対する別の方法でのアクセス。setattr項目参照

property

getattr/setattrでやったことを別の表記で。いわゆるaccessor
class MyClass(object):
    """Plactice Class"""
    def __init__(self, name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_name(self, name):
        self.__name = name

    def delete_name(self):
        self.__name = None

    name = property(get_name, set_name, delete_name, "name property")

obj = MyClass("kurt cobain")

obj.name = "king buzzo"
print(obj.name)
del obj.name
別の書き方だと
class MyClass(object): 
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, name):
        self.__name = name

    @name.deleter
    def name(self):
        self.__name = None

x = MyClass("kurt")
print(x.name)
x.name = "melvins"
print(x.name)
del x.name

isinstance

特定のクラスのinstanceか確認
x = MyClass("kurt cobain", 27)

if isinstance(x, MyClass):
    print("x is MyClass instance")
# 継承しているクラスを指定してもTrueが返ってくる
if isinstance(x, MySuperClass):
    print("x is MySuperClass instance")
perlでいう$obj->isa("Klass") に該当するようなことは一応確認可能か。ちょっと違う気もするが。もうひとつ余談でisinstanceは変数の型を調べる時に普通に使える。と思う。
# こんなんとか
isinstance([1, 2, 3], list)

issubclass

とあるクラスが調べたいクラスのサブクラスに属するか
#class MySuperClass(object):
class A(object): pass

class B(A): pass

class C(B): pass

x = C()
print(issubclass(C, B))
はTrueになる。クラスオブジェクトを渡すことに注意

dynamic

dynamic class
typeを使うとできる。あんまりいらないだろうけど
def _init(self, name, age):
    self.name = name
    self.age = age

MyClass = type("MyClass", (object,), { '__init__': _init})
obj = MyClass("kurt cobain", 27)
あとは同じ
dynamic loading
すでにimport済みの場合はglobalsを使えば可能
class MyClass(object): pass

klass = globals()['MyClass']
x = klass()
とすればMyClassのinstanceを生成したことになる
importしていない場合は
import http.client
conn = http.client.HTTPConnection("www.yahoo.co.jp", 80)
例えばこういうことをしたい場合は
path_to_class = "http.client.HTTPConnection"
target = path_to_class.split(".")
# ("http", "http.client", "HTTPConnection")
(package, module, cls_name) = (target[0], ".".join(target[:-1]), target[-1])
klass = getattr(__import__(module, fromlist=[package]), cls_name)
conn = klass("www.yahoo.co.jp", 80)
こうすれば可能
dynamic inherit
perlでいう
unshift @Package::ISA, "OtherPackage";
pythonだと
class A(object): pass

class B(object): pass

B.__bases__ += (A, )
# x = B(); x.__class__.__bases__ += (A, ) でもよい
動的に継承が可能。ただしpython3系だとエラーになる。同じことをしようとすると
TypeError: Cannot create a consistent method resolution
order (MRO) for bases object, A
現在調査中
mixin
いわゆるmixin。動的継承で実現できるがpython3はエラーになるので今は仮で。実質動的にmixinできるようにするのが目的なので
def mixin(base, *mixclasses):

    for mixclass in mixclasses:
        for item, val in mixclass.__dict__.items():

            if item == "__dict__" or item == "__doc__":
                continue
            try:
                setattr(base, item, val)
            except AttributeError as e:
                print(e, file=sys.stderr)
                pass
            except:
                print("other exception")
という関数を作ればとりあえず目的はやや達成。使い方は
x = MyClass()
# or mixin(MyClass, MyHyperClass, MySuperClass)
mixin(x.__class__, MyHyperClass, MySuperClass)
のようにすればよい。継承ではなくperlでいう
*{"$pkg\::method"} = \&method;
の形に近いかな
mixinその2
class MyClass(object):
    pass

class MyHyperClass(object):
    def hello(self, name):
        print("hello %s" % (name))

x = MyClass()
y = MyHyperClass()
x.hello = y.hello
x.hello("kurt")
とするとMyHyperClass#hello メソッドをMyClassでも使うことができる。この場合はメソッドが実行されずにメソッドオブジェクトをやり取りしたことになる。perlなんかだと例によって関数リファレンスとしてこのあたりをやり取りすることで実現可能。

dynamic method call

evalしかないかなあと思ったらあった
meth = getattr(x, "greeting")
# return method object
meth()
ない場合はAttributeErrorが発生するので先にそもそも存在するかhasattrで確認できる
if hasattr(x, "greeting"): getattr(x, "greeting")()
dynamic method install
setattr
setattr(x, "goodevening", lambda name: print("good evening. %s" % (name)))
クラスに対して追加したい場合は
setattr(MyClass, "greeting", (lambda self, name: print("good morning. %s!\n" % (name))))
とする。下のtypes.MethodTypeを使うかは好みやね。types.MethodTypeというモジュールを使えば、setattrと同じことができる
# すでにMyClassがあるとして
obj = MyClass("kurt cobain", 27)
obj.greeting = MethodType((lambda self, name: print("good morning. %s!\n" % (name))), obj)
obj.greeting("kurt")
print(obj.greeting)
この時のobj.greetingはあくまでobj(MyClass) instanceに対して追加にしただけ。MyClassに対してメソッドを追加したわけではないので、そうしたい場合は
MyClass.greeting = MethodType((lambda self, name: print("good morning. %s!\n" % (name))), MyClass)
とする

private property and method

先頭に__をつけるといいようだ
class MySuperClass(object):
    """Super Class"""

    def __init__(self, name, age):
        self.name = name
        self.age  = age
        self.__private = "aiueo";

    def __private_method(self):
        print("this is %s private method" % (x.__module__))
    def goodbye(self):
        self.__private_method()
        print("goodbye %s!" % (self.name))
protectedは存在しないようなので、先頭を_にするってルールにしておくといいと思う。ただし正確には完全にはprivateにはなってなくて、dirでメンバーを見てみると
# 他にもあるけど省略
['_MySuperClass__private', '_MySuperClass__private_method']
と名前が変わっただけで、実は外からアクセスは可能。ただやらないほうがいいでしょう。せっかく隠蔽してることやし

継承

class MySuperClass(object):
    """Super Class"""

    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def goodbye(self):
        print("goodbye %s!" % (self.name))

class MyClass(MySuperClass):
    """Plactice Class"""

    def greeting(self):
        print("myname is %s. age is %i" % (self.name, self.age))
多重継承
perlと同じだ。うれしい
class MySuperClass(object):
    """Super Class"""

    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def goodbye(self):
        print("goodbye %s!" % (self.name))

class MyHyperClass(object):
    """Hyper Class"""
    def breed(self):
        print("I don't care ? X5 Care if it's old")

class MyClass(MySuperClass, MyHyperClass):
    """Plactice Class"""

    def greeting(self):
        print("myname is %s. age is %i" % (self.name, self.age))
MyClass -> MySuperClass -> MyHyperClass と検索されるようだ。
super
継承したクラスに対してアクセスしたい場合
class MySuperClass(object):
    """Super Class"""

    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def helloworld(self):
        print("%s hello, %s" % (__class__, self.name))


class MyClass(MySuperClass):
    """Plactice Class"""

    def greeting(self):
        print("myname is %s. age is %i" % (self.name, self.age))

    def helloworld(self):
        print("%s hello, %s" % (__class__, self.name))
        super(self.__class__, self).helloworld()


x = MyClass("kurt cobain", 27)
x.helloworld()
result
<class '__main__.MyClass'> hello, kurt cobain
<class '__main__.MySuperClass'> hello, kurt cobain

mro

Method Resolution Order。多重継承できる言語だと問題になるあれ。でpythonはクラスを宣言するとそれを自分で確認できるようだ
class A(object): pass

class B(A): pass

class C(A): pass

class D(B, C): pass
いわゆる
    A
   / \
  B   C
   \ /
    D
ダイアモンド継承型の時のメソッド検索順のアルゴリズム。で検索する順番は
print(D.mro())
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
D, B, C, Aになるはず。methodではなく
D.__mro__
プロパティとしてもアクセス可能
mro + super
class MySuperClass(object):
    def __init__(self, name):
        self.name = name

    def goodnight(self):
        print("MySuperClass goodnight %s" % (self.name))

class MyHyperClass(MySuperClass):
    def goodnight(self):
        print("%s goodnight %s" % (__class__.__name__, self.name))
        super(__class__, self).goodnight()

class MySpecialClass(MySuperClass):
    def goodnight(self):
        print("%s goodnight %s" % (__class__.__name__, self.name))
        super(__class__, self).goodnight()

class MyClass(MyHyperClass, MySpecialClass):
    def goodnight(self):
        print("%s goodnight %s" % (__class__.__name__, self.name))
        super(__class__, self).goodnight()

obj = MyClass("kurt cobain")
obj.goodnight()
とすると結果は
MyClass goodnight kurt cobain
MyHyperClass goodnight kurt cobain
MySpecialClass goodnight kurt cobain
MySuperClass goodnight kurt cobain
となる。mro()の結果通りにメソッドが実行される。perlでいうClass::C3とかmroみたいなのはないかな

class method

newしなくても実行できるメソッド
class MyClass(object):

    def hello(cls, name):
        print("hello %s" % name)
    hello = classmethod(hello)

MyClass.hello("kurt")
accessorと同じく
class MyClass(object):

    @classmethod
    def hello(cls, name):
        print("hello %s" % name)

と書くこともできる。こっちのがいいね。@staticmethodというものもある
class MyClass(object):

    @staticmethod
    def hello(name):
        print("hello %s" % name)

第1引数にclsは必要ない。perlだと呼び出す時に
# class method
MyClass->hello("kurt");
# static method
MyClass::hello("kurt");
こんな感じになる

iterator

こんな感じか。iternextを実装すればよい。まああんまり自分で使うことはなさそうだが
class MyIterator(object):
    "Iterator for looping over a sequence backwards"
    def __init__(self):
        self.data = []
        self.index = 0

    def append(self, data):
        self.data.append(data)
        return self

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration

        res = self.current()
        self.index += 1
        return res

    def rewind(self):
        self.index = len(self.data)
        return self

    def current(self):
        return self.data[self.index]

it = MyIterator()
it.append("melvins").append("nirvana").append("clock")

for res in it:
    print(res)
iter関数があるのでそれを使ってもよい。例によって使うことはほとんどなさそうなのでかかない

generator

コルーチンなるものか
def counter(x):
    while True:
        yield(x)
        x += 1

f = counter(1)
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
結果は
1
2
3
4
5
6
7
8
9
10
関数を中断したところから再開できるイメージか。使い方がなんとなくおぼろげだが、使いこなすとかなりいけそう。http://diveintopython3.org/generators.html#generat...とかに実際に使われ方がのっている。

generatorよりiteratorを先に書いたのはgeneratorはiteratorの概念を持ち合わせているから。例えば
def make_gen():
    yield("one")
    yield("two")
    yield("three")
    yield("four")
    yield("five")

for word in make_gen(): print(word)
はだいたい想像するとおりの結果になる。pythonはなんとなくiteratorを有効活用することがポイントのような気がするので、理解しておく必要あり

metaclass

現時点ではあんまり自分で使わなさそうなので、今はパス。とはいえ あたりに書いているので、必要になればそのあたり。実用的なのは

abstract method

abc moduleを使えば実装可能。abcを参照

モジュール

perlだとrequireとかuseとかで呼び出すやつ

install package一覧

help("modules")
でみれる。
help("modules $pkg")
で指定したsub packageが一覧表示

import

パスが通っているライブラリ(標準ライブラリ)はとりえあず
import os
とかで可能。とりあえず自分で使う時は
  • os
  • sys
はとりあえず読み込んでおくほうがよさそうだ。まとめて呼び出すことも可能
import os,sys

from $module import $method

perlでいうpackage内の関数をexportする的な感じか
use Bar qw(foo bar)
的なやつ。pythonだと
from os import system
# os.systemとやらんでもいい
system("ls -l")
とできる。複数も可能
from os import system, getcwd
importのあとに*(全て)を指定することもできるが、混乱のもとになるので、やめといたほうがよい

as

別名をつけることができるらしい。あんまりいらんような気がするけど
import os.path as foo
# os.path.getsize("/path/to/file") とかせんでいい
foo.getsize("/path/to/file")

動的import

builtin関数のimportを使うと可能
mod = "os"
os = __import__(mod)
print(os.environ['PATH'])
execを使えば
mod = "os"
exec("import %s" % (mod))
print(os.environ['PATH'])
とすることも出来るが実行時にコンパイルされて処理が遅くなるので、importのほうがよい

自作する

sys.pathが通っているところなら、importで呼び出すことが可能。とりあえずカレントディレクトリにmyapp.pyというファイルを作成する
def hello_world():
    print("hello world!")
というファイルを作成する。呼び出す場合は
import myapp

myapp.hello_world()
とすればよい。pythonはファイル名がモジュール名となるようだ
多段構成なモジュール
osモジュールなんかでもそうだが
import os
import os.path
みたいにしたい場合。osはどうしているかというとsys.modulesという機能を使っているようで
if 'posix' in _names:
    name = 'posix'
    linesep = '\n'
    from posix import *
    try:
        from posix import _exit
    except ImportError:
        pass
    import posixpath as path

    import posix
    __all__.extend(_get_exports_list(posix))
    del posix
# _namesごとに違うモジュールをほんまは呼び出している。こんなところでモジュール呼び出しのaliasが使われていて、こういうふうに使うのかと思った
sys.modules['os.path'] = path
というようにすると1ファイルで多段構成のモジュールにすることができる。なのでsuperapp.pyというファイルを作り
# superapp package
def hello_superworld():
    print("hello superworld!")
として、myapp.pyで
import sys
import superapp

sys.modules['myapp.superapp'] = superapp
とする。あとは実行するスクリプトで以下のように呼び出すことができる
import myapp
import myapp.superapp

myapp.hello_world()
myapp.superapp.hello_superworld()

# めんどくさいなら↓でもよい
#from myapp import hello_world
#from myapp.superapp import hello_superworld
#hello_world()
#hello_superworld()
init.py使用版
ディレクトリ構成で多段構成なモジュールにする場合。とりあえず以下の構成にしてみる
myapp
    `
     |-- __init__.py
     |
      `-- hello.py
とする。ここで肝となるのは必ずinit.pyが空でも必要となる。じゃないとmyapp.helloはimportできない。とりあえずmyapp/hello.pyは
class Hello(object):

    def __init__(self, name):
        self.__name = name

    def hello(self):
        print("hello %s" % (self.__name))

とする呼び出し側は
import myapp.hello
x = myapp.hello.Hello("kurt")
x.hello()
とするか
from myapp.hello import Hello
Hello("kurt").hello()
とする。
名前空間
init.pyに
VERSION = 1.0
みたいな変数を書いた場合にこの変数にアクセスする場合は
myapp.VERSION
でアクセスすることができる。関数も同じ。だと思う
all
from $module import *で呼ばれたときにinit.pyにはない要素でexportしたい要素を指定する。init.pyを以下のように編集
VERSION = 1.0
__all__ = ["hello", "VERSION"]
とすると
from myapp import *
とした場合は
print(VERSION)
hello.Hello("melvins").hello()
として実行することができる。
sys.modules.keys()
で確認するとmyapp.helloが含まれていることがわかる
タグ

Wiki内検索

Menu

ここは自由に編集できるエリアです。

管理人/副管理人のみ編集できます