ファイルからのデータ入力
MySQLを始めて勉強中。データベースとテーブルを作成した後、既存のcsvファイルをテーブルに流し込む操作をやってみた。
最初にテキストの例のとおりに以下のコマンドでやったみた。
mysql> load data infile "指定ファイルの絶対パス" into table テーブル名 fields terminated by "," lines terminated by "\n";
するとこんなエラーになった。
ERROR 13 (HY000): Can't get stat of '指定ファイルの絶対パス' (Errcode: 2)
そこで調べてみると、ここに(http://mlog.euqset.org/archives/ml@mysql.gr.jp/14306.html)解決策が出ていた。
なんでもload data infileはMySQLのサーバ側にファイルを読み込ませる文らしい。
mysqlユーザではサーバマシンの指定したファイルにアクセスできないのでエラーになるみたい。
一方、LOAD DATA LOCAL INFILEという文だとMySQLのクライアント側にファイルを読み込ませることができるらしいので
早速試してみるとうまくいった。
mysql> load data local infile "指定ファイルの絶対パス" into table テーブル名 fields terminated by "," lines terminated by "\n"; Query OK, 3 rows affected (0.00 sec) Records: 3 Deleted: 0 Skipped: 0 Warnings: 0
Bridgeパターン
結城浩さんの「Java言語で学ぶデザインパターン入門」を題材にpythonでデザインパターンを書いてみる。
今回の題材はBridgeパターン。このパターンは機能のクラス階層と実装のクラス階層を結びつけるというものらしい。
まずは機能のクラス階層と実装のクラス階層とは何なのかってことから勉強。
あるクラスclsがあって、clsに新しい機能を追加する(新しいメソッドの追加)ときにはclsのサブクラスとしてcls2をつくる。
これで一段階のクラス階層ができる。さらにcls2に新しい機能を追加するならcls2のサブクラスcls3をつくる。これで二段階の
クラス階層ができて、この階層は機能の追加のためにつくられた階層となる。これを機能のクラス階層とすると。
これに対して、あるクラスclsではメソッドの宣言だけを行い、そのメソッドの実装をclsのサブクラスcls2で行った場合、clsとcls2に
よってできるクラス階層を実装のクラス階層とする。
クラス階層が1つだと機能のクラス階層と実装のクラス階層が混ざってしまい、クラス階層が複雑になりプログラムの見通しが悪く
なる危険がある。そこで、機能のクラス階層と実装のクラス階層を2つの独立したクラス階層に分けることが大事みたい。しかし、分けただけではダメで2つのクラス階層をつなぐことが必要。Bridgeパターンはそのつなぐ役割を果たす。
サンプルプログラム(bridge.py) は何かを表示するというもの。具体的には以下のよう。
まずDisplayクラス
import random
import sys
class Display(object):
def __init__(self, impl):
self.impl = impl
def opening(self):
self.impl.rawOpening()
def printing(self):
self.impl.rawPrinting()
def closing(self):
self.impl.rawClosing()
def display(self):
self.opening()
self.printing()
self.closing()このクラスは機能のクラス階層の最上位のクラス。コンストラクタのimplは実装を表すクラスのインスタンスが渡される。
このインスタンスが2つのクラス階層をつなぐ。
次はCountDisplayクラス
class CountDisplay(Display):
def __init__(self, impl):
super(CountDisplay, self).__init__(impl)
def multiDisplay(self, times):
self.opening()
for i in range(times):
self.printing()
self.closing()このクラスはDisplayクラスに指定回数表示するという機能(multiDisplayメソッド)を追加したもの。
よってこれは機能のクラス階層。
次はDisplayImplクラス
class DisplayImpl(object):
def rawOpening(self):
pass
def rawPrinting(self):
pass
def rawClosing(self):
passこのクラスは実装のクラス階層の最上位のクラス。Displayクラスのopening,printing,closingメソッドに対応するメソッドの
宣言のみ。
次はStringDisplayImplクラス
class StringDisplayImpl(DisplayImpl):
def __init__(self, st):
self.st = st
self.width = len(st)
def rawOpening(self):
self.printLine()
def rawPrinting(self):
print "|%s|" %self.st
def rawClosing(self):
self.printLine()
def printLine(self):
print "+%s+" %("-"*self.width)このクラスはDisplayImplクラスのサブクラスとしてメソッドを実装。ここは実装のクラス階層。
ここにさらにクラスを追加して、ランダム回数表示する処理を実現するにはどうするか?
機能のクラス階層に追加すれば良いのではってことでRandomDisplayクラス
class RandomDisplay(CountDisplay):
def random_Display(self, times):
self.multiDisplay(random.randrange(times))さらにクラスを追加して、テキストファイルの内容を表示する処理を実現するにはどうするか?
実装のクラス階層に追加すれば良いのではってことでTextDisplayImplクラス
class TextDisplayImpl(DisplayImpl):
def __init__(self, textfile):
self.textfile = textfile
def rawOpening(self):
self.f = open(self.textfile)
def rawPrinting(self):
print self.f.readlines()[0]
def rawClosing(self):
self.f.close()さらにクラスを追加して、
<> <*> <**> <***>
とか、
|- |##- |####- |######- |########- |##########-
みたいな模様を表示するにはどうするか?
今度は機能と実装の両階層に追加すれば良いのではってことでIncreasingDisplayクラスとDecoDisplayImplクラス
class IncreasingDisplay(CountDisplay):
def __init__(self, impl, increase):
super(IncreasingDisplay, self).__init__(impl)
self.increase = increase
def increasing_Display(self, max_number):
self.max_number = max_number
for i in range(0, max_number, self.increase):
self.multiDisplay(i)
class DecoDisplayImpl(DisplayImpl):
def __init__(self, start, deco, last):
self.start = start
self.deco = deco
self.last = last
def rawOpening(self):
sys.stdout.write(self.start)
def rawPrinting(self):
sys.stdout.write(self.deco)
def rawClosing(self):
sys.stdout.write("%s\n" %(self.last))最後に動作テスト部分
if __name__=="__main__":
d1 = Display(StringDisplayImpl("Hello, Japan."))
d2 = CountDisplay(StringDisplayImpl("Hello, World."))
d3 = CountDisplay(StringDisplayImpl("Hello, Universe."))
d4 = RandomDisplay(StringDisplayImpl("Hello, Random."))
d5 = Display(TextDisplayImpl("newfile.txt"))
d6 = IncreasingDisplay(DecoDisplayImpl("<", "*", ">"), 1)
d7 = IncreasingDisplay(DecoDisplayImpl("|", "#", "-"), 2)
d1.display()
d2.display()
d3.display()
d3.multiDisplay(5)
d4.random_Display(5)
d5.display()
d6.increasing_Display(4)
d7.increasing_Display(12)実行結果は以下。
C:\works\python\book1>python bridge +-------------+ |Hello, Japan.| +-------------+ +-------------+ |Hello, World.| +-------------+ +----------------+ |Hello, Universe.| +----------------+ +----------------+ |Hello, Universe.| |Hello, Universe.| |Hello, Universe.| |Hello, Universe.| |Hello, Universe.| +----------------+ +--------------+ |Hello, Random.| |Hello, Random.| |Hello, Random.| +--------------+ test! test! test! <> <*> <**> <***> |- |##- |####- |######- |########- |##########-
Abstract Factoryパターン
結城浩さんの「Java言語で学ぶデザインパターン入門」を題材にpythonでデザインパターンを書いてみる。
今回の題材はAbstract Factoryパターン。名前の通り抽象的な工場で、抽象的な部品を組み合わせて抽象的な製品を作るらしい。
わかりにくいが、要は部品の具体的な実装は気にせずに部品を組み立てて製品としてまとめてしまうというものみたい。
具体的な実装はサブクラスで行う。
サンプルのプログラムは階層構造を持ったリンク集をHTMLファイルとして作るもの。
はじめに抽象的な工場、部品、製品を含む部分(factory.py)。
# -*- coding: utf-8 -*-
class Item(object):
def __init__(self, caption):
self.caption = caption
def makeHTML(self):
pass
class Link(Item):
def __init__(self, caption, url):
super(Link, self).__init__(caption)
self.url = url
class Tray(Item):
def __init__(self, caption):
super(Tray, self).__init__(caption)
self.tray = []
def add(self, item):
self.tray.append(item)
class Page(object):
def __init__(self, title, author):
self.title = title
self.author = author
self.content = []
def add(self, item):
self.content.append(item)
def output(self):
self.filename = "%s.html" %self.title
writer = open(self.filename, "w")
writer.write(self.makeHTML())
writer.close()
print "%sを作成しました。" %self.filename
def makeHTML(self):
pass
class Factory(object):
@classmethod
def getFactory(cls, classname):
module, kls = classname.rsplit(".", 1)
return getattr(__import__(module), kls)()
def createLink(self, caption, url):
pass
def createTray(self, caption):
pass
def createPage(self, title, author):
passItemクラスはLinkクラスとTrayクラスを統一的に扱うために両者のスーパークラスになる。
LinkクラスはHTMLのリンクを抽象的に表現したクラス。Trayクラスはaddメソッドを使って複数の項目をひとまとめにする。
PageクラスはHTMLページ全体を抽象的に表現したクラス。addメソッドで項目を追加、outoutメソッドで自分自身の内容を
ファイルに書き込む。
Factoryクラスは抽象的な工場。getFactoryメソッドはクラス名を指定して工場のインスタンスをつくる。
getattr()関数は指定したオブジェクトの属性を返してくる。ここではclassnameで指定されたクラスのモジュールをインポート
して、モジュール内のクラスのインスタンスが返り、そのインスタンスを新しくつくってgetFactoryメソッドの戻り値にしている。
次に動作テスト用の実行部分(abstract_factory_main.py)。
# -*- coding: utf-8 -*-
from factory import *
import sys
factory = Factory.getFactory(sys.argv[1])
asahi = factory.createLink("朝日新聞", "http://www.asahi.com/")
yomiuri = factory.createLink("読売新聞", "http://www.yomiuri.co.jp/")
us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/")
jp_yahoo = factory.createLink("Yahoo!Japan", "http://www.yahoo.co.jp/")
excite = factory.createLink("Exite", "http://www.excite.com/")
google = factory.createLink("Google", "http://www.google.com/")
traynews = factory.createTray("新聞")
traynews.add(asahi)
traynews.add(yomiuri)
trayyahoo = factory.createTray("Yahoo!")
trayyahoo.add(us_yahoo)
trayyahoo.add(jp_yahoo)
traysearch = factory.createTray("サーチエンジン")
traysearch.add(trayyahoo)
traysearch.add(excite)
traysearch.add(google)
page = factory.createPage("LinkPage", "name")
page.add(traynews)
page.add(traysearch)
page.output()抽象的な工場で抽象的な部品をつくり、抽象的な製品を組み立てる。具体的な工場のクラス名はコマンドラインの引数で
指定する。この引数からgetFactoryで工場をつくって変数factoryに代入する。後はLink,Trayをつくってひとまとめにして
から、Pageをつくってoutput。
ここからは具体的な工場、部品、製品を含む部分(listfactory.py)。
import factory
class ListFactory(factory.Factory):
def createLink(self, caption, url):
return ListLink(caption, url)
def createTray(self, caption):
return ListTray(caption)
def createPage(self, title, author):
return ListPage(title, author)
class ListLink(factory.Link):
def __init__(self, caption, url):
super(ListLink, self).__init__(caption, url)
def makeHTML(self):
return ' <li><a href="%s">%s</a></li>\n' %(self.url, self.caption)
class ListTray(factory.Tray):
def __init__(self, caption):
super(ListTray, self).__init__(caption)
def makeHTML(self):
self.buffer = []
self.buffer.append("<li>\n")
self.buffer.append("%s\n" %self.caption)
self.buffer.append("<ul>\n")
for item in self.tray:
self.buffer.append(item.makeHTML())
self.buffer.append("</ul>\n")
self.buffer.append("</li>\n")
return "\n".join(self.buffer)
class ListPage(factory.Page):
def __init__(self, title, author):
super(ListPage, self).__init__(title, author)
def makeHTML(self):
self.buffer = []
self.buffer.append("<html><head><title>%s</title></head>\n" %self.title)
self.buffer.append("<body>\n")
self.buffer.append("<h1>%s</h1>\n" %self.title)
self.buffer.append("<ul>\n")
for item in self.content:
self.buffer.append(item.makeHTML())
self.buffer.append("</ul>\n")
self.buffer.append("<hr><address>%s</address>" %self.author)
self.buffer.append("</body></html>\n")
return "\n".join(self.buffer)ListFactoryクラスはFactoryクラスのcreateLink,createTray,createPageを実装。単にListLink,ListTray,ListPageのインスタンス
を返すだけ。
ListLinkクラスはmakeHTMLメソッドを実装してHTMLの断片をつくる。ListTrayクラスもmakeHTMLメソッドを実装。HTMLの断片をリストに
集めて最後につなげる。ListPageクラスでもmakeHTMLメソッドを実装してページの構成をつくる。
最後に別の具体的な工場を含む部分(tablefactory.py)。
import factory
class TableFactory(factory.Factory):
def createLink(self, caption, url):
return TableLink(caption, url)
def createTray(self, caption):
return TableTray(caption)
def createPage(self, title, author):
return TablePage(title, author)
class TableLink(factory.Link):
def __init__(self, caption, url):
super(TableLink, self).__init__(caption, url)
def makeHTML(self):
return '<td><a href="%s">%s</a></td>\n' %(self.url, self.caption)
class TableTray(factory.Tray):
def __init__(self, caption):
super(TableTray, self).__init__(caption)
def makeHTML(self):
self.buffer = []
self.buffer.append("<td>")
self.buffer.append('<table width="100%" border="1"><tr>')
self.buffer.append('<td bgcolor="#cccccc" align="center" colspan="%s"><b>%s</b></td>' %(len(self.tray), self.caption))
self.buffer.append("</tr>\n")
self.buffer.append("<tr>\n")
for item in self.tray:
self.buffer.append(item.makeHTML())
self.buffer.append("</tr></table>")
self.buffer.append("</td>")
return "\n".join(self.buffer)
class TablePage(factory.Page):
def __init__(self, title, author):
super(TablePage, self).__init__(title, author)
def makeHTML(self):
self.buffer = []
self.buffer.append("<html><head><title>%s</title></head>\n" %self.title)
self.buffer.append("<body>\n")
self.buffer.append("<h1>%s</h1>\n" %self.title)
self.buffer.append('<table width="80%" boder="3">\n')
for item in self.content:
self.buffer.append("<tr>%s</tr>" %item.makeHTML())
self.buffer.append("</table>\n")
self.buffer.append("<hr><address>%s</address>" %self.author)
self.buffer.append("</body></html>\n")
return "\n".join(self.buffer)実際に実行するときは、
C:\works\python\book1>python abstract_factory_main.py listfactory.ListFactory LinkPage.htmlを作成しました。
とすると、箇条書きを元にしたデザインのHTMLファイルがつくられる。
C:\works\python\book1>python abstract_factory_main.py tablefactory.TableFactory LinkPage.htmlを作成しました。
とすると、表組みを元にしたデザインになる。
Builderパターン
結城浩さんの「Java言語で学ぶデザインパターン入門」を題材にpythonでデザインパターンを書いてみる。
今回の題材はBuilderパターン。複雑な構造のものを一気に組み立てるのは難しいので、事前に全体を構成する各部分をつくって
段階を踏んで構造を持ったインスタンスを組み上げていくもの。
サンプルになっているのはこのパターンを使って文書を作成するプログラム(builder.py)。
Builderクラスで文書作成用のメソッドを決めて、Directorクラスでそのメソッドを使って文書をつくる。
どんな文書にするかはBuilderクラスのサブクラスで決まるというもの。
まずBuilderクラス
# -*- coding: utf-8 -*-
class Builder(object):
def makeTitle(self, title):
pass
def makeString(self, st):
pass
def makeItems(self, items):
pass
def closing(self):
passここではメソッドの宣言だけ。
次はDirectorクラス
class Director(object):
def __init__(self, builder):
self.builder = builder
def construct(self):
self.builder.makeTitle("Greeting")
self.builder.makeString("朝から昼にかけて")
self.builder.makeItems(["おはようございます。", "こんにちは。"])
self.builder.makeString("夜に")
self.builder.makeItems(["こんばんは。", "おやすみなさい。", "さようなら。"])
self.builder.closing()ここでBuilderクラスで宣言したメソッドを使って文書をつくる。コンストラクタに渡されることになるのは
Builderクラスのサブクラスのインスタンス。渡されるインスタンスによってどんな文書になるか変わる。
次はTextBuilderクラス
class TextBuilder(Builder):
_buffer = []
def makeTitle(self, title):
self._buffer.append("===================================\n")
self._buffer.append("[%s]" %title)
self._buffer.append("\n")
def makeString(self, st):
self._buffer.append("*%s\n" %st)
self._buffer.append("\n")
def makeItems(self, items):
for i in items:
self._buffer.append(" +%s\n" %i)
self._buffer.append("\n")
def closing(self):
self._buffer.append("===================================\n")
def getResult(self):
return "\n".join(self._buffer)ここはBuilderクラスのサブクラスでプレーンテキストで文書をつくる。リストに文書の各部を順に入れていき、joinメソッドで
つなげた結果が文字列で返ってくる。
次はHTMLBuilderクラス
class HTMLBuilder(Builder):
_buffer = []
def makeTitle(self, title):
self.title = title
self.filename = "%s.html" %title
self._buffer.append("<html><head><title>%s</title></head><body>\n" %title)
self._buffer.append("<h1>%s</h1>\n" %title)
def makeString(self, st):
self.st = st
self._buffer.append("<p>%s</p>\n" %st)
def makeItems(self, items):
self.items = items
self._buffer.append("<ul>\n")
for i in items:
self._buffer.append("<li>%s</li>\n" %i)
self._buffer.append("</ul>\n")
def closing(self):
self._buffer.append("</body></html>\n")
def getResult(self):
self.writer = open(self.filename, "w")
self.writer.write("\n".join(self._buffer))
self.writer.close()
return self.filenameここもBuilderクラスのサブクラスでHTMLファイルとして文書をつくる。ここでもリストに文書の各部を入れていってつなげたものを
ファイルに書き込む。結果はファイル名として返ってくる。
最後に動作テスト用の部分
if __name__=="__main__":
import sys
if len(sys.argv) == 1 or len(sys.argv) >= 3:
print "python builder.py plain => plain text"
print "python builder.py html => HTML text"
elif sys.argv[1] == "plain":
textbuilder = TextBuilder()
director = Director(textbuilder)
director.construct()
result = textbuilder.getResult()
print result
elif sys.argv[1] == "html":
htmlbuilder = HTMLBuilder()
director = Director(htmlbuilder)
director.construct()
filename = htmlbuilder.getResult()
print "%sが作成されました。" %filename
else:
print "python builder.py plain => plain text"
print "python builder.py html => HTML text"コマンドラインで指定した形式によってつくられる文書が変わる。
plainを指定するとTextBuilderクラスのインスタンスがDirectorクラスのコンストラクタに渡るし、htmlを指定すれば
HTMLBuilderクラスのインスタンスがDirectorクラスのコンストラクタに渡る。
実行結果は以下。
C:\works\python\book1>python builder.py plain =================================== [Greeting] *朝から昼にかけて +おはようございます。 +こんにちは。 *夜に +こんばんは。 +おやすみなさい。 +さようなら。 ===================================
C:\works\python\book1>python builder.py html Greeting.htmlが作成されました。
Prototypeパターン
結城浩さんの「Java言語で学ぶデザインパターン入門」を題材にpythonでデザインパターンを書いてみる。
今回の題材はPrototypeパターン。クラスからインスタンスをつくるのではなく、インスタンスをコピーすることで、
インスタンスから別のインスタンスをつくるというもの。
pythonでは copyモジュールの deepcopy関数を使うことでインスタンスのコピーをすることができるようなので、
まずは copyモジュールについて学習。copyモジュールは浅いコピーと深いコピー操作を提供してくれるらしい。
浅い (shallow) コピーと深い (deep) コピーの違いが関係してくるのは、複合オブジェクト (リストやクラスインスタンスの
ような他のオブジェクトを含むオブジェクト) だけということらしい。
浅いコピー (shallow copy) は新たな複合オブジェクトを作成し、その後 (可能な限り) 元のオブジェクト中に見つかったオブジェクトに対する 参照 を挿入するらしい。
深いコピー (deep copy) は新たな複合オブジェクトを作成し、その後元のオブジェクト中に見つかったオブジェクトの コピー を挿入するらしい。
とりあえず実験。まずは単純にコピー。
>>> import copy >>> ori = "Hello!" >>> c1 = copy.copy(ori) >>> c2 = copy.deepcopy(ori) >>> c1 'Hello!' >>> c2 'Hello!'
次にリストのコピー。
>>> lis = [1,2,3] >>> lis1 = copy.copy(lis) >>> lis2 = copy.deepcopy(lis) >>> lis [1, 2, 3] >>> lis1 [1, 2, 3] >>> lis2 [1, 2, 3] >>> lis[0] = "Hello!" >>> lis ['Hello!', 2, 3] >>> lis1 [1, 2, 3] >>> lis2 [1, 2, 3]
次はリストのリストのコピー。
>>> lis3 = [[1,2,3]] >>> lis4 = copy.copy(lis3) >>> lis5 = copy.deepcopy(lis3) >>> lis3 [[1, 2, 3]] >>> lis4 [[1, 2, 3]] >>> lis5 [[1, 2, 3]] >>> lis3[0][0] = "Hello!" >>> lis3 [['Hello!', 2, 3]] >>> lis4 [['Hello!', 2, 3]] >>> lis5 [[1, 2, 3]]
lis3に対する参照を行った後では浅いコピー(lis4)と深いコピー(lis5)の内容に違いが出た。
これが浅いコピーでは元のオブジェクト中に見つかったオブジェクトに対する 参照 を挿入して、
深いコピーでは元のオブジェクト中に見つかったオブジェクトの コピー を挿入するってことなのか。
要は深いコピーではオブジェクトの内部を辿って複製してくれるというわけか。
浅いコピーで複製されたオブジェクトは、可能な限り参照として渡されちゃうのでリストや辞書などの場合
その要素に参照があればそれは参照として渡されるってことでいいのかな。なのでクラスインスタンスのコピーでも
インスタンスの実体を複製するには深いコピーを行わなきゃならないってことかな。
ではデザインパターンの実装へ。サンプルプログラムは、文字列を枠線で囲って表示したり、下線を付けて表示したり
するもの(prototype.py)。
はじめにProductクラス。
import copy
class Product(object):
def use(self, s):
pass
def createClone(self):
passここは元々インターフェースなのでメソッドの宣言のみ。
次にManageクラス。
class Manager(object):
__showcase = dict()
def register(self, name, proto):
self.__showcase[name] = proto
def create(self, protoname):
p = self.__showcase.get(protoname)
return p.createClone()ここではregisterメソッドで製品の名前とProductクラスのインスタンスの一組を辞書に登録。
createメソッドはcreateCloneメソッドを使ってインスタンスを複製する。
次にMessageBoxクラス。
class MessageBox(Product):
def __init__(self, decochar):
self.decochar = decochar
def use(self, s):
length = len(s)
deco = self.decochar * (length + 4 )
print deco
print self.decochar,s,self.decochar
print deco
def createClone(self):
p = copy.deepcopy(self)
return pここはProductクラスの実装を行っている。useメソッドは与えられた文字列をdecocharで囲むというもの。
createCloneメソッドはdeepcopy関数を使って自分自身のインスタンスを複製する。
次にUnderlinePenクラス。
class UnderlinePen(Product):
def __init__(self, ulchar):
self.ulchar = ulchar
def use(self, s):
length = len(s)
print '"%s"' %s
print " %s " %(self.ulchar * length)
def createClone(self):
p = copy.deepcopy(self)
return pここもProductクラスの実装。ulcharで与えられる下線を付ける。
最後に動作テスト用のクラス。
if __name__== "__main__":
manager = Manager()
upen = UnderlinePen("~")
mbox = MessageBox("*")
sbox = MessageBox("/")
manager.register("strong message", upen)
manager.register("warning box", mbox)
manager.register("slash box", sbox)
p1 = manager.create("strong message")
p1.use("Hello, world.")
p2 = manager.create("warning box")
p2.use("Hello, world.")
p3 = manager.create("slash box")
p3.use("Hello, world.")最初にManagerクラスのインスタンスを作る。そのインスタンスに対してUnderlinePenクラスのインスタンスと
MessageBoxクラスのインスタンスを登録しておく。
実行結果は、
C:\works\python\book1>python prototype.py "Hello, world." ~~~~~~~~~~~~~ ***************** * Hello, world. * ***************** ///////////////// / Hello, world. / /////////////////
Singletonパターン
結城浩さんの「Java言語で学ぶデザインパターン入門」を題材にpythonでデザインパターンを書いてみる。今回の題材はSingletonパターン。指定したクラスのインスタンスが絶対に1つしか存在しないことを保証するデザインパターン。
pythonでこのデザインパターンを実装する方法として特殊メソッド__new__()をオーバーライドする方法があるようなので、まずは
クラスを定義するときに使う __new__(cls[,args....]) という特殊メソッドについて勉強。
pythonでのクラス定義では、普通は__init__メソッドで初期化を行うけど生成過程を制御したいときには__new__メソッドを
使うらしい。
とりあえずPython日本語マニュアルなどで調べてみた。
__new__メソッドも__init__メソッドと同じように引数を設定してクラスオブジェクトの関数の呼び出しの形で使うみたい。
ただ__init__メソッドが戻り値を設定しないのに対して__new__メソッドは戻り値を設定できるらしい。つまり自分自身である
インスタンスオブジェクト以外のものを返すことができるということ。
また__new__メソッドはクラスメソッドなので第一引数はインスタンスではなくクラスとなるらしい。
クラス cls の新しいインスタンスを作るために呼び出されて、残りの引数はオブジェクトのコンストラクタの式 (クラスの呼び出し文) に渡されるらしい。それで __new__() の戻り値は新しいオブジェクトのインスタンス (通常は cls のインスタンス) でなければならないらしい。
__new__() が cls のインスタンスを返した場合、 "__init__(self[, ...])" のようにしてインスタンスの __init__() が呼び出されると。このとき、self は新たに生成されたインスタンスで、残りの引数は __new__() に渡された引数と同じになるらしい。
今、新しいスタイルのクラス Cls があって、クラス Cls の新しいインスタンスをつくるために Cls(*args, *kwargs) とすると、
Pythonでは Cls.__new__(Cls, *args, **kwargs) が呼ばれるらしい。
__new__メソッドは戻り値 x を指定できるが、その戻り値が新しくつくられたインスタンスとして使われるらしい。
つづいてPythonは Cls.__init__(x, *args, **kwargs)を呼ぶけど、これは x が実際に Cls のインスタンスである場合に限られるらしい。それ以外の場合は x の状態は__new__が残した状態のままとなるらしい。
object.__new__とすると、第一引数として受け取るクラスから新しいインスタンスを初期化されていない状態でつくるらしい。
ここまでをふまえて、実装コードを見てみると、
class Singleton(object):
_instances = dict()
def __new__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = object.__new__(cls, *args, **kwargs)
return cls._instances[cls]
class DerivedSingleton(Singleton):
pass
if __name__ == '__main__':
print id(Singleton())
print id(Singleton())
print id(DerivedSingleton())
print id(DerivedSingleton())う〜ん。よくわからない。
実行結果は、
12483248 12483248 12483280 12483280
ふむ。確かにインスタンスの識別値が同じになってる。
ただ、いまいち__new__メソッドが完全に理解できてないのでまた勉強しなければ。
受信メールのタイトルを取得する
poplibモジュールの勉強の続き。
まずは下調べをするためにとりあえずメールサーバにログインしておく。
後で使うので emailモジュールもインポートしておく。
>>> import poplib, email >>> server = "mail.xxxx.co.jp" >>> user_id = "xxxx" >>> user_pass = "xxxx" >>> p = poplib.POP3(server) >>> p.user(user_id) '+OK Password required for xxxx.' >>> p.pass_(user_pass) '+OK xxxx has 1 visible message (0 hidden) in 1744 octets.'
ここでメールの一覧を取得できる、POP3クラスのインスタンスの持つlist()メソッド
を使ってみる。表示させてみると、
>>> mail_list = p.list()
>>> mail_list
('+OK 1 visible messages (1744 octets)', ['1 1744'], 8)タプルが返ってきて、1番目の要素にメッセージ番号とメッセージボックスサイズから成る
リストがあるのでこれでメッセージ番号を取得できる。
1番目のメッセージの内容は p.retr(1)[1] で1行ごとに分割されて含まれたリストとして
取得できるということだった。
これを1つの文字列にして、emailモジュールの message_from_string()メソッドに渡して
やれば文字列からメッセージオブジェクト構造を作成し返してくれるみたい。
あとはメッセージオブジェクト構造からヘッダー部分を取得して適切なデコード処理等を
行えばメールタイトルを取得できるみたい。以上をふまえて
http://d.hatena.ne.jp/white-azalea/20080511/1210480754のページのサンプルコード
を使わせていただいて書いたのが以下のスクリプト(take_mail.py)。
# -*- coding: utf-8 -*-
import poplib, email
server = "mail.xxxx.co.jp"
user_id = "xxxx"
user_pass = "xxxx"
p = poplib.POP3(server)
p.user(user_id)
p.pass_(user_pass)
mail_list = p.list()
for mail_id in mail_list[1]:
(no, msg_size) = mail_id.split(" ")
mail_data = p.retr(no)
msg = email.message_from_string("\n".join(mail_data[1]))
subject = email.Header.decode_header(msg["Subject"])
try:
print unicode(subject)
except:
pass実行結果は、
C:\works\python\book1>python take_mail.py
[('test', None)]