たろマーク (はてなブックマーク)
-
[ api ][ phone ][ webservice ]
- Colorful Bokeh Effect in Pixelmator | Abduzeedo | Graphic Design Inspiration and Photoshop Tutorials
[ pixelmator ] -
[ pixelmator ]
-
[ python ] 結構ボリュームあるw python のみならず、チームの開発サイクルとか、実際にどう活用していくかと言うことが書いてありそうで wktk
■import しようとするパッケージと実行しようとするファイル名がかぶると困ったことになる
あけおめ。
email.py って名前のファイルを作って、中身で from email.mime.text import MIMEText とかしたら、こんな事言われる。
[vkgtaro@cb21-komatsu.local] $ python email.py Traceback (most recent call last): File "email.py", line 1, infrom email.mime.text import MIMEText File "/Users/vkgtaro/Desktop/email.py", line 1, in from email.mime.text import MIMEText ImportError: No module named mime.text
モジュールのパッケージ名と同じ名前の py ファイルを探索可能なところにおいてることになるわけですね。ファイル名気を付けないと。
■引数付きの decorator
三重に関数をネストした decoration 用の関数を作る。
def deco(deco_arg):
def deco_inner(func):
def wrapper(*args, **kwards):
print "before wrapper: %s" % deco_arg
result = func(*args, **kwards)
print "after wrapper: %s" % deco_arg
return result
return wrapper
return deco_inner
んで、こうやると引数使って decorate できる。
@deco("boke")
def hoge(arg):
print "hoge: %s" % arg
hoge("aaa")
実行結果
before wrapper: boke hoge: aaa after wrapper: boke
実際にはこうやってるのと一緒。
def boo(arg):
print "boo: %s" % arg
_deco = deco("bbb")
b = _deco(boo)
b("aaa")
実行結果
before wrapper: bbb boo: aaa after wrapper: bbb
■Google Calendar の内容を Spreadsheet へ流す script
仕事で Google Docs の spreadsheet に time sheet をつけなくてはいけないんだけど、いつも Calendar を実績ベースに書き換えて居るので、それを流し込むだけの script 書いた。
月末の提出時に動かしてる。(本当は column がたくさんあったり、適切な sheet 選んだりって処理があったけど省いてる。)
こんなコードなら書いてるなぁ、というカンジ。
■text な table を作る
そのまま、texttable っていうのが PyPI にある。
pip install textable して、こんなコードを書くと
# -*- coding: utf-8 -*-
from texttable import Texttable
table = Texttable()
table.add_rows([
['id', 'name', 'content'],
[1, 'aaaaa bbbbb', 'hoge'],
[2, 'bbb cccc', 'fuga'],
[3, 'dddd eeee', 'awawa'],
])
print table.draw()
こんな感じで出力できる。
$ python text_table.py +----+-------------+---------+ | id | name | content | +====+=============+=========+ | 1 | aaaaa bbbbb | hoge | +----+-------------+---------+ | 2 | bbb cccc | fuga | +----+-------------+---------+ | 3 | dddd eeee | awawa | +----+-------------+---------+
add_rows() はまとめて行を追加、1行ごとであれば add_row() ってメソッドもある。
set_cols_align() で、各 column の内容の右寄せ/左寄せ/センタリングしたり、
set_cols_valign() で縦方向の位置決め、set_deco() で罫線の style 変えたりできるっぽい。
■virtualenvwrapper で virtualenv な仮想環境を切り替え
また、大分間が開いてしまった……。先日、PyConJP 2011 行ってきて、かなり楽しんできました。やっぱり、こう言うのに参加するとモチベーション上がりますね。
以下、Ubuntu 11.04 上での作業ログです。
まずは easy_install を入れる。(はなから pip があったかもしれない)
sudo apt-get install python-setuptools
virtualenv と virtualenvwrapper を入れる
sudo easy_install pip
sudo pip install virtualenv
sudo pip install virtualenvwrapper
.zshrc-after に以下を追記する。(自分の .zshrc が .zshrc-after を読む設定になってるだけなので、.bashrc や .zshrc などに追記すればいい。)
export WORKON_HOME=~/Envs
source /usr/local/bin/virtualenvwrapper.sh
んで、source .zshrc すると virtualenvwrapper が使う directory を作ってくれる。
これは virtualenvwrapper.sh が、起動時に毎回 directory があるかないかを調べてやってるみたい。
[vkgtaro@ubuntu] $ source .zshrc
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/initialize
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/premkvirtualenv
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/postmkvirtualenv
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/prermvirtualenv
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/postrmvirtualenv
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/predeactivate
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/postdeactivate
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/preactivate
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/postactivate
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/get_env_details
virtualenvwrapper の setup はここまで。
後は環境作ったりを virtualenvwrapper に付属のコマンドで行える。
mkvirtualenv で hoge1 という環境を作る
[vkgtaro@ubuntu] $ mkvirtualenv hoge1
New python executable in hoge1/bin/python
Installing setuptools............done.
Installing pip...............done.
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/hoge1/bin/predeactivate
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/hoge1/bin/postdeactivate
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/hoge1/bin/preactivate
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/hoge1/bin/postactivate
virtualenvwrapper.user_scripts creating /home/vkgtaro/Envs/hoge1/bin/get_env_details
(hoge1)[vkgtaro@ubuntu] $
今作った仮想環境から抜ける
(hoge1)[vkgtaro@ubuntu] $ deactivate
[vkgtaro@ubuntu] $
作成済みの環境を list する
[vkgtaro@ubuntu] $ lsvirtualenv
hoge1
作成済みの仮想環境に切り替え
[vkgtaro@ubuntu] $ workon hoge1
(hoge1)[vkgtaro@ubuntu] $
仮想環境に入った状態で pip とか使うと、その仮想環境に対してインストール出来る
(hoge1)[vkgtaro@ubuntu] $ pip install pyramid
hoge1 には pyramid が入ってる。
(hoge1)[vkgtaro@ubuntu] $ python
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:05:24)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyramid.config import Configurator
>>>
deactive して、仮想環境から抜けてみると pyramid は使えなくなってる。
(hoge1)[vkgtaro@ubuntu] $ deactivate
[vkgtaro@ubuntu] $ python
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:05:24)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyramid.config import Configurator
Traceback (most recent call last):
File "", line 1, in
ImportError: No module named pyramid.config
>>>
かなり楽ちん。しかし、virtualenvwrapper って名前はどうなんだろw
■doctest でテストを書く
README.txt に reST でパッケージの概要を書く
=================
atomisator.parser
=================
parser が提供する最上位関数 'parse' を使い、フィードからコンテンツを取得します。
>>> import os
>>> from atomisator.parser import parse
この館数は、フィード URL を引数に取り、取得したコンテンツをイテレータとして返します。
2つめのパラメータには取得する最大エントリ数を指定できます。
最大エントリ数を指定しなかった場合、最大10件まで取得します::
>>> res = parse(os.path.join(os.path.dirname(__file__), 'sample.xml'))
>>> res #doctest: +ELLIPSIS
<itertools.islice ...>
イテレータの各要素はエントリの情報を含む辞書型の値となります。::
>>> entry = res.next()
>>> entry['title']
u'CSSEdit 2.0 Released'
辞書には以下のキーが格納されています::
>>> keys = sorted(entry.keys())
>>> list(keys)
['id', 'link', 'links', 'summary', 'summary_detail', 'tags', 'title', 'title_detail']
このまま ~/Desktop/my_env/bin/nosetests --with-doctest --doctest-extension=.txt とかするとテストがこける。--with-doctest は、doctest も行う指定、--doctest-extension=.txt は、doctest のファイルの拡張子の指定。んで、__init__.py にこのテストが通るようにコードを書く
from feedparser import parse as feedparse
from itertools import islice
from itertools import imap
def _filter_entry(entry):
"""Filters entry field."""
entry['links'] = [link['href'] for link in entry['links'] ]
return entry
def parse(url, size=10):
"""Returns entries of the feed."""
result = feedparse(url)
return islice(imap(_filter_entry, result['entries']), size)
すると、テストが通る。
$ ~/Desktop/my_env/bin/nosetests --with-doctest --doctest-extension=.txt . ---------------------------------------------------------------------- Ran 1 test in 0.451sOK
reST で概要書いたらそれがそのままテストになるのは面白いなー。
nose は unittest の機能を提供しているパッケージらしい。エキスパート Python プログラミング、6章読んだら、11章読もうかなぁ。
アスキー・メディアワークス
売り上げランキング: 9716
■setup.py に書いた依存関係を PyPI からインストールする
paster コマンドで、新規にプロジェクトを作成する。エキスパート Python プログラミングに習うと、さっきの virtualenv で作った環境に packages というディレクトリを作って、その中で新しく作るのがいいみたい。
$ mkdir packages
$ cd packages
$ paster create -t pbp_package atomisator.parser
/usr/local/bin/paster:5: UserWarning: Module zope was already imported from None, but /System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python is being added to sys.path
from pkg_resources import load_entry_point
Selected and implied templates:
pbp.skels#pbp_package A namespaced package
Variables:
egg: atomisator.parser
package: atomisatorparser
project: atomisator.parser
Enter namespace_package (Namespace package (like pbp)) ['pbp']: atomisator
Enter package (The package contained namespace package (like example)) ['example']: parser
Enter version (Version) ['0.1.0']:
Enter description (One-line description of the package) ['']:
Enter long_description (Multi-line description (in reST)) ['']:
Enter author (Author name) ['']:
Enter author_email (Author email) ['']:
Enter keywords (Space-separated keywords/tags) ['']:
Enter url (URL of homepage) ['']:
Enter license_name (License name) ['GPL']:
Enter zip_safe (True/False: if the package can be distributed as a .zip file) [False]:
Creating template pbp_package
Creating directory ./atomisator.parser
Recursing into +namespace_package+
Creating ./atomisator.parser/atomisator/
Recursing into +package+
Creating ./atomisator.parser/atomisator/parser/
Copying README.txt to ./atomisator.parser/atomisator/parser/README.txt
Copying __init__.py_tmpl to ./atomisator.parser/atomisator/parser/__init__.py
Copying __init__.py_tmpl to ./atomisator.parser/atomisator/__init__.py
Copying setup.py_tmpl to ./atomisator.parser/setup.py
Running /usr/bin/python setup.py egg_info
$ cd atomisator.parser
paster で使っている pbp_package は、PyPI に pbp.skels と言うパッケージ名でアップロードされてるので、pip install pbp.skels した。
んで、atomisator.parser にできた setup.py の install_requires に依存している PyPI パッケージを書く。
install_requires=[
'setuptools',
'feedparser', # <= 追加した
# -*- Extra requirements: -*-
],
その後、python setup.py develop を実行すると、feedparser が install される。
このとき使う python は virtualenv で用意した python の方。エキスパート python だと、/usr/bin/atomisator-python に symlink 張って、atomisator-python を実行してる。
アスキー・メディアワークス
売り上げランキング: 9716
■virtualenv でまっさらな python 環境を作る
システムの pyhton を使用せずに、開発のためのまっさらな python 環境を作成します。
$ cd my_env $ virtualenv --no-site-packages . New python executable in ./bin/python Installing setuptools............done. $ ls -lha bin total 176 drwxr-xr-x 12 vkgtaro staff 408B 2 20 23:04 . drwxr-xr-x 6 vkgtaro staff 204B 2 20 23:04 .. -rw-r--r-- 1 vkgtaro staff 2.1K 2 20 23:04 activate -rw-r--r-- 1 vkgtaro staff 1.0K 2 20 23:04 activate.csh -rw-r--r-- 1 vkgtaro staff 2.8K 2 20 23:04 activate.fish -rw-r--r-- 1 vkgtaro staff 1.0K 2 20 23:04 activate_this.py -rwxr-xr-x 1 vkgtaro staff 308B 2 20 23:04 easy_install -rwxr-xr-x 1 vkgtaro staff 316B 2 20 23:04 easy_install-2.6 -rwxr-xr-x 1 vkgtaro staff 266B 2 20 23:04 pip -rwxr-xr-x 1 vkgtaro staff 274B 2 20 23:04 pip-2.6 -rwxr-xr-x 1 vkgtaro staff 50K 2 20 23:04 python lrwxr-xr-x 1 vkgtaro staff 6B 2 20 23:04 python2.6 -> python
こうすると、 my_env 以下に 独立したインタプリタ環境ができる。--no-site-packages オプションを使うと、すでに easy_install などでインストールされたものは除外して構築される。
virtualenv した後は easy_install などを使用しても、このディレクトリ以下にインストールされるようになる。
エキスパート Python ではこの後、nose インストールしたりして、/usr/bin 以下に symlink はったりするんだけど、環境変数変えた方がいい気がするけどどうなんだろう。
アスキー・メディアワークス
売り上げランキング: 9716
■メソッド一覧を取得する dir
python では、dir 関数で、引数に渡した object の method 一覧が見られる。
>>> class Hoge(object): ... def bar(self): ... pass ... >>> hoge = Hoge() >>> >>> dir(hoge) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar']
ruby だと methods だっけ?
>> class Hoge >> end => nil >> ?> hoge = Hoge.new => #<Hoge:0x101315f40> >> hoge.methods => ["inspect", "tap", "clone", "public_methods", "object_id", "__send__", "instance_variable_defined?", "equal?", "freeze", "extend", "send", "methods", "to_yaml", "hash", "to_yaml_properties", "dup", "to_enum", "instance_variables", "eql?", "instance_eval", "id", "singleton_methods", "taint", "frozen?", "instance_variable_get", "enum_for", "instance_of?", "display", "to_a", "method", "type", "instance_exec", "protected_methods", "==", "===", "taguri", "instance_variable_set", "kind_of?", "respond_to?", "taguri=", "to_s", "class", "private_methods", "=~", "tainted?", "__id__", "untaint", "nil?", "to_yaml_style", "is_a?"]
でした。
■paster
Python Paste プロジェクトの paster コマンドを使うと、python パッケージのひな形が簡単に作れる。perl の Module::Setup みたいなもの。
インストールは
pip install paster
paster create コマンドに -t でテンプレートを指定して package の名前を渡せば ok。
$ paster create -t basic_package lazy_people
Selected and implied templates:
PasteScript#basic_package A basic setuptools-enabled package
Variables:
egg: lazy_people
package: lazy_people
project: lazy_people
Enter version (Version (like 0.1)) ['']:
Enter description (One-line description of the package) ['']: hogehoge
Enter long_description (Multi-line description (in reST)) ['']:
Enter keywords (Space-separated keywords/tags) ['']:
Enter author (Author name) ['']: Daisuke Komatsu
Enter author_email (Author email) ['']: vkg.taro@gmail.com
Enter url (URL of homepage) ['']: http://vkgtaro.jp
Enter license_name (License name) ['']:
Enter zip_safe (True/False: if the package can be distributed as a .zip file) [False]:
Creating template basic_package
Creating directory ./lazy_people
Recursing into +package+
Creating ./lazy_people/lazy_people/
Copying __init__.py to ./lazy_people/lazy_people/__init__.py
Copying setup.cfg to ./lazy_people/setup.cfg
Copying setup.py_tmpl to ./lazy_people/setup.py
Running /usr/bin/python setup.py egg_info
basic_package で聞かれた内容は、setup.py とかに反映されてる。
from setuptools import setup, find_packages
import sys, os
version = '0.0'
setup(name='lazy_people',
version=version,
description="hogehoge",
long_description="""\
""",
classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
keywords='',
author='Daisuke Komatsu',
author_email='vkg.taro@gmail.com',
url='http://vkgtaro.jp',
license='',
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
include_package_data=True,
zip_safe=False,
install_requires=[
# -*- Extra requirements: -*-
],
entry_points="""
# -*- Entry points: -*-
""",
)
Paster は、Pylons という waf のから派生したプロジェクトらしく、デフォルトで、pylons のパッケージも作れる。(先に pylons のインストールしたかも)
$ paster create -t pylons mywabapp $ cd mywebapp $ paster serve --reload development.ini
即座に簡易サーバ立ち上げられるのとかいいんだけど、paster コマンドなの? と言うところはちょっと違和感。
■decolator
Python は、関数定義の前に @decolator ってやると、その関数をラップできる。
>>> def mydecolator(func):
... def _mydecolator(*args, **kw):
... print "call %s(%s, %s)" % (func.__name__, args, kw)
... return func(*args, **kw)
... return _mydecolator
...
>>> @mydecolator
... def hoge(x):
... return x + 1
...
>>> hoge(2)
call hoge((2,), {})
3
Flask は @app.route('/') とかして、デコレータで関数とルーティングのひも付けしてる。
■Observer パターン
今日はここまでー。元ネタは ruby の Observable モジュールを perl + moose で模倣した自分の記事。
ref. [designpattern][moose][perl] perl で Observer パターン
# -*- coding: utf-8 -*-
import sys
import time
import datetime
class Observable():
def __init__(self):
self.__observers = []
self.__state = False
def is_changed (self):
return self.__state
def changed (self):
self.__state = True
def notify_observers (self, args):
if not self.is_changed():
return
self.__state = False
for observer in self.__observers:
try:
observer.update(args)
except Exception, inst:
print type(inst)
print inst.args
print inst
def add_observer(self, obj):
self.__observers.append(obj)
class Tick(Observable):
def start (self):
while True:
now = datetime.datetime.now()
self.changed()
self.notify_observers([now.hour, now.minute, now.second])
time.sleep( 1.0 - (datetime.datetime.now().microsecond / 1000000.0) )
class TextClock():
def update(self, time):
t = "\e[8D%02d:%02d:%02d\n" % tuple(time)
sys.stdout.write(t)
if __name__ == '__main__':
tick = Tick()
tick.add_observer( TextClock() )
tick.start()
TextClock で、前に表示したのを削除して新しく表示させるのがうまくいかなかった。このあたりよく分かってないな……。
■Bridge パターン
ref. http://www.ceres.dti.ne.jp/~kaga/bridge.txt
# -*- coding: utf-8 -*-
import sys
class Display(object):
def __init__(self, impl):
self.__impl = impl
def open(self):
self.__impl.raw_open()
def printf(self):
self.__impl.raw_print()
def close(self):
self.__impl.raw_close()
def display(self):
self.open()
self.printf()
self.close()
class CountDisplay(Display):
def __init__(self,impl):
super(CountDisplay, self).__init__(impl)
def multiDisplay(self,times):
self.open()
for i in range(1,times):
self.printf()
self.close()
class DisplayImpl():
def raw_open(self):
pass
def raw_print(self):
pass
def raw_close(self):
pass
class StringDisplayImpl(DisplayImpl):
def __init__(self,string):
self.__string = string
self.__width = len(self.__string)
def raw_open(self):
self.print_line()
def raw_print(self):
print "|%s|" % self.__string
def raw_close(self):
self.print_line()
def print_line(self):
sys.stdout.write("+")
for i in range(0,self.__width):
sys.stdout.write("-")
print "+"
if __name__ == '__main__':
d1 = Display( StringDisplayImpl("Hello, Japan.") )
d2 = CountDisplay( StringDisplayImpl("Hello, World.") )
d3 = CountDisplay( StringDisplayImpl("Hello, Universe.") )
d1.display()
d2.display()
d3.display()
d3.multiDisplay(5)
python の print は改行がついてくるので、改行して欲しくないところは sys.stdout.write() で出力してる。
■委譲を使ったAdapterパターン
あけましておめでとうございます >_<
去年の blog とかほんとに数えるほどしかなくてひどいw
もうすぐ Pycon mini ということで、少しずつ python に慣れようと言うことで、デザインパターンやってみる。
ref. http://www.ceres.dti.ne.jp/~kaga/adapter2.txt
# -*- coding: utf-8 -*-
class Banner():
def __init__(self, string):
self.__string = string
def show_with_paren(self):
print "(%s)" % self.__string
def show_with_aster(self):
print "*%s*" % self.__string
class PrintBanner():
def __init__(self,string):
self.__banner = Banner(string)
def print1(self):
self.__banner.show_with_paren()
def print2(self):
self.__banner.show_with_aster()
if __name__ == '__main__':
p = PrintBanner('hello')
p.print1()
p.print2()






