shell, perl以外まともに使えんので何となくpythonを勉強することにしてみた。perlと比較して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モジュールをインストールする場合は必要になってくる
perlでいうcpanっぽいものらしい。後々必要だと思うのでインストールしておくが、3.x系では公式のeasy_installはインストールできなさそうなので、以下の方法でインストール
http://code.google.com/p/python-incompatibility/do... から取得
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 installPyPIからダウンロードしてインストールしてるんだと思う。ちなみにyumで入れるのなら(実際のところ、ほとんどのモジュールがpython3に対応していないように思う)
yum python-setuptools installとする
wget -O - http://github.com/utahta/pythonbrew/raw/master/pythonbrew-install | bash$HOME/.pythonbrewにインストールされる。install pathを変えたい場合は
export PYTHONBREW_ROOT=/path/to/pythonbrewなどとする
どうも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.3shabangに書く場合は
#!/usr/bin/env python import sys print(sys.version)のように/usr/bin/pythonと書かないこと
pip install virtualenv一応環境変数を用意しておく(virtualenvwrapperを入れていない場合はいらない?)
export WORKON_HOME=$HOME/.virtualenvs echo "export WORKON_HOME=\$HOME/.virtualenvs" >> ~/.bash_profile
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にインストールしたライブラリを使用することができる
プログラムから使うとなると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のフォーマットと同じ。たぶん。
strと似ているが。str()関数は引数で与えた値を人間が読みやすい文字列に、repr()関数は引数で与えた値と等価な値を返すインタプリタ表現(リテラル表記)を文字列として返す。ということらしい。
joinはarray methodだと思っていたら、stringだった
# 区切り文字をメインに考える ",".join(["nirvana', 'melvins', 'muse']) # 文字列でよい。試してないけどtuble型でもいいとか ",".join(["1234567890'])
文字列や数値を整数に変換。一応型があるということを知った。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:])
perlだと@ary[0..1]。文字列のスライスと使い方は同じ
# output is ['one', 'two'] print(a[0:2])これの応用で配列を空にすることもできる
a[:] = []
シーケンス型から配列に変換。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))
perlでいうforeach。shellっぽい
fluits = ['apple', 'banana', 'melon', 'orange', 'lemon'] for fluit in fluits: print(fluit)
loopだが、indexも取得できる
a = ["melvins", "nirvana", "converge", "muse", "mars volta", "at the drive in"] for i, v in enumerate(a): print("%i: %s" % (i, v))
insert(index, data)。指定のindexの位置に挿入。以下はperlでいうunshiftと同じ
fluits.insert(0, 'dragon fluit')appendと同じ
fluits.append(len(fluits), 'dragon fluit')
配列同士を合体
fluits.extend(['mango', 'dragon fluit'])ちなみに合体して新たなlistを作成する場合は以下のようにする
new_fluits = fluits + ['mango', 'dragon fluit']
indexを指定して要素を削除。popが使うことあんまりないような気がするが
# indexが1の要素を削除 del(fluits[1]) # スライスも利用可能 del(fluits[0:2])
ひっくり返す
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する
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(1, 11)とすると1..10までのリストが生成される。10..1のように逆で生成したい場合は
range(10, 0, -1)とする
複数のリストの同じ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 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 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にコピーされる
連想配列
d = {'nirvana': 'Kurt Cobain', 'melvins': 'King Buzzo', 'pealout': 'Tomohiro Kondo', 'muse': 'Matthew Bellamy'}
連想配列に変換する。コピーも可能
# 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])))
key/valueのセットの数を返す。別にmapじゃなくてもlenって配列とか文字列に対しても使えるね
# output is 4 len(d)perlだとscalar+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という関数を使えばよい
items()に似ているが取り出すたびにpairを削除していく
while len(dict) > 0: (key, value) = d.popitem() print(key + ":" + value)
コピーする。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)
listとは少し違うがほぼ同じ。関数からリストを返したい場合とかいい
ループ処理も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"
tuple関数
list = ["muse", "nirvana", "melvins"] t = tuple(list) # strも可能。あんまりないと思うけど # ("A", "B", "C", "D", "E") t = tuple("ABCDE")
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}とするとよい
だいたいわかると思うので省略
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っぽい結果になる
定義されているかどうか。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']
同じものを参照しているか
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と判断されるはず。また文字列同士に対して行うとおかしなことになるようなので、あんまり使用しないほうがいいっぽい
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してくれるようだ
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()
ファイルの先頭に新しい行を挿入したい場合。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()
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となる。
python3系からはデフォルトでunicodeとなるようだ。perlだと
use utf8をしてutf8 flagが有効になるあれ。標準で
str = 'あいうえお' print(len(str))とすると5となる。マルチバイトで文字列分割や正規表現などでいろいろ有効になる。byteとして扱いたい場合は
str = 'あいうえお'.encode('utf-8') print(len(str))encode(<encoding>)を使うとbyte列となりこの場合は15と結果が出力される
もう少し説明追加しよう。byte sequenseに変換するってのが正解らしい
encodeは以下と同じ意味。bytes型の変数を生成するbytesでおんなじことができるようだ
s = "あいうえお" # b'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a' print(s.encode("utf-8"))変換できなかったときに備えて、第2引数に挙動の設定をすることができる
opt | 説明 |
---|---|
strict | default. 変換できなかった場合はエラー |
ignore | 変換できなかった文字を無視 |
replace | 変換できなかった文字を?に変換。元データは消失 |
backslashreplace | 変換できなかった文字を\x \u \Uエスケープに変換される。(データは保持され、ASCIIに変換される) |
encodeは以下と同じ意味。bytes型の変数を生成するbytesでおんなじことができるようだ
b = bytes("あいうえお", encoding="utf-8")
指定したエンコーディングを使って、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 open("test.txt", mode = "r") as f: for line in f: print(line.rstrip(), file=f)同じくwithを抜けると自動的にf.close()してくれる
基本
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)
別名で使いたい。関数自身もオブジェクトなので
# greetingを別名で使用できるようにする hello = greeting hello("kurt")とする。()なしで呼び出せば、実行されずにオブジェクトとして認識される
これはperlでいうpodだが、pythonのほうが洗練されている
testpackage.py
test.py
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"すばらしい
無名関数
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)))
もう少し先で出てくる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()このように書けば同じ意味になるようだ
関数属性が内部関数になってしまうので、decorateされる関数の属性を保持したい場合
import functools def deco(f): @functools.wraps(f) def wrapper(*args, **kwds): res = f(*args) return "*** %s ***" % res return wrapperとすればdecoが返す関数オブジェクトの各属性はfのものになる
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>
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のほうが融通がききそうだ
たとえばファイル処理の場合
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節のところが実行される。これは予想通りの結果。
実際のところは
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と値がはいっていることが確認できる
こういう書き方をする
try: anything to do... except (ZeroDivisionError, IOError) as e: ZeroDivisionErrorとIOErrorが発生した場合 else: anything to do...
こういうことも可能
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を継承していることを利用して
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 zerosys.exc_info()を使用して例外情報を取得。詳細はsysの項目参照
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 <<");
とりあえず適当に書いてみた
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)
ちょっとしたtipsだけど役立ちそうだ
try: import nothing except (RuntimeError, ImportError) as e: pass # or anything to do..
perlと一緒でインスタンスメソッドを定義する場合は第1引数にselfを渡すといいようだ
class MyClass(object): """Plactice Class""" def hello(self, name="melvins"): print("hello %s" % (name)) x = MyClass() x.hello()
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)
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... にその他のメソッドがのっている
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]となる
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変数っぽく宣言することができる
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
特定のクラスの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)
とあるクラスが調べたいクラスのサブクラスに属するか
#class MySuperClass(object): class A(object): pass class B(A): pass class C(B): pass x = C() print(issubclass(C, B))はTrueになる。クラスオブジェクトを渡すことに注意
typeを使うとできる。あんまりいらないだろうけど
def _init(self, name, age): self.name = name self.age = age MyClass = type("MyClass", (object,), { '__init__': _init}) obj = MyClass("kurt cobain", 27)あとは同じ
すでにimport済みの場合はglobalsを使えば可能
importしていない場合は
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)こうすれば可能
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。動的継承で実現できるが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;の形に近いかな
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なんかだと例によって関数リファレンスとしてこのあたりをやり取りすることで実現可能。
evalしかないかなあと思ったらあった
meth = getattr(x, "greeting") # return method object meth()ない場合はAttributeErrorが発生するので先にそもそも存在するかhasattrで確認できる
if hasattr(x, "greeting"): getattr(x, "greeting")()
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)とする
先頭に__をつけるといいようだ
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 と検索されるようだ。
継承したクラスに対してアクセスしたい場合
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
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__プロパティとしてもアクセス可能
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みたいなのはないかな
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");こんな感じになる
こんな感じか。iterとnextを実装すればよい。まああんまり自分で使うことはなさそうだが
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よりiteratorを先に書いたのはgeneratorはiteratorの概念を持ち合わせているから。例えば
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を有効活用することがポイントのような気がするので、理解しておく必要あり
現時点ではあんまり自分で使わなさそうなので、今はパス。とはいえ
あたりに書いているので、必要になればそのあたり。実用的なのは
abc moduleを使えば実装可能。abcを参照
パスが通っているライブラリ(標準ライブラリ)はとりえあず
import osとかで可能。とりあえず自分で使う時は
- os
- sys
import os,sys
perlでいうpackage内の関数をexportする的な感じか
use Bar qw(foo bar)的なやつ。pythonだと
from os import system # os.systemとやらんでもいい system("ls -l")とできる。複数も可能
from os import system, getcwdimportのあとに*(全て)を指定することもできるが、混乱のもとになるので、やめといたほうがよい
別名をつけることができるらしい。あんまりいらんような気がするけど
import os.path as foo # os.path.getsize("/path/to/file") とかせんでいい foo.getsize("/path/to/file")
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()
ディレクトリ構成で多段構成なモジュールにする場合。とりあえず以下の構成にしてみる
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()とする。
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が含まれていることがわかる
タグ
最新コメント