ACER AspireOne 753購入
去年はASUSだったので、今年はACERということで、49800円のときに2GBのDDR3メモリとともに AO753をamazonで購入しました。
- 出版社/メーカー: 日本エイサー
- 発売日: 2010/07/02
- メディア: Personal Computers
- 購入: 2人 クリック: 457回
- この商品を含むブログ (4件) を見る
BUFFALO ノート用増設メモリ PC3-8500(DDR3-1066) 2GB D3N1066-2G/E
- 出版社/メーカー: バッファロー
- 発売日: 2009/12/11
- メディア: Personal Computers
- 購入: 44人 クリック: 441回
- この商品を含むブログ (11件) を見る
届いて開封してみると、メモリスロットカバーのネジに保障封印がしてありました。ちょっと迷ったけど、保障なんて受けたことないしいいやと思い封印を破りメモリ増設しました。そのカバーには、Windowsのライセンスシールの中央の上あたりに爪もついているので、ネジを緩めるだけでははがれず、つめをはずすのに苦労しました。
メモリ増設後のパフォーマンス エクスペリエンスインデックスは以下のとおりです。
1世代前であるCeleron U2300機で、オーバークロック済みのUL20AのパフォーマンスインデックスはASUS UL20A届いた - ラシウラにあるとおりですが、ベースとしてみればCeleron U3400機は、旧アーキテクチャにくらべ全体的にパフォーマンスがあがっているようです。
ASUSとの比較をすると、ACERよりもASUSのほうが評価は上です。というのもメモリ増設の封印してあるのは、はっきりいってほかの評価をどうでもよくするほどのマイナス評価です。ASUSはほかにもオーバークロックできたりするのもプラスです。逆にACERのBIOSはほとんど何もできません。
つくりも若干安っぽく、ACアダプタは立体的だし、キーボードはぺこぺこさがあるし、液晶背面も貧弱で背面でも指でつかむと画面がすぐへこみますし、スピーカーもUL20Aのほうが音がよいです。とはいえ、これはASUSのが値段のわりにすばらしいのだと思ったほうがいいでしょう。あと無駄なプレインストール体験版もASUSにくらべ多いです。
一方、ACER機のいい面は小ささと軽さ、キーボードのPageUp PageDownが独立キーになっている、タッチパネルの左右クリックボタンが分離している点(押すのに力が要らない、同時押しがしやすい)、運搬用ケースがついてる、というデザイン面でしょうでしょうか。
今見るとAmazonでの値段も値上がりしたようなので、ASUSのUL20FTのほうがいいかもしれません。
ASUS UL20FT 12.1型ワイド ノートPC Office無 Windows7搭載 シルバー UL20FT-2X034V
- 出版社/メーカー: Asustek
- 発売日: 2010/07/17
- メディア: Personal Computers
- 購入: 2人 クリック: 795回
- この商品を含むブログ (3件) を見る
Python 2.6以降で作ったコードを 2.5へ対応するときに引っかかる点
python-specfor · PyPI を作るとき、Python2.6と3.1を中心に書いてました。
これを2.5にも対応させたのですが、そのときその差が意外と大きかったのが新鮮だったのでメモ。
with文
2.5では、with文を有効にするには、そのファイルで__future__指定する必要があります。
from __future__ import with_statement
これは今回の中で一番分かりやすかった違いですが、specfor自体がwith文を使わせるものであるため、そこそこ多くのファイルに埋めこむことになりました。
namedtuple
collections.namedtupleも2.6からの機能です。
自らはnamedtuple型を定義しなかったのですが、標準モジュールのほうで結構使っていて、それに依存したコードがありました。
対策A: 代入時tuple展開
# difflib.SequenceMatcher.get_matching_blocks()の戻り値 macthesにて for match in matches: vindex = match.a + match.size
を以下のようにする
# difflib.SequenceMatcher.get_matching_blocks()の戻り値 macthesにて for a, b, size in matches: vindex = a + size
対策B: classを作る
matchはループ中でのみ使うものだったので、展開するのが楽です。
しかし、tupleを持ち運んで使っている場合もあって、その場合には、同じインタフェースを持ったclassを作成しました。
class funcspec(object): def __init__(self, argspec): self.args, self.varargs, self.keywords, self.defaults = argspec pass pass def getargspec(func): import inspect return funcspec(inspect.getargspec(func))
argspecがnamedtupleですが、それをfuncspecクラスで同じ名前のメンバーとなるよう調整しています。
相対import
python2.5は2.6以降にくらべ、相対importの能力が低いです。
from .framework import * # 2.5ではここで*は使えない。
# 2.5の場合、__main__モジュールでは、-mオプション経由の起動でも、相対importが使えない from . import version def main(): ... if __name__ == "__main__": main()
これは、以下のように対策しました
from .framework import spec # 個別の名前で指定する
# main内で、絶対importを使う def main(): from specfor import version ... if __name__ == "__main__": main()
python3用とpython2用のmultipleなdebパッケージを作るubuntuパッケージの作り方
debパッケージの作るのにはdebianディレクトリ以下の記述ファイルが多く必要で、その管理のためにコマンドやツールを多用したりするため、(rpmのspec作成がコピペから始められるのに比べると、)最初のものを用意するまでに多くの知識を得る必要があります。
そして、pythonパッケージを作る、python2系だけじゃなくpython3系でも使えるようにするパッケージの作るための情報というのは特に少なく、他の構成でのやり方をいろいろ試していきながらうまくいく方法を得ました。
この記事では、python-helloソースから、python2系用のpython-helloパッケージと、python3系用のpython3-helloパッケージを同時に作成することを想定したもので、応用可能な方法を記述していきます。
パッケージ対象
debの元となるパッケージは、python2でもpython3でも、同一のsetup.pyでbuild/installできるpythonパッケージである必要があります。
こうになっていればpure pythonモジュールでも、dllモジュールでも基本は同じやり方でdebパッケージ化できます。
例題: python-helloのdebパッケージ化
以下のような簡単な3ファイルだけで構成されたpythonパッケージを例に、debの作り方を説明します。
- python-hello/hello.py
def world(): return "Hello World!"
- python-hello/setup.py
from distutils.core import setup setup( name="hello", version="1.0.0", py_modules=["hello"], )
- python-hello/README.txt
module example: hello
dh_makeによるdebianディレクトリ雛形作成
まずディレクトリ名をpackagename-versionとなるように変更し、その中でdh_makeします。
mv python-hello python-hello-1.0.0 cd python-hello-1.0.0 dh_make --createorig -b -c bsd rm debian/*.ex debian/*.EX rm debian/docs rm debian/README.source
(以下、このカレントディレクトリから、すべてコマンドを実行していきます)
man dh_makeで出てくるオプションをつけることで、例えば"-c bsd"とすることでライセンス情報なども含んだ雛形が作れます。
dh_makeをすると、いっぱいファイルが出来ますが、生成されるファイルのうち*.exや*.EXは追加処理用のテンプレートであり、不要なので全部消します。docsファイルもmultipleパッケージでは、バイナリパッケージごとに用意することになるので消します。
また、debian/README.sourceも特に書く事がないのであれば消します。すると、以下のファイルだけが残ることになります。
以下これらのファイルが適切なものになるよう編集していくことになります。
まず、debian/README.Debianとdebian/copyrightを適切に編集します。"<"と">"で括られた箇所は何か書けと書いてある部分であり、そこを埋めるか削るかします。
comaptファイルは、このdebianディレクトリ下ファイルの仕様バージョン(debhelperのバージョン)です。ふつうそのままでOKです。
debian/changelog の編集
changelogファイルは生成バイナリパッケージのバージョン情報となるので、適切に編集していく必要があります。
changelogを編集するためのコマンドdchがあるので、それを使うのがいいでしょう。
dch -v 1.0.0-1nmu1
このコマンドでは、雛形が埋められてエディタが立ち上がります。そのまま編集してから、保存終了させます。changelogエントリは、たとえば以下のように書きます。
python-hello (1.0.0-1nmu1) lucid; urgency=low * packaging for ubuntu -- bellbind <bellbind@gmail.com> Wed, 28 Jul 2010 23:58:57 +0900
"nmu"とはNone Maintainers Updateの略で、野良パッケージではこれをパッケージバージョンに入れておけば、チェックでいろいろ警告がでるのを抑えることができます。
debian/rules の編集
debian/rulesは、本来ビルドやインストールの方法を書くファイルです。
標準では以下の3行にします。
#!/usr/bin/make -f %: dh $@
pythonパッケージで、setup.pyが使える場合、debian/rulesは以下の五行にしておけば良いです。
#!/usr/bin/make -f DEB_PYTHON_SYSTEM=pysupport include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/python-distutils.mk DEB_COMPRESS_EXCLUDE := .py
debian/control の編集
このファイルには、ソースパッケージとバイナリパッケージの説明や依存関係等の情報を記述します。
このソースパッケージの情報をもとにビルドし、インストール時は、その下のバイナリパッケージの情報に基づいて管理されます。
python-helloのcontrolファイルの全体を書いておきます。
このファイルだけは、パッケージ化するpythonモジュールがpure pythonだけか、native moduleを含むかで若干記述が変わるので、両方載せておきます。
pure python module用 debian/control
Source: python-hello Section: python Priority: extra Maintainer: bellbind <bellbind@gmail.com> Build-Depends: debhelper (>= 7), python-support, python-setuptools, python3-setuptools Standards-Version: 3.8.4 XS-Python-Version: 2.6, 3.1 Homepage: http://example.com/python-hello Package: python-hello Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, python Description: Example python module pakage Usage: . import hello print(hello.world()) . Package: python3-hello Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, python3 Description: Example python module pakage Usage: . import hello print(hello.world()) .
重要なポイントは、XS-Python-Versionにpython2とpython3の両方のバージョンを書くことです。Build-DependsとDependsも適切なものを指定する必要があります。
native module用debian/control
Source: python-hello Section: python Priority: extra Maintainer: bellbind <bellbind@gmail.com> Build-Depends: debhelper (>= 7), python-support, python2.6-dev, python3.1-dev, python-setuptools, python3-setuptools Standards-Version: 3.8.4 XS-Python-Version: 2.6, 3.1 Homepage: http://example.com/python-hello Package: python2.6-hello Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, python2.6 Description: Example python module pakage Usage: . import hello print(hello.world()) . Package: python3.1-hello Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, python3.1 Description: Example python module pakage Usage: . import hello print(hello.world()) .
pure python版との違いは、以下3点だけです(debian/rules, .install等も変更不要です)。
- バイナリパッケージをPythonのバイナリバージョンごとに用意する(python2系でもpython2.6とpython2.7で別パッケージにする必要がある)
- Archtecture: allを Archtecture: any にする(もしくは特定のアーキテクチャ名をリストアップ)
- Build-Depends に python2.6-dev, python3.1-devを入れる
2.6系と3.1系バイナリでメジャーパッケージのProvidesを設定してもよいでしょう。
Package: python2.6-hello Provides: python-hello ...
将来、2.7系がpythonのメジャーパッケージに変わったらReplacesを設定して置き換えることになります。たとえば、1.0.1からpython2.7系をpython-helloのメインにする場合以下のようになります。
Package: python2.7-hello Provides: python-hello Replaces: python-hello (<< 1.0.1) ...
追加ファイル: packagename.install
マルチバイナリパッケージの場合、debian/tmp以下にinstall後のファイル構造が作られます。
その中にあるファイルを各バイナリパッケージに振り分ける必要があります。
それを指定するのが、*.installファイルです。ディレクトリトップからのファイルglobパターンで記述します。
この例では、バイナリパッケージは、python-helloとpython3-helloがあるので、
debian/tmp/usr/lib/python2.6/*
- debian/python3-hello.install
debian/tmp/usr/lib/python3.1/*
を用意します。
追加ファイル: packagename.docs
同様に、パッケージの追加ドキュメントになるファイルは、*.docsファイルで指定します。
README.txt
- debian/python3-hello.docs
README.txt
確認
ここまでできていれば、ファイル構成は以下のようになっているはずです。
- python-hello-1.0.0/debian/README.Debian
- python-hello-1.0.0/debian/changelog
- python-hello-1.0.0/debian/compat
- python-hello-1.0.0/debian/control
- python-hello-1.0.0/debian/copyright
- python-hello-1.0.0/debian/python-hello.docs
- python-hello-1.0.0/debian/python-hello.install
- python-hello-1.0.0/debian/python3-hello.docs
- python-hello-1.0.0/debian/python3-hello.install
- python-hello-1.0.0/debian/rules
- python-hello-1.0.0/README.txt
- python-hello-1.0.0/hello.py
- python-hello-1.0.0/setup.py
パッケージビルド
この記述でバイナリパッケージを生成できるかチェックします。
debuild -uc -us
作成時、多くのlintianのエラーや警告が出ますが、上のディレクトリにはpython-helloとpython3-helloの二つのdebファイルが生成できているはずです。debファイルの生成確認を持って、ここで終わりとします。launchpadのppa等に公開するためには、このlintianエラーや警告が消えるように頑張っていくことになります。
応用
- binaryモジュールは、必要なライブラリをcontrolに書く必要があります。
- /etc等どっちのモジュールでも使うものはpackagename-commonパッケージをつくるようにし、それを各バイナリパッケージのDependsに入れておけばいいでしょう。
- ソースがpython3とpython2でsetupファイルが別の場合、sys.versionでimportするsetupファイルを切り替えるsetup.pyを用意します。
debian/rulesのpysupportでだめなら、pycentralを使う
おまけ: debファイル中のファイルリスト一覧を取り出すには
dpkg-deb -c ../python-hello_1.0.0-1nmu1_i386.deb
おまけ: lintianメッセージを詳細情報つきで出すには
lintian -i ../python-hello_1.0.0-1nmu1_i386.changes | lv
トラブルシューティング
- ログで「XS-Python-Versionはdeprecateで、debian/pyversionを使え」のようなメッセージが出るが、lucidではこのやり方ではmulti packageではエラーになってしまい、debian/pyversionsは使えなかった
python3パッケージのモジュールが、debian系でsys.pathが通っているdist-packagesではなく、site-packages下に入る。python2では同じ記述でpyshared下に入るので、まだpython-support/python-centralがpython3向けにうまく機能していないのだろう。これはsys.pathにsite-packagesへのPATHを追加すれば使うことはできるが...- → debian/rulesを(cdbsではなく)dhで書く
emacsのpython-modeで、TABキーでのインデント位置を固定する方法
自分はキーボタンにモードがあるのが嫌いです。たとえばIMEではトグルは使わず、macのように変換/無変換キーにON/OFFを割り当てて使っています。これによってキーを何度押してもASCIIはASCIIだし、ひらがなはひらがなになります。*1
emacsのpython-modeでは、同じ位置でTAB keyを複数回押すと、インデントが下がる(outdent)ようになっていて、これが非常にいらつかせます。
そこで、以下のようなフックを.emacsで入れることで、cやrubyなどの言語モードと同じように、python-modeでも何回TABを押してもインデント位置が変わらないようにしています。
(add-hook 'python-mode-hook '(lambda() (defun my-indent-line (&optional arg) "modeless indent for python indentation" (interactive "P") (let ((old-this-command this-command)) (setq this-command t) (py-indent-line arg) (setq this-command old-this-command) )) (setq indent-line-function 'my-indent-line) ))
ちなみに、インデントを戻すときはブロックの最後に必ず pass や return を入れることになります。*2
emacs23 progmodes/python.elの場合
コマンド名や引数がpython-mode.elから若干変わっていますが、やり方は一緒です。
(add-hook 'python-mode-hook '(lambda () (defun my-indent-line () "modeless indent for python indentation" (interactive "P") (let ((old-this-command this-command)) (setq this-command t) (python-indent-line) (setq this-command old-this-command) )) (setq indent-line-function 'my-indent-line) ))
python-mode.elとprogmodes/python.el両方に対応するフック
(add-hook 'python-mode-hook '(lambda () (defun my-indent-line (&optional arg) "modeless indent for python indentation" (interactive "P") (let ((old-this-command this-command)) (setq this-command t) (cond ((fboundp #'python-indent-line) (funcall #'python-indent-line)) ((fboundp #'py-indent-line) (funcall #'py-indent-line arg)) ) (setq this-command old-this-command) )) (setq indent-line-function 'my-indent-line) ))
Cythonを使ってみる
python-simplexqueryでは、C&C++でpythonのextensionを書いたけど、これ以上ベタでpython層変換を書くのはきついので、このあたりをサポートするツールを試すことにし、まずcythonを使ってみました。
cythonはpyxというpython言語の拡張言語(pyrex)のソースファイルを、cファイルに変換するpythonモジュールです。distutilsのコマンド拡張も入っているので、setup.pyに.cや.cpp同様直接.pyxを混ぜて入れることができ、cコードに変換後にコンパイルさせることも可能です。
setup.py
from distutils.core import setup, Extension from Cython.Distutils import build_ext setup( name = 'hello', cmdclass = {'build_ext': build_ext}, ext_modules = [Extension("hello", ["chello.c", "hello.pyx"])] )
ミソは、build_extをCythonのものに指定すること
chello.c
#ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include <stdio.h> #include <string.h> extern void * (* get_malloc(void))(size_t); extern char * say_hello(const char * name) { char * hello = "Hello"; int hellolen = strlen(hello); int namelen = strlen(name); int buflen = hellolen + 1 + namelen + 1; char * buf = get_malloc()(buflen); sprintf(buf, "%s %s", hello, name); return buf; }
mallocはpythonのものを使うことにします。ここでは、それを外で定義させるため、関数get_malloc()経由で取得させました。最初のdefineはcl.exeの警告を消すためのおまじない。
hello.pyx
cdef extern from "Python.h": void * PyMem_Malloc(size_t) void PyMem_Free(void *) pass #cdef extern char * say_hello(char *) # or cdef extern: char * say_hello(char *) pass ctypedef void * malloc_t(size_t) cdef extern malloc_t * get_malloc(): return PyMem_Malloc # function returned func cdef requires arg name of its func type cdef extern void (* get_free())(void * ptr): return &PyMem_Free def say_hello_to(name): # convert py to c # cannot mix py exp in cdef exp without pyvars bname = name.encode("utf-8") cdef char * cname = bname cdef char * buf = say_hello(cname) # convert c to py ret = buf PyMem_Free(buf) return ret.decode("utf-8")
いくつかポイント
実行
普通のと同じで、python setup.py build でビルドできます。できたモジュールはcythonライブラリを必要としません。
python3対応
cythonの生成cファイルは、python2でもpython3でも対応している。
ただし、Cython-0.12.1のCython/Compiler/Main.pyがpython3非互換なのでsetup.py build時に修正する必要がある。
- build時のエラー部分をprint(msg)、raise Excep(msg)、except Excep as ex: などにする程度。2to3でいける?
twitter記法をつかってみる
暫定、完成版
(未完成)やってみた。麻雀の上がりチェックプログラム - ラシウラから、ちょっと修正して要件を満たしたものです。
# -*- coding: utf-8 -*- class Hai(object): def __init__(self, num, tsumo=False): self.num = num self.tsumo = tsumo pass def __eq__(self, other): return self.num == other.num and self.tsumo == other.tsumo pass class Tenpai(object): def __init__(self, toitsu, sumentsu): self.groups = [toitsu] + sorted(sumentsu, self.rimentsu) pass def __hash__(self): return hash(str(self.group)) def __eq__(self, other): return self.groups == other.groups def rimentsu(self, mentsua, mentsub): if is_juntsu(mentsua): return 1 if is_juntsu(mentsub): return -1 return 1 def format(self): return "".join(self.format_group(group) for group in self.groups) def format_group(self, group): if any(hai.tsumo for hai in group): return "[%s]" % "".join(str(hai.num) for hai in group if not hai.tsumo) else: return "(%s)" % "".join(str(hai.num) for hai in group) pass pass def main(): while True: try: tehai_str = raw_input("haipai> ").strip() if not tehai_str: break tehai = parse(tehai_str) for tenpai in iter_tenpai(tehai): print(tenpai) pass pass except: import traceback traceback.print_exc() pass pass pass def parse(tehai): if len(tehai) != 13: raise Exception("tehai should be 13 hai") return [Hai(int(tehai[i])) for i in range(len(tehai))] def iter_tenpai(tehai): tsumo_list = [Hai(i, True) for i in range(1, 10)] # TBD: check: count of same num <= 4 tenpaiset = set() for tsumo in tsumo_list: tsumotehai = rihai(tehai + [tsumo]) for toitsu, rest in iter_toitsu(tsumotehai): for sumentsu in iter_allmentsu(rest): tenpai = Tenpai(toitsu, sumentsu).format() if tenpai in tenpaiset: continue tenpaiset.add(tenpai) yield tenpai pass pass pass pass def rihai(tsumo_and_tehai): return sorted(tsumo_and_tehai, lambda a, b: cmp(a.num, b.num)) def iter_toitsu(ritsumo): same = [] for i in range(len(ritsumo) - 1): if ritsumo[i].num == ritsumo[i+1].num: toitsu = ritsumo[i:i+2] rest = ritsumo[:i] + ritsumo[i+2:] if toitsu in same: continue same.append(toitsu) yield (toitsu, rest) pass pass pass def is_juntsu(mentsu): return (mentsu[0].num + 1 == mentsu[1].num and mentsu[0].num + 2 == mentsu[2].num) def is_kotsu(mentsu): return mentsu[0].num == mentsu[1].num == mentsu[2].num def is_mentsu(mentsu): return is_juntsu(mentsu) or is_kotsu(mentsu) def pick1(hailist): for i in range(len(hailist)): yield (hailist[i], hailist[:i] + hailist[i+1:]) pass pass def iter_allmentsu(rest): if len(rest) == 0: yield [] return a = rest[0] r1 = rest[1:] same = [] for b, r2 in pick1(r1): for c, r3 in pick1(r2): mentsu = [a, b, c] if mentsu in same: continue same.append(mentsu) if not is_mentsu(mentsu): continue for allmentsu in iter_allmentsu(r3): yield [mentsu] + allmentsu pass pass pass pass if __name__ == "__main__": main()
追記: ドメイン知識を利用する
上の四面子の探し方(iter_allmentsu)は、先頭の牌に対し全ての三牌の組を列挙してそれが順子か刻子かを判定していく方式をとってます。これは細かい性質を知らなくても問題文からすぐ割り出せるやり方です。
しかし麻雀のルールから考えれば、先頭の牌に対し刻子となる組み合わせ、順子となる組み合わせを探していく方が、効率が良いと思います。なぜなら探索範囲の限定がしやすいから。整牌済なら、刻子なら数値が違う牌が出た時点で失敗となり、順子なら一つ上二つ上の牌それぞれがない時点で失敗とわかるからです。それが下記のコードです:
def iter_allmentsu(hai_list): if len(hai_list) == 0: yield [] return juntsu, rest = find_juntsu(hai_list) if juntsu: for allmentsu in iter_allmentsu(rest): yield [juntsu] + allmentsu pass pass kotsu, rest = find_kotsu(hai_list) if kotsu: for allmentsu in iter_allmentsu(rest): yield [kotsu] + allmentsu pass pass pass def find_kotsu(hai_list): if (hai_list[0].num == hai_list[1].num and hai_list[0].num == hai_list[2].num): return hai_list[:3], hai_list[3:] return [], hai_list def find_juntsu(hai_list): juntsu = [hai_list[0], None, None] rest = [] for hai in hai_list[1:]: if juntsu[1] is None and hai.num == juntsu[0].num + 1: juntsu[1] = hai pass elif juntsu[2] is None and hai.num == juntsu[0].num + 2: juntsu[2] = hai pass else: rest.append(hai) pass pass return (juntsu, rest) if juntsu[1] and juntsu[2] else ([], hai_list)