モジュールと名前空間とclassのImport
Pythonには標準モジュールがある。使い方は一般的。
#Simple XML-RPC Serverの例 import xmlrpclib from xmlrpclib import Fault import SocketServer import BaseHTTPServer import sys import os
ここでのポイントはfrom。FROMを使うとローカルの名前空間にロードされる。
from xmlrpclib import Fault def xmlrpclib() : """...
とかくと上書きしてしまうので注意。
インポートされるライブラリパスは、環境変数に依存する。
カレントディレクトリ->PYTHONPATH(PATH書式)->インストールパス
ファイル名が、モジュール名になり、Pythonでの名前空間を表す。
#hoge.py def foo(): print "foo"
#sample.py import hoge hoge.foo()
ファイル名の代わりにディレクトリを使えば、名前空間をネストできる。
クラスに関しても同じようにインポートする。ただし、Javaのような「クラス名=モジュール名」の対応が100%成立すると限らない。
一方で、PHPのように、適当なファイル名でモジュールを作成する、いい加減さでうまくいくようなモノでもない。
Perlの use strict;をイメージするとよいかな。
PHPでのインポート
<?php require_once "Smarty.class.php"; require_once "Zend.php"; $smarty = new Smarty; $zend = new Zend;
- ファイル名とクラス名が一致しなく、銘々規則はいい加減でいい。手軽に使えるので便利
- 一方で、大人数で開発するときに、似た名前のファイルが増殖し、頭を抱える原因になる。
JavaScriptの場合、確固たる手法はない。
<script type="text/javascript" src="./js.cgi?type=initA&user=B" > </script> <script type="text/javascript"> document.write("<script...");//Scriptタグを書き出す eval( xmlHttpResult );//xmlHttpの結果をevalする </script>
バイトコードコンパイル
制御構造
Pythonの特徴
-
- do{}while() が無い
-
- do〜while好きは処理を工夫する
-
- switch がない
-
- elifを使う
-
- else if と書かない
-
- elif を使う
- else は使える
-
- do{}while() が無い
#C言語を母とする言語によく見られる while( ( c = input.getChar() ) != null ){ out.print( c ); } for ( var i =0;i<array.length();i++ ){ out.print( i + "="+array[i] + "\n" ); } #この形式はPythonではエラーになる(はず :あとで詳しく調べる )
では、どうするか? foreach文を使う。
for a in array : print a #enumerate()関数を使う for key , val in enumerate( array ): print key , "=", val
配列処理は、key=>val の対応が重要なのでループ変数よりIteratorの方が実用性が高い。だからこれで十分だ。
どうしても int = i ; が良いなら仕方がない
for i in range(1, len(array)): print i , "=", array[i]
と書けばいい。
while を使うStackの例
#stack = [0...99] #Pythonでは while len(stack) > 0: print stack.pop()
配列の扱い
PythonのプログラミングはJavaScriptに似ている。文法はまるで似ていないが。発想が似てる。
配列の動的インクリメント
Javascriptのばあい
var hoge; hoge[hoge.length] = "test1"; hoge[hoge.length] = "test2"; hoge[hoge.length] = "test3"; //hoge = { 0: "test1", 2:"test2", 3:"test3" }
Pythonの場合。
##配列のマージを利用する hoge[len(hoge):] = ["test1"] hoge[len(hoge):] = ["test2"] hoge[len(hoge):] = ["test3"] ##hoge = { 0: "test1", 2:"test2", 3:"test3" } ##Appendメソッドを使う hoge.append( "test1" ) hoge.append( "test2" ) hoge.append( "test3" ) ##hoge = { 0: "test1", 2:"test2", 3:"test3" }
もちろん、append()関数を使ってもいい。ただ、JavaScriptでも配列にappendすることよりも言語構造で処理することが多いので、こっちの書式がよく使われるのかな?。PHPやPerlでもappend()しないなぁ。
##注意) 配列のマージはappendより処理が重いよ。マニュアルによると、append推奨らしい。
ちなみにPHPの場合はとっても楽ちん
<?php hoge[]= "test1"; hoge[]= "test2"; hoge[]= "test3"; //hoge = a:3:{i:0;s:5:"test1";i:1;s:5:"test2";i:2;s:5:"test3";}
PHPだと「appendしる」みたいなことは書いていなく、これが自然な記述ってこと。楽だねぇ。オブジェクトがIteratorインタフェース実装してればどこで使っても問題ないみたい。
Javaだと、Collectionインタフェース実装したクラスにキャストして・・・それから・・・云々・・死ねる。Eclipseが発展してきた理由がわかる。補完無しだと腱鞘炎だ。
PHPのserialize関数はJSONっぽい文字列を返してくれるが、若干仕様が異なるのでそのままJavaScriptでevalは出来ない。まぁJSONを返すパッケージがあるのでそれを使えばいいさ。
モジュールをパッケージ化する
今度は、パッケージの作成方法
まず、パッケージとはモジュールの集合体。Pythonにおいて、以下のことが成立する
ディレクトリ構造 = パッケージ階層 ファイル名 = モジュール名
じゃぁパッケージ全体の設定はどうするんだ? __init_.py ファイルを設置する。(省略可)
#ディレクトリ構造 ./Amazon +- __init_.py +- AWS_Actount.py /products + __init__.py +-- /Book | +-- __init__.py +--/Video +-- __init__.py
などと__init__.pyが沢山出来ますよ。__init__.pyがあることでディレクトリがパッケージとして認知される。
パッケージ内の特定モジュールをLoadする。
これはJavaと同じ発想で良い。
//Java import java.io.*; import java.util.Hashtable; import java.util.Properties; #Python import Amazon.products import Video from Amazon
ここで、注釈: import X from のこと
//Javaだと import java.io.*; import java.util.Hashtable; import java.util.Properties;
java.utilを何度も書く。これが面倒だろ?
Pythonでは、Fromを使うことでSimpleにしている
javaを題材に例を作ると
#python import java.io.* from java.util import Hashtable, Properties # ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ # 共通部分 タプル
このシンプルな記法がPythonの特徴さ。
パッケージの銘々規則
変数名や関数名と同じ。ファイル名は[名前.py]と書く。 正規表現で書くと
[a-Z][a-Z0-9_]* または [a-zA-Z][a-zA-Z_0-9]* または (\l\s)(\w)
windowsはcase insensitiveだぞ?
Windows は大文字小文字を区別しないので、[名前.py]では不便なことが出てきそうですね?Windows95系には、ファイル名の文字数制限がある。*1
安全のために、パッケージの初期ロード(__init__.py)に内包するモジュール名を定義しておく。__all__ 変数を使う。
# ./sample/__init__.py __all__ = ["hoge", "FOO", "Bar"]
と書いておけば
from sample import *;
と全指定したときに __all__の中身で指定した「大文字小文字」でパッケージが読み込まれる。ファイル名を無視するようだ。
*1:win98を現役で使ってる開発者なんていないだろうけど
dir() パッケージの中身を調べる
dir(name) を用いるとそのモジュールで利用している、変数名を調べられる
import sys print dir(sys) # # #['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', '__stdin__', '_ #_stdout__', '_current_frames', '_getframe', 'api_version', 'argv', 'builtin_module_names', # 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'exc_c #lear', 'exc_info', 'exc_type', 'excepthook', 'exec_prefix', 'executable', 'exit', 'getchec #kinterval', 'getdefaultencoding', 'getfilesystemencoding', 'getrecursionlimit', 'getrefcou #nt', 'getwindowsversion', 'hexversion', 'last_type', 'last_value', 'maxint', 'maxunicode', # 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix' #, 'ps1', 'ps2', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'settrace', 'stderr #', 'stdin', 'stdout', 'subversion', 'version', 'version_info', 'warnoptions', 'winver'] print dir() # ['__builtins__', '__doc__', '__name__', 'sys']
なんにつかうの? filter(), map(), reduce()
正直何に使うんだろう?と一瞬わからなかった。こいつら。filter, map, reduce。理解すると便利なので覚えよう。
- 配列のそれぞれに対して、Callbackしてくれる関数群。
- prototype.js の Enumerable だと思えばいい。
- PHPだとarray_walk()。
- 機能は__iter__()とGenerator使えば実現できる
def f(x): return x%2 == 0 #偶数かどうか調べる print filter( f, range(1,10) ) # [ 2,4,6,8,]
JavaScript (prototype.js) ならこうなる
<script type="text/javascript" src="prototype.js" ></script> <script type="text/javascript"> var hoge = $R( 1,10, true ); hoge = hoge.findAll( function(v){ return v%2==0; } ); document.write(hoge); //hoge = 2,4,6,8 </script>
覚え方、配列にフィルタを掛ける。だから filter() ここは試験に出ますぉ
ちなみにPHPならこんなことになる
<?php $hoge = range(1,9); $hoge = array_filter( $hoge, create_function( '&$v, $i', 'return !($v&1);' ) ); var_dump($hoge);
$hoge = array_filter() が特徴的かな。
PHPは結果を代入することが多い、代入忘れがエラーの元に。ちなみにfilter()も結果を変数に代入が必要だよ。JavaScriptは代入不要。これは、Arrayの親クラスEnumerableが代入をやってくれてるから。
map()
prototype.jsだと、Enumerable.each() に相当する。Iteratorだとわかれば後は簡単。
#pow seq = range( 1,10 ); seq = map( lambda x : x*x, seq ) print seq
reduce()
これは、PythonのドキュメントよりPHPのarray_reduce()のdocの説明がわかりやすい。
array_reduce() applies iteratively the function function to the elements of the array input, so as to reduce the array to a single value. If the optional initial is available, it will be used at the beginning of the process, or as a final result in case the array is empty. If the array is empty and initial is not passed, array_reduce() returns NULL.
array_reduce() は、配列 input の各要素に function 関数を繰り返し適用し、 配列を一つの値に減らします.オプション intial が利用可能な場合、処理の最初で使用されたり、 配列が空の場合の最終結果として使用されます。 配列が空で initial が渡されなかった場合は、 array_reduce() は NULL を返します。
使用例。
#階乗 seq = range( 1,10 ); print map( lambda x,y : x*y, seq ) #[1, 4, 9, 16, 25, 36, 49, 64, 81]
条件分岐に使える 例外処理
私は、Javaでtry 〜 catch を条件分岐の代わりに使うのは非推奨と習った。富豪プログラミングの立場では推奨かもしれない。
Pythonでは条件分岐に使えと言わんばかりの使用になっている
Pythonの [try 〜 catch]
- try:
- except A:
- except :
- else:
- finally:
のセット。
try: #statements except NameErorr, var : #Exceptionに与えられた文字列も同時に取得できる print var except ( IOError, RuntimeError ):#複数のExceptionをまとめてCatch print except : #全部のExceptionをCatch print else : #例外なしで無事通過したとき print "ok" finally: #全ての後処理 print "end"
例外を投げる
throw Exceptionと書きたいところだが、raise とかく
raise Excetion , "エラーです" raise Exception("エラーです")
なぜ2番目の書き方がゆるされるか? ExceptionがClassだから。
ExceptionがClassということは、ユーザー定義のExceptionを利用できる
class SampleExcepion(Exception): #Exceptionを継承 def __init__(self, value): self.value = value def __str__(self): return repr(self.value) try: #statements raise SampleExcepion("foooo") except SampleExcepion, e : print e.value ##output # 'foooo'
with 構文のサポート
ECMAScriptには with 文というモノがある
withを使えば、名前空間を変えることが出来る デフォルトの名前空間は window
#type="text/javascript" with( window.document.location ){ alert("test");//関数が見つからないエラーになる window.alert("test");//実行される href="http://www.yahoo.co.jp";//実行される }
これと同じではないが、Pythonには withがある。
withを使うことで、finallyの処理が華麗になる。
#with構文 with open("myfile.txt") as f: try: for l in f: print l except: print "some error occured" finally: f.close()
Javaなどでtry -catch - finally を使おうとすると変数のスコープで苦労する。
その問題を解決してくれるのがwith.withこの使い方はJavaScriptにも応用すると便利だよ。*1
*1:JavaScriptを実行するブラウザがwithをサポートしているか調べておくこと。ちなみにWSHでは使うことが出来た
PythonのDocStringの書き方
def function() : """This is a Sample function.""" print
- 関数宣言 def の次行に書く。
- 先頭は大文字にする
- 末尾はピリオドで終わる
- 文字列は引用三つ """ でquoteする
なぜPythonを始めるか?
- PHPのPEARがいまいち。
- PerlのCPANはMSDN並の巨大ダンジョンで困った。
- Pythonアイコンがかっこいい。Rubyのアイコンはダサイ。
- Ruby処理系はやっぱ遅い気がする。
- なんだかんだ言ってPHPはWEBワールド限定。。。
- Perlは記号が多くて嫌い。
Pythonの特徴的なところ。
- { } は使わない
- インデントが { } の代わり
- 新しいインデントの開始時には : を使う
- print 関数だけは [,] でつなげばいい。*1
- for x in a が使える*2
- 文字列の繰り返しに "-" * 50 が使える
- 配列の定義方法
- 配列の扱いが特徴的
- a[0:] 最初から
- a[0:3] a[0], a[1], a[2]
- a[0:10:-1] [9,8,7,6,5,4,3,2,1,0]
- 変数にまとめて代入できる
Pythonのいけてないところ
- 日本語ユーザーが少ない。
- ドキュメントが貧弱
- ドキュメントの日本語訳がもさい
- 本が売ってない
- 誤字多すぎ
Pythonの良いところ
とにかく、日本でPythonが流行してくれないことには。どうしようもない問題。国内だとRubyに確実に負けてます。個人的にはRubyブームは一過性じゃないかなと。
現在勉強した項目
PythonのLambda
lambda で関数への参照を返せる
def f(n): """lambdaサンプル""" return lambda x : x + n
JavaScriptだとこんな感じかな?
var f = function(n){ return function(x){ return n+x; } }
JavaScriptの関数をイメージすると理解しやすかった。
関数の引数は配列で渡す
ここがちょっと特徴的か?
関数のデフォルト値
def f( i, foo = "bar" ): print foo print i f(10) # # bar # 10
関数のデフォルト値2
def f( i, foo="bar", hoo="book" ): print i print foo print hoo f( 100, hoo="comic" ) #100 #bar #comic
デフォルト指定があれば引数は省略可。省略する引数にnullを入れなくて良い。
必要な要素だけ名前指定で書けばいい。
PHP なら null で埋める。
<?php public function f( $i, $foo = "var", $hoo = "comic" ){ echo $i; echo $foo; echo $hoo } f( 100, null, "comic" ); ?>
nullも省略して func( $i , , , ,); と書いても良いけれど。わかりにくくなるのでNULLつかってる。
Javascriptでもだいたい同じ。
JavaScriptはちょっと手続きが多いかな。
<script type="text/javascript"> var f = function( i, foo, hoo){ i = i; foo = foo || "var"; hoo = hoo || "book"; document.writeln(i); document.writeln(foo); document.writeln(hoo); } f( 100, null, "comic" ); </script>
Javaだと・・・タイプ量が・・考えたくない(w
関数のデフォルト値3
デフォルト値と可変引数を使うと、さぼれる。
Pythonだと楽で良いかな。JavaScriptだとfunciton.argmentオブジェクトを使う。
def f( i, *foo, **a ): for x in foo :print x print i f(10, "hoge", "moe", "tun") # hoge # moe # tun # 10
tupleとlist
タプル。配列の一種。
ここらでPython配列まとめ。
Python配列には2種類ある
- A 可変長
- B 固定長
- 固定長な配列
- C言語っぽい配列
- 文字列(string)
- tuple
- Set
と分類されてる。
何が違うか?変数の作り方を見れば一目瞭然だろう。
#List list = ["abc", "def", "ghi"] #Tuple tuple = ( "abc", "def", "ghi") #Dictionary dic = {"abc": "123", "def": "456", "ghi" : "789"} #Set sets = set(["sony", "apple", "sharp", "apple", "sharp", "sony"]) #sets=['sony','apple','sharp']
で、タプルは、オブジェクトというより言語構造に近い。
#タプルを使った例 a = 1,2,3 x,y,z = a #こんなモノもタプルです #引数がタプルで、戻り値もタプルな例 def f(x,y,z): return x,y,z print f(*a) #(1,2,3) a,b,c = f(1,2,3) #a =1, b=2, c=3
関数に使うと便利だと思うよ。rubyも、この形式取り入れてますよね。
関数の定義に使うので、配列形式というより、言語構造だと思う。
Set ユニーク値
配列の値に重複を許さない。配列のキーとして使うのかな。
#set()の例 print set([1,2,3,4,4,3,2,1])#1,2,3,4 a = set("google") #o,l,e,g b = set("yahoo") #y,a,o,h print a - b #e,l,g print b - a #y,a,h
Dictionary 辞書式配列
一般的に連想配列と呼ばれるモノ。JSON形式。あえて説明の必要はないと思うが。JavaでもDictionaryクラス(Hashtable, Properties)になる。
#Dictionary dic = {} # {} dic["a"] = "apple" # {'a':'apple'} dic["c"] = "cupple" # {'a':'apple', 'c':'cupple'} del dic["a"] # {'a':'apple'} dic["p"] = "people" # {'a':'apple', 'p':'people'} dic["s"] = "sample" # {'a':'apple', 'p':'people', 's':'sample'} dic.keys() # ['a', 'p', 's'] "a" in dic # True dic.has_key("s") # True
Dictionary配列は関数を使って増やすことも出来る
#関数を用いた例 dict(j="jingle", "t"="tinkle") dict([("s", "simple"), ("a", "ample")])
リストを文章で理解させる
filter()を使わず、map()を使わず、値をチェックする。そんな方法。
かなり特徴的
配列から、偶数を取り出し、各要素を2乗する処理。
さっきのmap()とfilter()を使うとこうなる
def f(x): return x%2 == 0 seq = filter( f, range(1,10) ) seq = map( lambda x : x*x, seq ) print seq
これを、英文で書いても、Pythonは理解してくれますよ。ってことらしい。
seq = range(1,10) print [ x*x for x in seq if x%2==0 ] # x*x の x は seq にある要素で 偶数のもの
配列の値のチェックとか、条件分岐くらいPythonが理解してくれますよ ってこと。
配列が英文っぽく書けますよってことがポイントらしい。
英文が
(x) for x in array if x is something
これが日本語なら、
この配列の要素 は (x) 、array の各要素xで x が something のもの
ってことか。
配列の中をもうちょっと英文っぽくすると。。。
this array is consits of (x) for x in array if x is something.
filterやlambdaを使わわない、だからコードとコメントが減って楽になる。「ソースに語らせる」と良いソースコードが書けるよってことだろうね。
英文のドキュメントには List Comprehension (Pythonが配列表現を理解する)と書いてある。
英文風に書けるので便利でしょ? ってことらしい。
英語が使えない俺には便利がさがいまいち理解できない。
#空白が含まれる配列を受け取った、どうしよう fruit = [" apple " , " orange", "banana", "mango "] #Pythonが解決します fruit = [ name.strip() for name in fruit ]
この場合、『 [ ]の中身は、(name.strip()) で、name は fruit の中身 』 とPythonが解釈します
ってことらしい。
この機能、たぶん使わない。 だってJavaScriptやPerl、PHP書いてる人がソース見ても何のことかわからん。Pythonユーザーからすると、「それは読めばわかるだろ。」ってことだろうなぁ。
配列のループにEnumerateとIterate
配列をforループで順次取り出すには配列毎に便利なメソッドが用意されている
Sequenceの場合
a = "goooooooooooogle" for x,y in enumerate( a ): print x, " = ", y
Dictionaryの場合
a = {"Perl","Larry","Python":"Guido", "ruby":"Matz"] for x,y in a.iteritems(): print x, ":", y
他に、sorted,reversed で整理も出来る。
配列の比較
配列は、比較できる。前から順番に調べていき、違いが見つかったらそこでストップする。そこから後ろは評価されない。前から二つずつ値を取り出して調べる。
(1, 2, 3) < (1, 2, 4) [1, 2, 3] < [1, 2, 4] 'ABC' < 'C' < 'Pascal' < 'Python' (1, 2, 3, 4) < (1, 2, 4) (1, 2) < (1, 2, -1) (1, 2, 3) == (1.0, 2.0, 3.0) (1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4)
配列の型を超えて比較可能。