ラベル 読書 の投稿を表示しています。 すべての投稿を表示
ラベル 読書 の投稿を表示しています。 すべての投稿を表示

6/19/2011

[読書] Python クックブック 第2版 読んでみる。第1章-その2

間があいたけど、第1章-その2。結構、勉強になることあるよね。
肩肘張らず、楽しく、ゆる~くがモットーです。



1.13 文字列の一部にアクセスする
structモジュールを使う。サンプルの方法は3だとエラー。

ドキュメントから
3.x
This module performs conversions between Python values and C structs represented as Python bytes objects.
2.x
This module performs conversions between Python values and C structs represented as Python strings.

ほう、バイト型にですか。
>>> baseformat = "5s 3x 8s 8s"
>>> numremain = len("123456781234567812345678")-struct.calcsize(baseformat)
>>> format = "%s %ds" % (baseformat, numremain)
>>> leading, s1, s2, trailing = struct.unpack(format, b"123456781234567812345678")
>>> s1
b'12345678'
>>> s2
b'12345678'
>>> leading
b'12345'
>>> trailing
b''
>>> 


くっつける
>>> struct.pack(format,leading, s1, s2, trailing)
b'12345\x00\x00\x001234567812345678'


1.14 インデントの変更

例外の部分を3に合わせて

def addSpace(s,numAdd):
 """行頭に指定数の空白を付与する。"""
 white=" "*numAdd
 return white + white.join(s.splitlines(True))
   
def numSpace(s):
 """各行の行頭にあるスペース数を、リスト形式で戻す"""
 return [len(line)-len(line.lstrip()) for line in s.splitlines()]


def delSpace(s,numDel):
 """行頭から指定したスペース分をスライスした(除去した行を返す)"""
 if numDel > min(numSpace(s)):
  raise ValueError("removing more spaces than there are")
 return '\n'.join([ line[numDel:] for line in s.splitlines() ])

 
def unIndntBlock(s):
 """一番インデントの小さいものに合わせて成形する"""
 return delSpace(s,min(numSpace(s)))

試してみる。
空白が3,2,4個行頭にあるとする。
>>> s=' Hello\n world!\n goodbye'
>>> min(numSpace(s))
2
>>> print(unIndntBlock(s))
Hello
world!
goodbye
>>>
各行の行頭からスペースが2個削除。


1.15 タブとスペースの変換

スペースをタブに変更する。
サンプルだとダブルバイトが入ると変になったので、str.encode()のlen()を取得するように変更してみた。
def unexpand(astring, tablen=2):
    import re
    #スペースと非スペースに切断する。
    pices = re.split(r'( +)', astring.expandtabs(tablen))
    #全体の長さを初期化
    lensofar = 0
    for i,piece in enumerate(pices):
        #要素の長さ
        thislen = len(str.encode(piece))
        #全体の長さ
        lensofar += thislen
        if piece.isspace():
            #要素の長さをタブ1個のスペース数で割る。余りがタブに出来ない分なのでスペースになる。
            numblanks = thislen % tablen
            numtabs = (thislen - numblanks + tablen - 1)//tablen
            pices[i] = '\t'*numtabs + ' '*numblanks
    return ''.join(pices)

2個の空白があえばタブにする。
>>> unexpand("1234 567   890  あ あ   い")
'1234 567\t 890\tあ あ\t い'

1.18 一度に複数のパターンを置換する
import re
def multiple_replace(txt,adict):
#1.辞書の内容にメタキャラが含まれる可能性がるので、escapeする。
#mapでキーを取りだし|で結合。検索パターンの作成。
rx = re.compile('|'.join(map(re.escape,adict)))
#引数はマッチオブジェクト
def one_xlat(match):
return adict[match.group(0)]
#検索にヒットするたびに、マッチオブジェクトを引数に関数をコールバック。
return rx.sub(one_xlat,txt)

まず、検索パターンを作成する。縦棒で検索文字列をつなぎ、compileする。
そして、re.subに置換文字列の代わりに、コールバック関数を渡す。
こうした場合re.subではマッチが起きるたびにコールバック引数オブジェクトをコールする。
その際、コールバック引数オブジェクトへの唯一の引数は、re.MatchObjectインスタンスが自動的に渡される。

簡単な例だと、以下な感じ。
>>> import re
>>> rx = re.compile('a|b|c')
>>> def hoge(match):
return "x"

>>> print(rx.sub(hoge,'abc45'))
xxx45
>>> def hoge(match):
print(match.group(0))
return "x"

>>> print(rx.sub(hoge,'abc45'))
a
b
c
xxx45
>>>

multiple_replaceはコールされるたびに、正規表現の再計算とone_xlat補助関数の再定義が走るので、
クロージャ・アプローチの方が良い。
元サンプルの可変長引数 *argsは不要というか、結局辞書化する必要が出てくるしなぁ。
dictに*args,**kwdsと2個渡すところでエラーになったので辞書だけにした。
import re
def make_xlat(**kwds):
adict = dict(**kwds)
rx = re.compile('|'.join(map(re.escape ,adict)))
def one_xlat(match):
return adict[match.group(0)]
def xlat(text):
return rx.sub(one_xlat, text)
return xlat
動かしてみよう。
>>> adict={
"Larry Wall":"Hoge",
"creator":"killer",
"Perl":"World",
}
>>> text="Larry Wall is the creator of Perl"

こうでも良いし。
>>> fnc=make_xlat(**adict)
>>> fnc(text)
'Hoge is the killer of World'
>>>

こうしてもいいわけね。
>>> fnc=make_xlat(Perl="World",the="ssss")
>>> fnc(text)
'Larry Wall is ssss creator of World'
>>>

置換方法にバリエーションを持たせたい->(単語単位)場合に置換したいとか。
クラス化して継承を利用する。
import re
"""
基底クラス
"""
class make_xlat():
def __init__(self, **kwds):
self.adict = dict(**kwds)
self.rx = self.make_rx()
def make_rx(self):
return re.compile('|'.join(map(re.escape,self.adict)))
def one_xlat(self,match):
return self.adict[match.group(0)]
def __call__(self,text):
return self.rx.sub(self.one_xlat,text)
import make_xlat
import re
"""
派生クラス
"""
class make_xlat_by_wh_word(make_xlat.make_xlat):
def make_rx(self):
return re.compile(r'\b%s\b' % r'\b|\b'.join(map(re.escape,self.adict)))

単語単位にマッチしているので、PerlsはWorldに置換されない。
>>> fnc=make_xlat_wh_word.make_xlat_by_wh_word(**adict)
>>> fnc(text)
'Hoge is the killer of Perls'



1.24 一部の文字列のみ大文字小文字無関係にする

strを継承したクラスを作成。

class iStr(str):
    """
    str継承。検索と比較は大文字小文字を無視。
    """
    def __init__(self,*args):
        self._lowered = str.lower(self)
    def __repr__(self):
        return '%s(%s)' % (type(self).__name__,str.__repr__(self))
    def __hash__(self):
        return hash(self._lowered)
    def lower(self):
        return self._lowered

strのメソッドをラップ。
def _make_case_insensitive(name):
    str_meth = getattr(str,name)
    def x(self,other,*args):
        try: other = other.lower()
        except(TypeError ,AttributeError ,ValueError ): pass
        return str_meth(self._lowered,other,*args)
    #Python2.4 late add x.func_name=name
    x.func_name=name
    setattr(iStr, name, x)

case insensitiveとして扱うものを属性に追加
for name in 'eq lt le gt ne contains'.split():
    _make_case_insensitive('__%s__' % name)

for name in 'count endswith find index rfind rindex startswith'.split():
    _make_case_insensitive(name)

こうなるものが、
>>> HOGE="Test"
>>> HOGE.startswith("t")
False

こうなるよと。
>>> FOO=iStr("Test")
>>> FOO.startswith("t")
True

このレシピは、ケースインセンシティブなコンテナ型などを作る際に応用が利く。

ケースインセンシティブなリスト。iListの各itemがiStrでラップされるだけ。
class iList(list):
 def __init__(self,*args):
  self[:] = self
 wrap_each_item = iStr
 def __setitem__(self,i,v):
  if isinstance(i,slice): v = map(self.wrap_each_item,v)
  else: v = self.wrap_each_item(v)
  list.__setitem__(self,i,v)
 def append(self,item):
  list.append(self,self.wrap_each_item(item))
 def extend(self,seq):
  list.extend(self,map(self.wrap_each_item,seq))

>>> WARA=iList()
>>> WARA
[]
>>> WARA.append("a")
>>> WARA.append("b")
>>> WARA.append("c")
>>>
>>> WARA
[iStr('a'), iStr('b'), iStr('c')]
>>> WARA.append("A")
>>> WARA
[iStr('a'), iStr('b'), iStr('c'), iStr('A')]
>>>
>>> WARA.count("a")
2
>>>

5/05/2011

[読書] Python クックブック 第2版 読んでみる。第1章-その1

内容は2.x系向けに書かれてる。3.x系ではどうするの?と考えながら読んでみるなどする。
いつも通り、間違ってても、車輪の再発明になっても気にしない。娯楽なので。
作戦:ガンガンいこうぜ。




1.3 オブジェクトが文字列のようなものかテストする

Python2では文字列の方が、Unicode型と非Unicode型があり、スーパクラスとしてbasestring型があった。
これをisinstance()に渡すと、Unicodeか否かの判別ができた。
basestringデータ型 はPython3にはないので、素直にisinstance(anobj,str)でよい。


1.6 文字列の連結

Pythonの文字列はイミュータブル。Javaで文字列を+連結するのと同じ問題を孕む。
''.joinを使うのが正解だよね。



1.8 文字列にキャラクタセットの文字が含まれるか調べる

itertools.ifilter() はPython 3では 標準ビルトイン関数 filter() になっている

書き変えてみる
def containsAny2(seq, aset):
  for item in filter(aset.__contains__,seq):
  return True
 return False

not の結果がemptyだとTrueが戻ることを利用。
def containsAll(seq,aset):
 return not set(aset).difference(seq)


>>> not set()
True
>>> not set('a')
False


>>> not ''
True
>>> not 'a'
False

Python 3 では Python 2 の string.maketrans とそっくりのスタティックメソッド maketrans がバイト列型に加わっている。
そしてユニコード文字列型にも maketrans スタティックメソッドが追加された。
これはユニコード文字列型の translate に渡せる辞書を返す。

調査対象文字列に、任意の文字列を1つでも含むか?
def containsAny(astr,strset):
 notrans = str.maketrans('','',astr)
 return len(strset) != len(strset.translate(notrans))


1.9 文字列クラスのtranslateメソッドを簡単に使う。

クロージャーを使ったラッパを作っているが、3.xではサンプルは動かない。
練習がてらユニコード文字列の maketransメソッドを使ったコードを書いてみた。

削除とkeepを2者択一にしてたりして機能縮小版。とりあえず。

def translator(frm='',to='',delete='',keep=None):
 if len(to) == 1:
  to = to * len(frm)
 if keep is not None:
  trans = str.maketrans('','',keep)
 else:
  trans = str.maketrans(frm,to,delete)
  
 def translate(s):
  if keep is not None:
   return s.translate(str.maketrans('','',s.translate(trans)))
  else:
   return s.translate(trans)
 return translate

a,dをbに変換して、数字だけ削除
>>> import string
>>> test = translator(frm='ad',to='b',delete=string.digits)
>>> test('aaaaaccccdddd123456789')
'bbbbbccccbbbb'

数字だけ残す
>>> test = translator(frm='ad',to='b',keep=string.digits)
>>> test('aaaaaccccdddd123456789')
'123456789'
>>>

ダブルバイト。愛は嘘なり。
>>> test = translator(frm='愛',to='嘘',delete=string.digits)
>>> test('愛愛愛123456789')
'嘘嘘嘘'
>>>

1/24/2011

[読書]Head First Python 読んでみる。 Chapter3

Chapter3は File & Exception : Dealing with Errors.


全章通じてそうだけど、小さな例題アプリを少しづつ、お話と共に作りながら進んでいく形式。
いつもながらこのHead Firstのやり方はうまい。猫でもわかるようになっている。

ただ、猫でない人にとっては冗長、そういう人は対象読者ではないにしても。

英語を読み進めるスピードが遅いのと、オンラインで読んでいるせいもあって
だんだん、面倒になってきたぞ。どんどん飛ばして読んでもいいのだが。。うーむ。

この内容ならこの章は2~3ページでいいじゃない。というのは野暮なのでしょう。たぶん。

もうちょっと頑張ってみよう。

    1/16/2011

    [読書]Head First Python 読んでみる。 Chapter2

    Head First Python 読んでみる。 Chapter2


    読書記録としてはWikiの方がよいのだろうけど、続かなそうなので。。
    この心理的作用はなんだんだろう?お手軽だから?うーん。

    Chapter 2 はモジュール作成から配布を中心に、名前空間など書いてある。
    この段階からPyPIの使い方が書かれているのは良いことなんだと思う。

    • How to distribution the own Python Modules.
    • How to use the Python Package Index ("PyPI"). Registration, Upload Module, Update Module.
    • Python Name Space. Main name space is known __main__.
    1. A module is a text file that contains Python code.
    2. We can use the distribution utilities to turn own module into a shareable package.
    3. The setup.py program provides metadata about your module and is used
      to build, install, and upload your packaged distribution.
    4. The range() BIF can be used with 'for' to iterate a fixed number of times.
    5. Including end=’’ as a argument to the print() BIF switches off its automatic inclusion of a new-line on output.
    6. Arguments to your functions are optional if you provide them with a default value.

    1/06/2011

    [読書]Head First Python 読んでみる。 Chapter1

    Head FirstシリーズのPython版が出ていたので読んでみるなど。

    まだ翻訳版は出ていない?っぽいので原書で。英語出来ないのにw

    Head Firstシリーズは「学習」に重点を置いていて、如何に効率的に理解させて記憶に残すか?
    を考えて作られている本。絵が一杯で楽しいんだけど、その分冗長でちんたら進むので、飽きてしまう事も。

    所謂、リファレンスではないので初学者向け。「浅く、広くPythonに触れてみる」といったところ。
    ちゃんとするなら、ネズミ本。Apple AppsStoreで600円だし。




    Chapter1
    Meet Python : Everyone Loves Lists.

    IDLEの使い方
    Python のList
    For Loop
    BIFs instance()
    Function
    再帰

    など。小気味よく読了。
    後半の章ではGoogle App Engine を用いてWebアプリつくったりもしていて期待出来そう。

    なんだけど、とある事情で今月中に読み終えないといけず、496 Pages もあるからなぁ。
    単純日割りで24page/day。英語が最大のネックか。

    12/16/2010

    [読書]ケント・ベック 実装パターン 

    Kent Beck の実装パターンを読んだ。
    日常的にコードを書く人ではない、趣味の園芸な自分が読んでも楽しめる。

    一通り読んだものの咀嚼出来ていないところがあるので、時間を見つけて査読したいな。

    ちょっと前に、Junitのソースコードを眺めていたんだけど、この本読んでる最中に、
    「ああ、ここの記述はあそこのソースでもやってたなぁ」と思いだした。
    もう一度、Junitちゃんと読んでみようかなぁ。

    コレクションAPIのパフォーマンス比較をするために、測定用フレームワークを作っていて付録Aで
    そのコードを公開している、コード自体はとても小さいシンプルなものだけど、本書の中のパターン
    が使われている。

    後でWebで見たかったので写経してみた。
    コメントいれてる。変なところがあったら御免なさい。

    このListSerchクラスのserchメソッドの実行時間を計測すると
    search 25.30 77.81 551.10 と結果出力される。
    要素数が増加すると実行時間が増えている。



    import java.util.ArrayList;
    import java.util.List;

    public class ListSerch {
    private List<Integer> numbers;
    private int probe;

    public ListSerch(int size){
    numbers = new ArrayList<Integer>();
    for (int i = 0; i < size; i++) {
    numbers.add(i);
    probe = size / 2;
    }
    }
    //ArrayListの真ん中を取得させる。
    public void search(){
    numbers.contains(probe);
    }
    }

    ドライバークラスは以下。
    テストしたいクラスに含まれるメソッドの配列を引数にしてMethodsTimerインスタンス化。
    report()メソッドを実行する。
    結果はコンソールに
    メソッド名 1回実行での時間 10回実行での合計時間 100回実行での合計時間 ・・・合計が1秒こえるまでやる。

    public class TestDriver {

    public static void main(String[] args) throws Exception{
    MethodsTimer tester = new MethodsTimer(ListSerch.class.getDeclaredMethods());
    tester.report();
    }
    }



    import java.lang.reflect.Method;

    public class MethodsTimer {
    public final Method[] methods;
    private static final int MAXIMUM_SIZE = 100;
    public static final int ONE_SECOND = 1000000000;

    public MethodsTimer(Method[] methods){
    this.methods = methods;
    }

    public void report() throws Exception{
    for(Method each : methods){
    System.out.print(String.format("%.2f\t", r.getMethodTime()));
    for (int size = 1; size <= MAXIMUM_SIZE; size *=10)
    {
    MethodTimer r = new MethodTimer(size, each);
    r.run();
    System.out.print(r.getMethodTime() + "\t");
    }
    System.out.println();
    }
    }
    }



    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;

    public class MethodTimer {
    private final int size;
    private final Method method;
    private Object instance;
    private long totalTime;
    private int iterations;
    private long overhead;

    public MethodTimer(int size, Method method) throws Exception{
    this.size=size;
    this.method=method;
    instance = createInstance();
    }

    public MethodTimer(int iterations) throws Exception{
    this(0,MethodTimer.Overhead.class.getMethod("nothing", new Class[0]));
    this.iterations = iterations;
    }

    private static MethodTimer overheadTimer(int iterations) throws Exception{
    return new MethodTimer(iterations);
    }

    private Object createInstance() throws Exception {
    Constructor<?> constructor = method.getDeclaringClass().getConstructor(
    new Class[] { int.class });
    return constructor.newInstance(new Object[] { size });
    }

    double getMethodTime(){
    return (double)(totalTime - overhead) / (double)iterations;
    }


    void run() throws Exception {
    iterations = 1;
    while (true) {
    totalTime = computeTotalTime();
    if (totalTime > MethodsTimer.ONE_SECOND)
    break;
    iterations *= 2;
    }
    overhead = overheadTimer(iterations).computeTotalTime();
    }



    private long computeTotalTime() throws Exception {
    long start = System.nanoTime();
    for (int i = 0; i < iterations; i++) {
    method.invoke(instance, new Object[0]);
    }
    return System.nanoTime() - start;
    }

    public static class Overhead {
    public Overhead(int size) { }
    public void nothing() { }
    }

    }