主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

スポンサーサイト

                
tags:
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Python: クラスメソッドの使いどころ

                
tags: python
 通常、メソッドはインスタンスから使うものだ。
class Foo:
def method(self):
print("method done")

Foo().method()


 クラスのメソッドには実体がないので、クラスから呼び出せない。
Foo.method()

 Pythonにはクラスメソッドが用意されている。これはインスタンスでなくクラスから使うことができる。
class Foo:
@classmethod
def method(cls):
print("method done")

Foo.method()


 ドキュメントを流し読みしていたことがあったのでクラスメソッドのことは知っていたのだけど、実際のところどう使うのが有効なんだろかと考えたりしていた。そしたらTornadoのデモの中に使用を見つけることができた。
https://github.com/tornadoweb/tornado/blob/master/demos/websocket/chatdemo.py
class ChatSocketHandler(tornado.websocket.WebSocketHandler):
waiters = set()
cache = []
cache_size = 200

def open(self):
ChatSocketHandler.waiters.add(self)

def on_close(self):
ChatSocketHandler.waiters.remove(self)

@classmethod
def update_cache(cls, chat):
cls.cache.append(chat)
if len(cls.cache) > cls.cache_size:
cls.cache = cls.cache[-cls.cache_size:]

@classmethod
def send_updates(cls, chat):
logging.info("sending message to %d waiters", len(cls.waiters))
for waiter in cls.waiters:
try:
waiter.write_message(chat)
except:
logging.error("Error sending message", exc_info=True)

def on_message(self, message):
logging.info("got message %r", message)
parsed = tornado.escape.json_decode(message)
chat = {
"id": str(uuid.uuid4()),
"body": parsed["body"],
}
chat["html"] = tornado.escape.to_basestring(
self.render_string("message.html", message=chat))

ChatSocketHandler.update_cache(chat)
ChatSocketHandler.send_updates(chat)

 インスタンスを元となったクラスの変数に格納したり、格納されたインスタンスすべてにメソッドを実行させるといったように、そのクラスのインスタンスをまとめる役割としてクラス変数と共に使われていた。
 なるほど。これならインスタンスをまとめる変数をクラスの外に作る必要がないので、わかっていれば読みやすいし使いやすい。

 ちょっと書いてみる。ゲームキャラクターを表すクラスShapeを考える。とりあえず座標x、yと位置更新メソッドupdateをメンバーとして与える。まずはクラスメソッドなしで。
class Shape:
def __init__(self,x, y):
self.x = x
self.y = y

def update(self):
self.x += 1
self.y += 1

def main():
shapes = set()
for p in xrange(10):
shape = Shape(p, p)
shapes.add(shape)

q = 0
while q < 60:
for shape in shapes:
shape.update()
q += 1

if __name__ == "__main__":
main()

 クラスShapeのインスタンスを取りまわすために、変数shapeをmain関数内で使っている。あとそれをまとめるためのセットshapesとループを回すための変数。
 クラスメソッドを使ってちょっと改造してみる。
class Shape:
collection = set()
def __init__(self,x, y):
self.x = x
self.y = y

def update(self):
self.x += 1
self.y += 1

@classmethod
def add_new_shape(cls, (x, y)):
shape = Shape(x, y)
Shape.collection.add(shape)

@classmethod
def update_all(cls):
for shape in Shape.collection:
shape.update()

def main():
for p in xrange(10):
Shape.add_new_shape((p, p))

q = 0
while q < 60:
Shape.update_all()
q += 1

if __name__ == "__main__":
main()

 main関数内の変数がループを回すためのもの以外消せた。ちょっと強引にやり過ぎたとも思うけど。

 インスタンスを複数作るようなクラスを作ったとき、そのインスタンスの管理を元となったクラスに任せられれば、コードの一貫性が増す。そんなときに使いたいのがクラスメソッドとクラス変数の組み合わせ。
            

コメントの投稿

非公開コメント

プロフィール

hMatoba

Author:hMatoba
Github

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。