[僕] python アーカイブ

僕ト云フ事

たろマークはてなブックマーク

トップ > python

2012年01月06日

[python]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, in 
    from 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 ファイルを探索可能なところにおいてることになるわけですね。ファイル名気を付けないと。

2011年12月27日

[decorator][python]引数付きの 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

2011年11月07日

[gdata][python]Google Calendar の内容を Spreadsheet へ流す script

仕事で Google Docs の spreadsheet に time sheet をつけなくてはいけないんだけど、いつも Calendar を実績ベースに書き換えて居るので、それを流し込むだけの script 書いた。
月末の提出時に動かしてる。(本当は column がたくさんあったり、適切な sheet 選んだりって処理があったけど省いてる。)

こんなコードなら書いてるなぁ、というカンジ。

2011年10月18日

[pypi][python][texttable]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 変えたりできるっぽい。

textable documentation

2011年08月31日

[python][virtualenv][virtualenvwrapper]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

2011年02月21日

[python]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.451s

OK

reST で概要書いたらそれがそのままテストになるのは面白いなー。
nose は unittest の機能を提供しているパッケージらしい。エキスパート Python プログラミング、6章読んだら、11章読もうかなぁ。

エキスパートPythonプログラミング
Tarek Ziade
アスキー・メディアワークス
売り上げランキング: 9716

2011年02月20日

[python]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 を実行してる。

エキスパートPythonプログラミング
Tarek Ziade
アスキー・メディアワークス
売り上げランキング: 9716

[python]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 はったりするんだけど、環境変数変えた方がいい気がするけどどうなんだろう。


エキスパートPythonプログラミング
Tarek Ziade
アスキー・メディアワークス
売り上げランキング: 9716

2011年02月15日

[python]メソッド一覧を取得する 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?"]

でした。

2011年02月13日

[pylons][python]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 コマンドなの? と言うところはちょっと違和感。

[python]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('/') とかして、デコレータで関数とルーティングのひも付けしてる。

2011年01月26日

[designpattern][python]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 で、前に表示したのを削除して新しく表示させるのがうまくいかなかった。このあたりよく分かってないな……。

[designpattern][python]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() で出力してる。

[designpattern][python]委譲を使った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()
トップ > python