メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2008年3月1日土曜日

[Apache][CodeReading] Apache2.2.8コードリーディング30日目

今日もApache2.2.8コードリーディング。

今日はちょっとだけ。

今日やったところは、

  • apr_cvt()/Apache2.2.8
らへん。

apr版printfの不動小数点数を文字列に変換するところ。

apr_cvt()
この関数は少々難しい。いかに自分が力不足か確認できた。。。

何をする関数かというと、与えられた浮動小数点数値を
与えられた精度で、文字列化するのだが、ここで小数点は文字列化しない。
小数点の位置は引数で関数に渡すパラメータにセットされ、呼び出し元に返される。
正負も引数で関数に渡すパラメータにセットされ、呼び出し元に返される。

たとえば、1234.5678という数値があったとする。
そして、eflags == 0、ndigits == 10でapr_cvt()をコールしたとする。
このときの関数の呼び出し結果は、

123456780000000
 

という文字列と、

4
 

という小数点の位置と、

0
 

という正負フラグ
になる。

あと、たとえば、0.9999という数値があったとして、
精度が4以下の場合、1に丸められる。


とりあえず、以下コード。

96 static char *apr_cvt(double arg, int ndigits, int *decpt, int *sign,
97 int eflag, char *buf)
98 {
99 register int r2;
100 double fi, fj;
101 register char *p, *p1;
102
103 if (ndigits >= NDIG - 1)
104 ndigits = NDIG - 2;
105 r2 = 0;
106 *sign = 0;
107 p = &buf[0];
108 if (arg < 0) {
109 *sign = 1;
110 arg = -arg;
111 }
112 arg = modf(arg, &fi);
113 p1 = &buf[NDIG];
114 /*
115 * Do integer part
116 */
117 if (fi != 0) {
118 p1 = &buf[NDIG];
119 while (p1 > &buf[0] && fi != 0) {
120 fj = modf(fi / 10, &fi);
121 *--p1 = (int) ((fj + .03) * 10) + '0';
122 r2++;
123 }
124 while (p1 < &buf[NDIG])
125 *p++ = *p1++;
126 }
127 else if (arg > 0) {
128 while ((fj = arg * 10) < 1) {
129 arg = fj;
130 r2--;
131 }
132 }
133 p1 = &buf[ndigits];
134 if (eflag == 0)
135 p1 += r2;
136 if (p1 < &buf[0]) {
137 *decpt = -ndigits;
138 buf[0] = '\0';
139 return (buf);
140 }
141 *decpt = r2;
142 while (p <= p1 && p < &buf[NDIG]) {
143 arg *= 10;
144 arg = modf(arg, &fj);
145 *p++ = (int) fj + '0';
146 }
147 if (p1 >= &buf[NDIG]) {
148 buf[NDIG - 1] = '\0';
149 return (buf);
150 }
151 p = p1;
152 *p1 += 5;
153 while (*p1 > '9') {
154 *p1 = '0';
155 if (p1 > buf)
156 ++ * --p1;
157 else {
158 *p1 = '1';
159 (*decpt)++;
160 if (eflag == 0) {
161 if (p > buf)
162 *p = '0';
163 p++;
164 }
165 }
166 }
167 *p = '\0';
168 return (buf);
169 }
 

引数は、
  • arg 変換対象の浮動小数点数値
  • ndigits 精度
  • decpt 出力パラメータ。小数点の位置
  • sign 出力パラメータ。正負。
  • eflag フォーマットが'e'か'E'の場合は、0以外の値を指定する。
  • buf 出力パラメータ。変換後文字列格納領域。
となっている。
さて、ややこしいので1つづつ見ていく。

99行目の

register int r2;
 

は、小数点の位置の算出に利用される。

103     if (ndigits >= NDIG - 1)
104 ndigits = NDIG - 2;
105 r2 = 0;
106 *sign = 0;
107 p = &buf[0];
 
 

あたりは特に難しくない。精度が、上限値(NDIG==80)を超えていたらセットしなおしている。
r2(小数点の位置)は0クリア。
sign(正負フラグ)も0クリア。
pを出力領域の先頭アドレスにセット。

108     if (arg < 0) {
109 *sign = 1;
110 arg = -arg;
111 }
  

ここは、変換対象の浮動小数点数が負の値で合った場合の処理。
signに1をセットし、argは正の値にセットしなおす。



112 arg = modf(arg, &fi);
 
 
ここで整数部と小数部を分離。
fiには整数部、argには小数部が入る。

113     p1 = &buf[NDIG];
 

ここで、p1に出力領域(buf)の最後尾のアドレスをセットしている。


117     if (fi != 0) {
118 p1 = &buf[NDIG];
119 while (p1 > &buf[0] && fi != 0) {
120 fj = modf(fi / 10, &fi);
121 *--p1 = (int) ((fj + .03) * 10) + '0';
122 r2++;
123 }
124 while (p1 < &buf[NDIG])
125 *p++ = *p1++;
126 }
 

ここで、整数部を文字列に変換する。
118行目は必要なコードでは無いと思う。
whileループは整数部が無くなるまで繰り返す。
120行目で10分の1にすることで、整数部の1の位を取り出している。
1の位はfjに10分の1の値で設定される。

そして、面白いのがここ。
121             *--p1 = (int) ((fj + .03) * 10) + '0';
 
 
10分の1にして取り出した1の位の値に0.03を加算後、10倍しているのだが、
この0.03が無いと結果が変わってしまう。
たとえば、1234.0という値を変換しようとした場合、0.03を加算しないと
p1には1134という値がセットされてしまう。
0.03を加算することで、doubleやfloatの問題を回避している。

124行目からは、121行目で作成した文字列をbufの先頭領域にコピーしている。


127     else if (arg > 0) {
128 while ((fj = arg * 10) < 1) {
129 arg = fj;
130 r2--;
131 }
132 }
 


は、整数部が無かった場合の処理で、
小数点以下第一位の位に0以外の数値を持ってきている。
位を移動した分だけr2も更新。

133     p1 = &buf[ndigits];
134 if (eflag == 0)
135 p1 += r2;
136 if (p1 < &buf[0]) {
137 *decpt = -ndigits;
138 buf[0] = '\0';
139 return (buf);
140 }
 
 
p1に指定精度になるようにbuf[ndigits]へのアドレスをセット。
135行目で、整数部の桁数分p1を後ろにずらしている。

141     *decpt = r2;
142 while (p <= p1 && p < &buf[NDIG]) {
143 arg *= 10;
144 arg = modf(arg, &fj);
145 *p++ = (int) fj + '0';
146 }
 

ここで、decptをセット。r2には小数点の位置(整数部の桁数)がセットされているので
その値をそのままdecptの指す先へセットしている。

142から146行目の処理では小数点以下の値を文字列化している。

仮にndigitsの値分の精度が必要なかった場合、あまった領域には'0'がセットされる。

147     if (p1 >= &buf[NDIG]) {
148 buf[NDIG - 1] = '\0';
149 return (buf);
150 }
 

で、領域を壊して突き進んでいたら、出力領域の最後尾にヌル文字をセットして
呼び出し元へ返る。


151     p = p1;
152 *p1 += 5;
153 while (*p1 > '9') {
154 *p1 = '0';
155 if (p1 > buf)
156 ++ * --p1;
157 else {
158 *p1 = '1';
159 (*decpt)++;
160 if (eflag == 0) {
161 if (p > buf)
162 *p = '0';
163 p++;
164 }
165 }
166 }
 

ここは、簡単に言うと、丸め処理をしている部分。
出力精度が4桁で、渡された値が99999であった場合、
このループに入るときのp1は、最後の'9'を指している。
そして、その'9'に5を加算する。('>'になる)
'>'は'9'より大きいので、このループが実行される。
このループの実行が終わると
99999であった値は100000に変わる。
それに伴ってdepctの値も更新。

最後にbuf[ndigits]にヌル文字をセットし、
bufを返す。



多分大体こんな感じの処理であっていると思う・・・。
うーむ。
ややこしいー。


おしまい。
.

[Python][お勉強] 「Pythonチュートリアル」を読む(9) -- データ構造

リストの補足。

  • append(x)
  • extend(L)
  • insert(i,x)
  • remove(x)
  • pop(i),pop()
  • index(x)
  • count(x)
  • sort()
  • reverse()
の説明が書かれている。

関数プログラミングのツール

filter()
書式は以下のとおり。

filter(関数, シーケンス)
 

シーケンスから、関数が真となるアイテムのみを取り出し、取り出したアイテムから成る
シーケンスを返す。


>>> L = [1,2,3,4,5]
>>> filter(lambda x: x % 2, L)
[1, 3, 5]
>>>
 

な感じ。


map()
書式は以下のとおり。

map(関数, シーケンス)
 


シーケンスの各要素をパラメータに関数を実行し、その関数の実行結果からなるシーケンスを
返す。
シーケンスは複数個渡すこともできて、その場合関数はシーケンスの個数分の要素を受け取れる
ようにする必要がある。

>>> map(lambda x: x**2, L)
[1, 4, 9, 16, 25]
>>> map(lambda x, y: x**2 + y ** 2,L,L)
[2, 8, 18, 32, 50]
 

な感じ。

mapに渡すシーケンスが複数の場合で、「長さ」が異なるシーケンスが渡された場合、
不足した要素の分はNoneが使用される。

>>> L2 = [1,2]
>>> map(lambda x, y: (x, y), L, L2)
[(1, 1), (2, 2), (3, None), (4, None), (5, None)]
>>>
 



reduce()
書式は以下のとおり。

reduce(関数, シーケンス)
 

シーケンスの最初の2つの要素をとり、関数に渡す。その結果と次のシーケンスの要素を1つ取り、
関数に渡す。この処理をシーケンスの要素がなくなるまで繰り返す。
以下、1から10の総和。

>>> reduce(lambda x, y: x + y, range(1,11))
55
>>>


また、第三引数に初期値を指定できる。
初期値は最初の要素としてreduceに渡される。

>>> reduce(lambda x, y: x + y, range(1,11), 100)
155
>>>
 



リスト内包表記
書式は以下のとおり。

[式 for節 if節]
 

式とそれに続くfor節から成る。
さらに0個以上のforまたはif節が続けられる。

得られる結果は、式をforまたはif節で評価した結果のリスト。
式の評価値がタプルになる場合は括弧で囲まなければならない。


>>> [ x ** 2 for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> [ (x ** 2, x ** 3) for x in range(1,11)]
[(1, 1), (4, 8), (9, 27), (16, 64), (25, 125), (36, 216), (49, 343), (64, 512), (81, 729), (100, 1000)]
>>>
 



del文
リストの要素を削除する。

>>> del L[1]
>>> L
[1, 3, 4, 5]
>>> del L[1:3]
>>> L
[1, 5]
>>>
 

な感じ。


タプルパッキング

>>> t = 1,2,3
>>> t
(1, 2, 3)
>>>
 



タプルアンパッキング

>>> t
(1, 2, 3)
>>> (a,b,c) = t
>>> a
1
>>> b
2
>>> c
3
>>>
 

な感じ。

多重代入は、タプルパッキングとタプルアンパッキングのあわせ技。

集合
重複しない要素を順不同で集めたもの。

>>> L = [1,2,3,1,2,3]
>>> set(L)
set([1, 2, 3])
>>>
 

な感じ。
数学的演算もサポートする。


>>> s1 = set('abcdefg')
>>> s2 = set('cdefghi')
>>> s1 - s2
set(['a', 'b'])
>>> s1 | s2
set(['a', 'c', 'b', 'e', 'd', 'g', 'f', 'i', 'h'])
>>> s1 & s2
set(['c', 'e', 'd', 'g', 'f'])
>>> s1 ^ s2
set(['i', 'h', 'b', 'a'])
>>>
 




ディクショナリ
いわゆる、連想配列やハッシュ。
キーには可変型オブジェクトは使えない。


ディクショナリのループ

>>> for k, v in D.iteritems():
... print "%s=%d" % (k, v)
...
a=1
c=3
b=2
>>>
 

iteritems()なんてのも使える。


シーケンスからインデックス値も同時に得る
enumerateを使うと、インデックス値をも得ることができる。

>>> L = [1,2,3,4,5]
>>> for i, v in enumerate(L):
... print "%d=%d" % (i,v)
...
0=1
1=2
2=3
3=4
4=5
>>>
 




おしまい。
.

2008年2月29日金曜日

[Apache][CodeReading] Apache2.2.8コードリーディング29日目

今日もApache2.2.8コードリーディング。
ひらメソッドでリーディング。

今日はapr_vformatterがコールしている関数群を中心に読んだ。
で、

  • NDIGローカルマクロ(apr_snprintf)/Apache2.2.8
  • HAVE_ISINFマクロ/Apache2.2.8
  • HAVE_ISNANマクロ/Apache2.2.8
  • S_NULL_LENローカルマクロ(apr_snprintf)/Apache2.2.8
  • S_NULLローカルマクロ(apr_snprintf)/Apache2.2.8
  • conv_p2_quad()/Apache2.2.8
  • conv_p2()/Apache2.2.8
らへん。

S_NULLは"(null)"っていう文字列。
S_NULL_LENはその文字列長。

メインはconv_p2_quad()とconv_p2()あたりか。

conv_p2_quad()
conv_p2_quad()は、64ビット整数を、8進表記文字列か16進表記文字列へ変換する関数。
以下、その関数。

638 static char *conv_p2_quad(apr_uint64_t num, register int nbits,
639 char format, char *buf_end, register apr_size_t *len)
640 {
641 register int mask = (1 << nbits) - 1;
642 register char *p = buf_end;
643 static const char low_digits[] = "0123456789abcdef";
644 static const char upper_digits[] = "0123456789ABCDEF";
645 register const char *digits = (format == 'X') ? upper_digits : low_digits;
646
647 if (num <= APR_UINT32_MAX)
648 return(conv_p2((apr_uint32_t)num, nbits, format, buf_end, len));
649
650 do {
651 *--p = digits[num & mask];
652 num >>= nbits;
653 }
654 while (num);
655
656 *len = buf_end - p;
657 return (p);
658 }
 

パラメータのnumを、nbits、formatの値に従って文字列に変換する。
nbitsが3の場合は8進に、nbitsが4の場合は16進表記になる。
nbitsが4の場合で、formatが'X'(大文字のX)である場合は、
0xa~0xfまでの数字に大文字が使われる。

numがINT32の範囲内であれば、conv_p2()を使用して変換する。

conv_p2()
ほとんどconv_p2_quad()と一緒。
で、以下コード。

619 static char *conv_p2(register apr_uint32_t num, register int nbits,
620 char format, char *buf_end, register apr_size_t *len)
621 {
622 register int mask = (1 << nbits) - 1;
623 register char *p = buf_end;
624 static const char low_digits[] = "0123456789abcdef";
625 static const char upper_digits[] = "0123456789ABCDEF";
626 register const char *digits = (format == 'X') ? upper_digits : low_digits;
627
628 do {
629 *--p = digits[num & mask];
630 num >>= nbits;
631 }
632 while (num);
633
634 *len = buf_end - p;
635 return (p);
636 }
 

こちらは32ビット整数を8進表記文字列か16進表記文字列に変換する関数になっている。
型が違うだけでconv_p2_quad()と一緒。


あとは特になしな感じ。



おしまい。
.

[Python][お勉強] 「Pythonチュートリアル」を読む(8) -- 制御構造

4章突入。

if文


if <test1>:
<statements1>
elif <test2>:
<statements2>
else:
<statements3>
 

な感じ。「else if」、[elsif」でもなく「elif」。

for文
あらゆるシーケンスに対し、そのシーケンス内の順序で反復する。

for <var> in <sequence>:
<statements>
 

な感じ。
ループ内でリスト内のアイテムを更新する際は、リストのコピーをとって反復をかける。

>>> a = [1,2,3,4,5]
>>> for b in a[:]:
... a.insert(0, b)
...
>>> a
[5, 4, 3, 2, 1, 1, 2, 3, 4, 5]
>>>
 

な感じ。

range()
連続した数字列に対して反復をかけたいときに便利。

>>> range(5)
[0, 1, 2, 3, 4]
>>> range(5, 10)
[5, 6, 7, 8, 9]
>>> range(0,10,3)
[0, 3, 6, 9]
 


break文、continue文。
Cから持ってきたもの。動きに関してもほぼ一緒。

ループ文にはelseブロックを持たせることができるが、break文で終了した場合はelseブロックは実行されない。

pass文。
なにもしない文。


関数定義

def func(arg):
statements
 

の形。

「関数をコールするときに渡される実パラメータは、コール時点で、その関数のローカルシンボル表に加えられる。」
とのこと。
extends environmentな感じか。
return文がない場合、またはreturnに式を伴わない場合は、はNoneが返される。

引数のデフォルト値
関数の引数はデフォルト値を指定できる。
デフォルト値が指定されている場合、定義上渡せる引数よりも少ない引数でコールできる。

注意点:デフォルト値は、関数を定義しているスコープで定義した時点で評価される。
以下、その例。

>>> i = 100
>>> def func(aaa = i):
... print aaa
...
>>> i = 99
>>> func()
100
>>>



また、デフォルト値は一度しか評価されない。
以下、その例。

>>> def func(x, aaa = []):
... aaa.append(x)
... return aaa
...
>>> print func(1)
[1]
>>> print func(2)
[1, 2]
>>> print func(3)
[1, 2, 3]
>>>
  



キーワード引数
キーワード引数も受け取れる。

>>> def func(a, b, c):
... print "a = [%s]" % a
... print "b = [%s]" % b
... print "c = [%s]" % c
...
>>> func(a="aaa", b="bbb", c="ccc")
a = [aaa]
b = [bbb]
c = [ccc]
>>>
 

な感じ。
キーワード引数を使えば、引数の指定順は任意。
キーワード名には「仮引数」名を使用する。

※突然「仮引数」という言葉が出てきたが、一般的な「仮引数」でよいのだろうか・・・?
良さそうだねー。

仮引数の最後に**名前という形で記述すると、その名前が指す変数はディクショナリとして
仮引数に対応するキーワードを省いた全てのキーワード引数を受け取ることができる。
つまり、仮引数にないキーワードも使えるようになる。


任意引数
引数をタプルで受け取れるようにすれば任意個のパラメータを受け取れるようになる。

>>> func("a","b","c","d","e")
a=[a]
b=[b]
('c', 'd', 'e')
>>>
 



引数リストのアンパック

>>> def func(a, b, c):
... print "a=[%s]" % a
... print "b=[%s]" % b
... print "c=[%s]" % c
...
>>> L = [1,2,3]
>>> func(*L)
a=[1]
b=[2]
c=[3]
>>>
 

*演算子を使えば、引数にリストを展開して渡すことができる。
さらに、
**演算子を使えば、引数にキーワード引数としてディクショナリを展開して渡すことができる。

>>> D = { "b":"2", "c":"3", "a":"1"}
>>> func(**D)
a=[1]
b=[2]
c=[3]
>>>
 




lambda式
無名関数を生成する。が、単一の式しかもてない。


ドキュメンテーション文字列。
ドキュメンテーション文字列がかけるよ、というお話。




おしまい。
.

[Python][お勉強] 「Pythonチュートリアル」を読む(7) -- Pythonを電卓としてつかう

今日もPythonのお勉強。

数値
Pythonをbcのように使うお話。
複素数の虚数部はiじゃなくてj。

文字列
シングルクオートでもダブルクオートでも良い。
複数行にまたがる場合は、\(バックスラッシュ)を使ってもよい。


>>> "abcdefg\
... hijklmnop"
'abcdefghijklmnop'
>>>
 

な感じ。
raw文字列にすると・・・

>>> r"abcdefg\n\
... hijklmnop"
'abcdefg\\n\\\nhijklmnop'
>>>
 

のように、'\n'も展開されないし、バックスラッシュも意味がなくなる。
バックスラッシュの改行は改行コードに変換される。

バックスラッシュの他、複数行出力にトリプルクオートが使える。

>>> """
... abcdefg
... hijklmnop
... """
'\nabcdefg\n hijklmnop\n'
>>>
 


文字列の連結には+演算子が使える。

>>> "abcdefg" + "hijklmnop"
'abcdefghijklmnop'
 



文字列の繰り返しには*演算子が使える。

>>> "hoge" * 2
'hogehoge'
>>>
 


2つの隣接する文字列リテラルは自動で連結される。

>>> "hoge" "tara"
'hogetara'
>>>
 

ただし、リテラル以外であればエラー。

>>> "hoge".strip() "tara"
File "<stdin>", line 1
"hoge".strip() "tara"
^
SyntaxError: invalid syntax
>>>
 

と思いきや、左辺が文字列リテラルであれば、
右辺がリテラル以外でも問題なしの模様。

>>> "hoge" "hoge".strip()
'hogehoge'
>>>
 


文字列に添え字付けでアクセスすることもできる。

>>> "hoge"[1]
'o'
>>>
 

シーケンスなので。

同様に、スライシングも可。

>>> "hoge"[1:2]
'o'
>>>
 


注意点としては、変更不可であること。

>>> "hoge"[1] = 'a'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object does not support item assignment
>>>
 

hogeをhageにしようとしてもできない。
どうしてもhageがいい人は、

>>> "hoge"[:1] + 'a' + "hoge"[2:]
'hage'
>>>
 


のようにスライシングを利用しても良い。

スライスにでたらめなインデックス値を指定しても良い。
その場合には、Pythonにより適切に扱われる。

>>> "hoge"[100:1]
''
>>> "hoge"[100:10000]
''
>>>



負の値が指定された場合は、

>>> "hoge"[-1]
'e'
>>>
 

のように、最後の文字から何番目かを示していることになる。

ビルトイン関数len()は文字列の長さを返す。

>>> s = "abcdefg"
>>> len(s)
7
>>>
 



Unicode文字列もつかえる。

>>> u"Hello, World!"
u'Hello, World!'
>>>
 

また、raw-Unicode文字列なるものもある。

>>> ur"Hello,\u0020World!"
u'Hello, World!'
>>>
 

正規表現などを使うときに便利とのこと。

指定のエンコーディングを使ってUnicode文字列を8ビット文字列に変換したいときは

>>> u"あいうえお".encode('utf-8')
'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a'
>>>
 

のようにする。encode関数のパラメータは小文字を使うことが望ましい。

逆にエンコードデータからUnicode文字列にするときは、

>>> print unicode('\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a','utf-8')
あいうえお
>>>
 

のようにunicode関数を使用する。

リストも使えると。




おしまい。
.

2008年2月28日木曜日

[Apache][CodeReading] Apache2.2.8コードリーディング28日目

今日もApache2.2.8コードリーディング。

今日も、昨日と同じくDEBUGログまわり。
printf書式を実装している部分。

今日読んだところは、

  • FIX_PRECISIONローカルマクロ(apr_snprintf)/Apache2.2.8
  • conv_10_quad()/Apache2.2.8
  • conv_10()/Apache2.2.8
  • FALSEローカルマクロ(apr_snprintf)/Apache2.2.8
  • INT32_MINローカルマクロ(apr_snprintf)/Apache2.2.8
  • INT32_MAXローカルマクロ(apr_snprintf)/Apache2.2.8
  • APR_INT64_T_FMTマクロ/Apache2.2.8
らへん。
これらはapr_vformatterという関数からコールされている。

conv_10_quad()とconv_10()は、数値を数字列に変換する関数。
10進表記の文字列に変換する。
conv_10_quad()とconv_10()の違いは、64ビットか32ビットかの違い。
その名のとおり、quadは64ビットに対応する。

conv_10_quad()
この関数は"%lld"フォーマットに対応する。
で、以下、そのソース。

383 static char *conv_10_quad(apr_int64_t num, register int is_unsigned,
384 register int *is_negative, char *buf_end,
385 register apr_size_t *len)
386 {
387 register char *p = buf_end;
388 apr_uint64_t magnitude = num;
389
390 /*
391 * We see if we can use the faster non-quad version by checking the
392 * number against the largest long value it can be. If <=, we
393 * punt to the quicker version.
394 */
395 if ((magnitude <= APR_UINT32_MAX && is_unsigned)
396 || (num <= INT32_MAX && num >= INT32_MIN && !is_unsigned))
397 return(conv_10((apr_int32_t)num, is_unsigned, is_negative, buf_end, len));
398
399 if (is_unsigned) {
400 *is_negative = FALSE;
401 }
402 else {
403 *is_negative = (num < 0);
404
405 /*
406 * On a 2's complement machine, negating the most negative integer
407 * results in a number that cannot be represented as a signed integer.
408 * Here is what we do to obtain the number's magnitude:
409 * a. add 1 to the number
410 * b. negate it (becomes positive)
411 * c. convert it to unsigned
412 * d. add 1
413 */
414 if (*is_negative) {
415 apr_int64_t t = num + 1;
416 magnitude = ((apr_uint64_t) -t) + 1;
417 }
418 }
419
420 /*
421 * We use a do-while loop so that we write at least 1 digit
422 */
423 do {
424 apr_uint64_t new_magnitude = magnitude / 10;
425
426 *--p = (char) (magnitude - new_magnitude * 10 + '0');
427 magnitude = new_magnitude;
428 }
429 while (magnitude);
430
431 *len = buf_end - p;
432 return (p);
433 }
 

とりたてて面白いことをやっているわけではない。
あえて言うなら、
元の値から、10で割った後、10でかけて1桁目を0にした値を差し引いて
1桁目を取得していることぐらいか。
値そのものが、32ビットの範囲内であれば、conv_10()をコールする。

conv_10()
conv_10は大体conv_10_quad()と一緒。
やっていることもほぼ一緒。

APR_INT64_T_FMT
これは、"lld"と記述されている。それだけ。

他は特になし。



今日の分はここまで。

おしまい。
.

[Python][お勉強] 「Pythonチュートリアル」を読む(6) -- PYTHONSTARTUP

環境変数PYTHONSTARTUPに実行させたいスクリプトを指定できる。


$ cat a.py
print "Hello, World"
$ export PYTHONSTARTUP=a.py
$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
Hello, World
>>>
 

上記ではa.pyを指定している。内容はHello,Worldと画面に出すだけ。
このファイルは対話セッションと同じ名前空間で実行される。


おしまい
.

[Python][お勉強] 「Pythonチュートリアル」を読む(5) -- ソースコードのエンコーディング

ファイルのエンコーディングを指定する方法。


# -*- coding: エンコーディング名 -*-
 

というのをshbangの直後に置く。

使用できる標準エンコーディングは、ライブラリリファレンス参照とのこと。


おしまい
.

[Python][お勉強] 「Pythonチュートリアル」を読む(4) --インタプリタの起動

シェルの-cと同じ感じで起動する。


python -c コマンド [引数] ...
 


モジュールを指定して起動する。

python -m モジュール名 [引数] ...
 


スクリプト実行後、対話モードに入る。

python -i スクリプトファイル名
 


引数
sys.argvに入っている。
sys.argv[0]が第一引数。


プライマリプロンプト
起動すると>>>といったプロンプトが表示されるが、このプロンプトのこと。

セカンダリプロンプト
継続行に表示される...といったプロンプトのこと。



おしまい
.

[Python][お勉強] 「Pythonチュートリアル」を読む(3) -- GNU readline

特に必要なし。

できなきゃrlwrap使うんで。

.

[Python][お勉強] 「Pythonチュートリアル」を読む(2) -- 食欲

特に食欲はそそられませんでした。

ということで次。


.

[Python][お勉強] 「Pythonチュートリアル」を読む(1) -- まえがき

今日もPythonお勉強。

今日からPythonチュートリアルを読む。

まず前書き。

「初心者」、「中級者」、「多言語のエキスパート」のそれぞれについて
読み方が提案されている。

魅力的な提案だが、「超初心者」が載っていない。
ということで、最初から全部熟読する方向でいきます。

おしまい。
.

2008年2月27日水曜日

[Python][お勉強] 「Pythonチュートリアル」を読む(0) -- 志

「Pythonチュートリアル」という本を読む。
気になるところは、本家の原文も見ながら読む。

学んだことを出力することで理解を深めたい。
ということで、またもやインターネットのごみ、玉石混交の石の方、うんこ、量産予定。
検索エンジンでひっかかったらごめんなさい。

使用プロセスは以下のとおり。
1) 通勤電車の中で読む。
2) 出社したら人に隠れてすばやくここにアウトプット。
3) ことあるごとにPythonと戯れる。


仕事が忙しくなった状態でうまくいくかが懸念事項。
多分、毎日は無理っぽい。
ま、てきとーに。
.

[Apache][CodeReading] Apache2.2.8コードリーディング27日目

今日もApache2.2.8コードリーディング。
ひらメソッドでリーディング。

さて、まだApache起動直後の初期化中。
デバッグログを出力しようとしているところで、
printfのAPR版部分で、そのコア部分。

今日やったところは以下のとおり。

  • INS_CHARローカルマクロ(apr_snprintf)/Apache2.2.8
  • boolean_e列挙型/Apache2.2.8
  • NUM_BUF_SIZEローカルマクロ(apr_snprintf)/Apache2.2.8
  • apr_uint64_t/Apache2.2.8
  • apr_islowerマクロ/Apache2.2.8
  • NULローカルマクロ(apr_snprintf)/Apache2.2.8
  • apr_isdigitマクロ/Apache2.2.8
  • NUMローカルマクロ(apr_snprintf)/Apache2.2.8
  • STR_TO_DECローカルマクロ(apr_snprintf)/Apache2.2.8
らへん。

INS_CHARマクロ
バッファに1文字セットするマクロ。
中で、file_printf_flushがコールされる。
コードは、

255 #define INS_CHAR(c, sp, bep, cc) \
256 { \
257 if (sp) { \
258 if (sp >= bep) { \
259 vbuff->curpos = sp; \
260 if (flush_func(vbuff)) \
261 return -1; \
262 sp = vbuff->curpos; \
263 bep = vbuff->endpos; \
264 } \
265 *sp++ = (c); \
266 } \
267 cc++; \
268 }
 

な感じ。flush_funcは、関数へのポインタで、今回の場合は
file_printf_flush。

バッファがいっぱいになったら、file_printf_flushがコールされる。
file_printf_flush内で、バッファを出力すると、vbuffのcurposは
バッファの先頭をさすように更新されるので、262行目でspの値を
更新している。file_printf_flush内でバッファを出力しなかった場合は
curposは259行目で代入した値のままで、262行目で代入しても
値は同じ。

で、spのさしている先にc(文字)を代入している。
代入後sp++。ccの値も更新。

ccが何なのかは今のところ良く分からない。が、多分出力文字数ではないかと
思う。多分。

263行目の

263 bep = vbuff->endpos; \
 

の部分。
endposか、bepがどこかで更新されているのであれば、
ここでendposの値をbepに入れるのは分かるのだが、
少なくともINS_CHARマクロ、apr_vformatter関数では
endposも、bepも触っていないようだ。

このマクロは別のところでも使っているのだろうか・・・?

後のために、一応
  • INS_CHARマクロの263行目は必要なのか?
という疑問をメモっておく。
file_printf_flushでは触っていないが、snprintf用とかvnprintf用とかで
endposかbepどちらかが更新されるのだろうか。



apr_islower、apr_isdigit
この辺はctype.hのislower、isdigitそのまま。
#defineしているだけ。


NUMマクロ
'0'を差し引いて数字を数値にしているだけ。

STR_TO_DECマクロ
数字列をNUMマクロを使用して数値にしているだけ。


今日のところはここまで。
apr_vformatterは時間がかかりそう。。



おしまい。
.

[その他][本] 読みたい本

読みたい本お買い物リスト。

  • Pythonチュートリアル【読破】
  • Python関連の和書8割ぐらい。【やめ】(2008/4/11)
  • Pythonクックブック【読破】(2008/4/11)
  • みんなのPython【読破】(2008/4/22)
  • みんなのPython WEBアプリ編【読破】(2008/5/5)
  • Pythonクイックリファレンス【読破】(2008/5/5追加)
  • Jythonプログラミング【読破】(2008/6/15)
  • CTMCP
  • PAIP
  • ドラゴン本
  • Essentials of Programming
  • Lisp in Small Pieces (2008/2/28 追記)
  • Beautiful Code: Leading Programmers Explain How They Think (Theory in Practice (O'Reilly)) (2008/3/20追記)【読破】(2008/7/18)
  • プログラミングGauche【読破】(2008/3/20追記)

ぐらいか。今のとこ。
とりあえず、さしあたってはPython関連読み漁りで物欲を満たす予定。
CTMCP、ドラゴン本はきっとぞくぞくする系。多分。

PAIPは何が書いてあるか知りませんが、天才の人たちが面白いって言ってるっぽいので
読んでみたいと。

Essentials of Programmingは最初の方をちろっと読んだ。
どうも、第1版が面白いらしいが、第2版でいいや。
って、今や第3版が出てるのね。

上記Python系以外はじっくり読みたいので、なかなか手が出せず・・・。
読む日がくるのかどうかも不明。

-- 2008/3/20追記
Beautiful Code: Leading Programmers Explain How They Think (Theory in Practice (O'Reilly))
は、某ハッカーが面白そうだと言うんで、追加。

プログラミングGaucheは発売前から欲しかったものなんで、今日買ってきた。
うーむ。読みたい本だらけですなー。

[Python][お勉強] Python入門(71) - 「初めてのPython」終了

「初めてのPython」全て読み終えた。

使い方を学ぶには満足なんだけど、タイトルどおり物足りない感じ。
Perlで言うところの「Learning Perl」な感じ。そりゃそうか。

うーむ。
どうしてそうなっているのか、とか、背景にある概念とか思想とか・・・
が、書いてあると良かったのかも。

その辺って「Pythonチュートリアル」に書いてあるのかな?もしかして。

それともWEB上?
それだと物欲が満たされないのでした。


とりあえず、次は「Pythonチュートリアル」読破予定。
.

[Python][お勉強] Python入門(71) - フレームワーク

Tkinterとか、WindowsのCOMとか、Jythonとか、さらっと紹介している。

ごちそうさまでした。


おしまい。
.

[Python][お勉強] Python入門(70) - コーディングテクニック

今日もPython。。。

つまるところ、「Python Pocket Reference」、「Python Standard Library」、「Python in Nutshell」、
「Python Cookbook」を見なさいとのこと。

さらに、「ライブラリリファレンス」を見なさいとのこと。

ふーん。

で、27章完。


おしまい
.

[Apache][CodeReading] Apache2.2.8コードリーディング26日目

昨日はさぼり。でもちょっと読んだ。

読んだところは、

  • file_printf_flush()/Apache2.2.8
  • apr_file_write_full()/Apache2.2.8
だけ。

apr_file_write_full()は、apr_file_writeを使って、指定したバイト数を
がんばって出力する関数。
apr_file_writeはwriteシステムコールでEAGAINとかが返ってくると、
出力バイト数を減らしてリトライする。
apr_file_write_fullは、apr_file_writeで書き込めたバイト数を保持していて、
当初予定していた指定バイト数が全て出力されるまでがんばる。


file_printf_flushの方は、
apr_file_printf関数の中でも呼ばれているが、
多分主はapr_vformatter関数の中で呼ばれる方。

apr_vformatter関数は未読なので今のところ不明。

な感じ。

.

2008年2月26日火曜日

[Python][お勉強] Python入門(69) - 開発ツール

Pythonでの開発にはいろいろな開発ツールが使える。

その一部。

PyDoc
ドキュメンテーション文字列をいい感じに出力するツール。Pythonの標準ツール。

PyChecker
文法誤りでなく、実行してみないと露見しないミスを検知するらしい。
Pythonの標準ライブラリはこのチェッカーでチェックされている。

PyUnit
JUintみたいなもの。

doctest
テストツールだが、ドキュメンテーション文字列と連携して動作するらしい。

IDE
IDLEとか。

プロファイラ
profileモジュールなどが利用できる。

デバッガ
pdb。

プログラムの配布
Py2exe、Installer、freezeというツールがあるらしい。

実行速度の向上
「-O」は最適化フラグなのだそうだが、効果はいまいちとのこと。
詳細は「プログラミングPython 第二版」を参照のこと、だそうです。


その他
Vaults of Parnassusを見てね、だそうで。



おしまい。
.

[Python][お勉強] Python入門(68) - Pythonのツールセット

「初めてのPython」P525まで読んだ人は「Pythonプログラマ」を名乗って良いと書いてある。

それは置いといて、
Pythonのコア部分はひととおり見たとのこと。
この後は、ツールセットを学んでいくのだが10年はかかるとのこと。

Pythonのツールセット(抜粋)
ビルトイン
Pythonに標準でついているツールセット。文字列、リスト、ディクショナリなどのビルトインオブジェクト。

Pythonエクステンション
Pythonで書かれた、プログラマが独自に定義した関数やクラス、モジュールなどを指す。

Cエクステンション
CやC++を使って書くモジュールのこと。



おしまい。
.

[Python][お勉強] Python入門(67) - 簡易テストプログラム(sys.exc_typeの例)

sysモジュールのexc_typeとexc_valueを使用すると、
exceptブロック内で具体的にどのような例外が発生したかを知ることができる。

このテクニックを使うと簡単なテストプログラムを作成できる。

以下、その例。


import sys
log = open('testlog','a')
from testapi import moreTests, runNextTest, testName

def testdrive():
while moreTests():
try:
runNextTest()
except:
print >> log, 'FAILED', testName(), sys.exc_type
else:
print >> log, 'PASSED', testName()

testdrive()
 

だそうです。

実際に使うとしたら、PyUnit、doctestの方が良さそうではあるが、
sys.exc_typeは確認できる。



ふーん。
.

[Python][お勉強] Python入門(66) - raiseステートメント v2

raiseステートメントは以前やったのだが、
また出てきたので再度やる。

まず書式。


1) raise string
2) raise string, data
3) raise instance
4) raise class, instance
5) raise
6) raise class
7) raise class, arg
8) raise class, (arg, arg, ...)
  

1から3は以前やった。
4は受け渡すデータとしてインスタンスを指定している。
5も以前やったからパス。
6から8は、それぞれ以下と同じ意味。

6) raise class()
7) raise class(arg)
8) raise class(arg,arg,...)
 




おしまい。
.

[Python][お勉強] Python入門(65) - 文字列例外、クラス例外

今日もPythonのお勉強。

今日は、exceptの見出し行やraiseのname部についてやる。
まず文字列例外。

name部には文字列オブジェクトかクラスオブジェクト、またはインスタンスオブジェクト
を指定できるとのこと。で、そのうちの文字列オブジェクトの方から。

文字列例外
Pythonでは文字列オブジェクトを「例外」にすることができる。


>>> e = "abc"
>>> try:
... raise e
... except e:
... print 'abeshi'
...
abeshi
>>>
 

ここでの注意点は、raiseするオブジェクトとexcpetのname部に指定するオブジェクトの
リファレンスを同一にしなければならないということ。
文字列を指定できるのではなく、オブジェクトを指定できるということで、
さらにリファレンス値を同じにしなくてはならない。


クラス例外
クラス例外は文字列例外と違って、同一のオブジェクトかどうかでは実行するexceptブロックを決定しない。
クラス例外の場合は、「同一のオブジェクトツリー」に属しているかどうかで実行するexceptブロックを決定する。

>>> class C1: pass
...
>>> class C2(C1): pass
...
>>> class C3: pass
...
>>> try:
... raise C2
... except C1:
... print 'abc'
...
abc
>>> try:
... raise C1
... except C1:
... print 'abc'
...
abc
>>> try:
... raise C3
... except C1:
... print 'abc'
...
Traceback (most recent call last):
File "", line 2, in ?
__main__.C3: <__main__.c3>
>>>


クラスC1とC2、C3を用意した。C2はC1のサブクラスで、C3は独立している。
このとき、C2の例外はC1で受け取れる。つまりexcept C1:と記述したブロックが実行される。
C3の例外の場合C1では受け取れない。つまりC1とは別のオブジェクトツリーに属しているから。


また、クラス例外をraiseする際、Pythonの中では必ずインスタンスが必要になるとのこと。
上記の例では、

raise C1
 

と、クラス名を指定しているが、この実態は、

raise C1()
 

と同義、とのこと。

さらに、raiseでは必ずインスタンスが必要なのだが、発生する例外は
あくまで「クラス」なので、exceptブロックにはクラス名を指定する必要がある。


また、クラス例外用のクラスを定義する場合、
「強制されているわけでは無いが、クラス例外を自分で作る際は、ビルトイン例外のExceptionを継承すべき」とのこと。




おしまい。
.

2008年2月25日月曜日

[Apache][CodeReading] Apache2.2.8コードリーディング25日目

今日もApache2.2.8コードリーディング。

やっとこさっとこデバッグログ実出力完了。
場所はApache起動直後の初期化部分。
allocator、poolの初期化が終わって、
apr_thread_mutex_createをしようかというところ。

その中で、apr_pcallocという関数がコールされているんだけど、
APR_POOL_DEBUGを有効にしてコンパイルすると
apr_pcallocの代わりにapr_pcalloc_debugという関数が呼ばれるようになる。
んで、この関数の中をいくと、デバッグログを出力するところがあるんだけど、
そこ。


今日読んだところは、

  • apr_file_write()/Apache2.2.8
  • apr_wait_for_io_or_timeout()/Apache2.2.8
  • APR_STATUS_IS_EINTRマクロ(その他)/Apache2.2.8
  • APR_STATUS_IS_EINTRマクロ(NETWARE)/Apache2.2.8
  • APR_STATUS_IS_EINTRマクロ(WIN32)/Apache2.2.8
  • APR_STATUS_IS_EINTRマクロ(OS2)/Apache2.2.8
  • SOCEINTRマクロ/Apache2.2.8
  • SOCBASEERRマクロ/Apache2.2.8
  • APR_EINTRマクロ/Apache2.2.8
  • apr_pollset_poll()(select)/Apache2.2.8
  • apr_pollset_poll()(poll)/Apache2.2.8
  • get_revent()(poll)/Apache2.2.8
  • apr_pollset_poll()(port)/Apache2.2.8
  • get_revent()(port)/Apache2.2.8
  • APR_EGENERALマクロ/Apache2.2.8
  • apr_pollset_poll()(kqueue)/Apache2.2.8
  • apr_time_usecマクロ/Apache2.2.8
  • apr_time_secマクロ/Apache2.2.8
  • APR_USEC_PER_SECマクロ/Apache2.2.8
  • APR_TIME_Cマクロ/Apache2.2.8
  • APR_INT64_Cマクロ/Apache2.2.8
  • get_kqueue_revent()/Apache2.2.8
らへん。

やっとapr_pollset_poll全種類読破。
そして、apr_pollset_pollが読み終わったことで、apr_wait_for_io_or_timeout()も終了。

今日のメインはapr_file_write。
apr_file_writeは、簡単に言うと、バッファリングありの出力と、バッファリングなしの出力をこなす。
バッファリングありかどうかは、apr_file_t構造体にそういう設定があるので、
その設定値によって決まる。

書き込み時にEAGAINやEWOULDBLOCKを伴ってエラーになった場合、
apr_wait_for_io_or_timeout()をコールする。
リソースが一時的に使用不可になっているので、使用可能になるまで待つ。

使用可能になるまで待つのだが、その後使用可能になったのにもかかわらず
また一時的にリソースが使用不可になると、出力バイト数を半分にしてしまう。
半分にしては書き込み、また半分にしては書き込み、というのを、書き込めるか、エラーが
発生するか、writeシステムコールが0を返すまで繰り返される。

通常のファイルの場合、出力予定バイト数が0にさえなれば、
writeシステムコールは0を返すのだが、特殊ファイルの場合は
下手をすると無限ループってことも有り得るじゃないかなー。
確か、特殊ファイルの場合の出力バイト数が0だったときの動作って
未定義だった気がする。

まぁ、それは置いといて、
apr_file_writeを使って書き込みをした場合、
書き込めたバイト数が、書き込みたいバイト数(パラメータに渡したバイト数)と
違っていた場合、リソースが頻繁に「一時的に使用不可」になっている
ということか。


明日はこのapr_file_writeを使っているところから読む予定。



おしまい。
.

[Python][お勉強] Python入門(64) - assertステートメント

例外を故意に発生させるステートメントのひとつ。

書式は以下のとおり。


assert test, data
 

テストtestが偽であった場合、AssertionError例外がスローされる。
data部も指定されている場合は、dataも渡される。

上記は、

if __debug__:
if not test
raise AssertionError, data
 

と書き直すことができる。
__debug__は基本的には1。
起動オプション-Oを指定すると0になる。



おしまい
.

[Python][お勉強] Python入門(63) - raiseステートメント

例外を故意に発生させる方法のひとつにraiseステートメントがある。

書式は以下のとおり。


raise name
raise name, data
raise
 


ひとつめ、

raise name
 

は指定した例外名nameを故意に発生させる。

2つめ、

raise name, data
 

は、例外名nameを発生させ、dataとともに例外処理に渡す。
exceptブロックで、

except name, X:
 

と記述しておくと、変数Xにdataを受け取ることができる。


3つめ、

raise
 

は、直近に発生した例外を再度発生させる。




おしまい。
.

[Python][お勉強] Python入門(62) - try/finallyステートメント

tryステートメントはexcept、elseのほかに、finallyブロックを持つことができる。

書式は以下のとおり。


try:
<statements1>
finally:
<statements2>
 


finallyブロックは、tryブロック中で例外が発生しようがしまいが、必ず実行される。

注意点としては、except、elseとともに使用することができないこと。



おしまい
.

[Python][お勉強] Python入門(61) - try/except/elseステートメント

try/except/elseステートメント

書式は以下のとおり。


try:
<statements1>
except name1:
<statements2>
except name2, data:
<statements3>
except (name3, name4):
<statements4>
except:
<statements5>
else:
<statements6>
 


tryブロック中で例外が発生すると、exceptブロック中のステートメントが実行される。
どのexceptブロックが実行されるかは、exceptの後に記述されたnameによって判断される。
exceptブロックには4つの書き方がある。

1つめは、

except name1:
 

という書き方。name1はそのexceptブロックで捕捉したい例外名を書く。

2つめ。

exept name2, data:
 

name2はそのexceptブロックで捕捉したい例外名を書く。
dataに保持されたデータを受け取る。

3つめ。

except (name1, name2)
 

という書き方。ひとつのexceptブロックで複数の例外を処理したい場合に括弧を使って列挙する。

4つめ。

except:
 

例外名を記述しない書き方。全ての例外が捕捉される。ただし、別にexceptブロックが存在する場合は、そのexceptブロックで捕捉していない例外のみになる。

また、exceptブロックは何個書いても良い。

elseブロックはあってもなくても良い。
tryブロックで例外が発生しなかった場合にのみelseブロックは実行される。




おしまい。
.
--
つか、nameって何?

[Python][お勉強] Python入門(60) - 例外概要

今日もPython。

例外から。
まずは例外概要。

例外とは
プログラム処理の流れを変えるイベントの一種。

Pythonにおける例外処理
Pythonでは、tryステートメントが使用できる。
tryステートメントの種類は以下のとおり。

  • try/except
  • try/finally
  • raise
  • assert
try/except
自動的に発生した例外、あるいはコードによって発生した例外を検知し、処理する。

try/finally
finallyブロックは必ず実行される。「終了処理」などを記述できる。

raise
意図的に例外を発生させる。

assert
条件が満たされた場合に例外を意図的に発生させる。



例外の役割
エラー処理
tryステートメントを利用した場合、そのブロック中でエラーが発生すると
exceptブロック中の例外処理が実行される。例外処理後はtryブロックの後のコード
から実行される。

実行結果通知
コードが正しく実行されたかどうかを通知する、という目的にも使用できる。

特殊な条件への対応
例外処理のコードの中で対応するようにすれば、プログラム構造が簡単になる場合がある。

実行終了時の処理
finallyブロックを持たせることで、tryステートメント中の処理が終了する際に
確実に一定の処理を行わせることができる。

特殊な制御フロー
たとえば「バックトラッキング」をサポートする等。




おしまい
.

2008年2月24日日曜日

[Apache][CodeReading] Apache2.2.8コードリーディング24日目

今日もひらメソッドにてApache2.2.8コードリーディング。

今日読んだところは

  • apr_pollset_poll()(epoll)/Apache2.2.8
  • APR_RING_CONCATマクロ/Apache2.2.8
  • get_epoll_revent()/Apache2.2.8
  • apr_get_netos_errorマクロ(その他)/Apache2.2.8
  • apr_get_netos_errorマクロ(netware)/Apache2.2.8
  • apr_get_netos_errorマクロ(win32)/Apache2.2.8
  • apr_get_netos_errorマクロ(os2)/Apache2.2.8
  • apr_pollset_poll()(os2)/Apache2.2.8
  • sock_errnoマクロ/Apache2.2.8
  • apr_os2_sock_errno()/Apache2.2.8
  • APR_FROM_OS_ERRORマクロ/Apache2.2.8
  • APR_OS_START_EAIERRマクロ/Apache2.2.8
  • make_pollset()/Apache2.2.8
らへん。
pollしているところ。

場所はApacheの初期化部。
APR_POOL_DEBUGでAPR_POOL_DEBUG_VERBOSE_ALLOCをしている場合でDEBUGログを出力しようとしているところ。出力終わるのをpollして待っている感じ(だっけ?)。

apr_pollset_poll()(epoll版)
今日読んだ中では、まあ一番面白いかなぁ。
といっても、epoll_waitしているだけ。

面白いのはepollじゃなくて、やはりリング部。

apr_pollset_addなんかで、ファイルディスクリプタを監視対象に追加するんだけど、
その追加に失敗した場合、pfd_elem_t領域をdead_ringにつないでおく。

このapr_pollset_pollの中で、epoll_waitが終わると、
dead_ringにつないでいた失敗時に作成したpfd_elem_tをfree_ringにつなぎ、
当のdead_ringは空にセット。

うーむ。なるほど。
ここでdead_ringをfree_ringにつなぎなおすのね。

次に同じapr_pollset_tを使用して
apr_pollset_add等をすると、
このfree_ringからpfd_elem_t領域が取得される。

ふーん。

今日はこんだけ。

おしまい。
.

[Python][お勉強] Python入門(59) - 新スタイルクラス

ビルトインオブジェクトを継承したクラスは新スタイルクラスとなる。
そうでは無いクラスはクラシッククラスという。

新スタイルクラスはPython2.2で導入されたもの。



新スタイルクラスとクラシッククラスの違い

  • オブジェクトツリーの検索順が違う
  • 新スタイルクラスではスタティックメソッド、クラスメソッドが使用できる
  • 新スタイルクラスでは__slots__属性が使用できる。
  • 新スタイルクラスでは「プロパティ」を使用することができる。
  • 新スタイルクラスでは__getattribute__メソッドを使用することができる。

オブジェクトツリーの検索順
クラシッククラスの場合

class A: pass
class B(A): pass
class C(A): pass
class D(B): pass
class E(C): pass
class F(D, E): pass

a = F()
print a.X
 

とあった場合、変数Xを探す順番は、

① クラスF
② クラスD
③ クラスB
④ クラスA
⑤ クラスE
⑥ クラスC
 

となるらしい。
つまり、上下優先

新スタイルクラスの場合

class A(object): pass
class B(A): pass
class C(A): pass
class D(B): pass
class E(C): pass
class F(D, E): pass

a = F()
print a.X



とあった場合、変数Xの検索順は

①クラスF
②クラスD
③クラスE
④クラスB
⑤クラスA
⑥クラスC
 

となるらしい。
つまり左右優先


この辺は要注意。



スタティックメソッドとクラスメソッド
スタティックメソッドは、第一引数にインスタンスオブジェクトを渡さずに、
ほぼ通常の関数のように使用できるメソッド。
クラスメソッドは、第一引数にクラスを渡すことができるメソッド。

Python2.2以降であれば、クラシッククラスにも持たせることができるとのこと。
具体例は載っていないので良くわからない。


__slots__
インスタンスに持たせるインスタンス属性を特定のものに限定するのに使用する。
__slots__があるとインスタンスには指定された属性しかもてなくなる。


>>> class C1(object):
... __slots__ = ["aaa", "bbb"]
...
>>> a.aaa = 10
>>> a.bbb = 20
>>>
 

こんな感じ。
このとき、__slots__に指定されていない変数名を指定すると・・・


>>> a.X = [1,2,3,4]
Traceback (most recent call last):
File "", line 1, in ?
AttributeError: 'C1' object has no attribute 'X'
>>>
 

怒られる。

制約もつく。インスタンスに__dict__属性を持てなくなったりする。
もちろん__slots__に指定すればよいらしい。



プロパティ
プロパティを使用すると、インスタンス属性へのアクセスには、自動で対応するメソッドをコール
させることができるようになる。
__getattr__や__setattr__と違うのは、コールされるメソッド、対応するメソッドを指定しなければ
ならないこと。(指定できること)


で、その例。

>>> class C1(object):
... def getabc(self):
... return self._abc
... def setabc(self, x):
... self._abc = x
... abc = property(getabc,setabc,None,None)
...
>>> a = C1()
>>> a.setabc(10)
>>> a.getabc()
10
>>>
 

propertyのパラメータはそれぞれ、

getter、setter、del、docs
 

だそうです。



__getattribute__
存在しない属性へのアクセス時の__getattr__とは違って、全ての属性へのアクセスに対応する。
かなり扱いづらいらしい。無限ループに簡単に陥るかららしい。

詳細の記述はなし。



おしまい
.

[Python][お勉強] Python入門(58) - 属性の「隠蔽」

無理っす。



が、ネームマングリングで一見隠れているように見せることは可能。

ネームマングリング
classステートメント中の変数名を2つのアンダースコアで始まる名前にすると、
自動でクラス名が付加される。


class Spam:
__x = 10
 

というものがあった場合、自動で

_Spam_x

に変換される。

が、このネームマングリングの機能は「隠蔽」が目的ではないので外からアクセスできる。
あくまでインスタンス名の重複防止が主目的。




へぇ。

おしまい
.

[Python][お勉強] Python入門(57) - ビルトインオブジェクトの拡張

ビルトインオブジェクトを拡張するには、大きく2つの方法がある。

1つめはデリゲーションによる拡張。
もうひとつは継承による拡張。

デリゲーションの方は、たとえばリストを拡張したいのであればリスト用の
フックメソッドを実装してやる。

継承であれば拡張したい部分だけオーバーロードなりをしてやればよい。
多くの場合、デリゲーションよりも継承した方がコードは少なくなる。


ただし、注意点があって、先を読むと出てくるのだが、
ビルトインオブジェクトかobjectを継承してクラスを作る場合と
ビルトインオブジェクトかobjectをスーパークラスも含めて継承せずにクラスを作る場合と
では、オブジェクトツリーの検索順が違うとのこと。
詳細は後日。



ふーん。

おしまい。
.

[Python][お勉強] Python入門(56) - クラスとモジュール

クラスとモジュールの違いを良く認識しておいてくださいとのこと。


モジュール

  • データとロジックのパッケージ
  • Pythonのコードを収めたファイル、またはCエクステンションによって作られる。
  • インポートによって使用される。

クラス
  • プログラマが独自のオブジェクトを作るのに利用できる
  • classステートメントによって作成される
  • 「呼び出し」に対応できる。
  • モジュールの属性になる。

だそうで。


おしまい。
.

[Python][お勉強] Python入門(55) - 結合メソッドと非結合メソッド

非結合メソッドとは


クラス名.メソッド名(インスタンス名, ...)
 

という形でアクセスされたメソッドのこと。
この場合、第一引数にインスタンスオブジェクトを渡す必要がある。


結合メソッドとは

インスタンス名.メソッド名(...)
 

の形でアクセスされたメソッドのこと。
第一引数には自動的にインスタンスオブジェクトが渡される。


非結合メソッドはインスタンスと結合されていないから非結合メソッドか???
結合メソッドはインスタンスと暗に結合されているから結合メソッドか???


ま、そんな感じ。


おしまい。
.

[Python][お勉強] Python入門(54) - 引数によって機能が変わるメソッドを作る


class C:
def meth(self, x):
・・・・
def meth(self, x, y, z):
・・・・
 

というのは無理。
2番目に定義されたmethが有効になるだけ。


やるとしたら、

class C:
def meth(self, *args):
if len(args) == 1:
・・・・
elif type(arg[0]) == int:
・・・・
 

という形か、

class C:
def meth(self, x):
x.operation()
 

のような感じにするしかないとのこと。

だそうです。


おしまい。
.