Emacs24を入れてみました。
なぜかふとEmacsを24にしてみようと思い立ったので入れてみました。
OS X用だとSourceForgeで.dmgが配布されているのでそこからダウンロードしてきました。
普通に古いのと置き換えました。
起動するとinit.el内でエラーがいくつか出ていたのでとりあえず困らなそうなやつは全部コメントアウトしました。
で、問題が一つ。
どうもflyspellがデフォルトで機能しているらしく
Error enabling Flyspell mode: (Searching for program No such file or directory ispell)
というメッセージが。
ispellはインストールしてないのでインストールします。
portsとかbrewとかで入れられるらしいんですが面倒くさいのでソースから入れました。(僕のMacにはportを入れてない。)
$ tar -xvzf ispell-3.3.02.tar.gz $ cd ispell-3.3.02 $ cp local.h.macos local.h $ make all
そしたらエラーが出た。
correct.c:248: error: conflicting types for ‘getline’ /usr/include/stdio.h:449: error: previous declaration of ‘getline’ was here make: *** [correct.o] Error 1
コンフリクトしてるらしい。
とりあえず適当に置換します。
$ chmod 644 correct.c $ vim correct.c :%s/getline/_getline/g 保存して閉じる $ make all 今度は通ったはずなので $ sudo make install
無事インストール出来ました。
再びEmacs起動してみます。
やっぱりispellが無いとか言われる・・・。
まぁインストールは出来てるわけだからパスの問題だろうと言うことで
$ which ispell /usr/local/bin/ispell
init.elに追記
(setq ispell-program-name "/usr/local/bin/ispell")
もっかい起動して適当なファイルを開いてみます。
バッファには
Starting new Ispell process [default] ...
と出ているので大丈夫そうです。
例えばですがPHPで
$a = 'enviroment';
とか書いちゃうとアンダーライン付いてスペルミスしていることを教えてくれます。
canvasはFlashの置き換えになるのか
HTML5になっても今の状況を見る限りブラウザ依存という問題は消えないわけでして、せめてcanvasに限定するならどうだろうかと思ったわけです。
今までブラウザゲームと言えば大半がFlashで作ってましたけどFlashだと依存問題があんまり無いので開発者はそれほど苦労してなかったと思います。
少なくとも僕はそうでした。つまりゲームの開発だけに注力出来ていたわけです。
そこでcanvasに絞ってみたらどうかと考えたわけです。
と言うか既にcanvasだけでやってるようなライブラリも出てます。
なのでこの話題についてもかなり今更であるわけなんですが。
canvas限定ならベンダープレフィックス付けて処理を切り分けて〜みたいなことしないで済みます。
それで試したいのもあってzz.jsのブランチを作りました。
一つはrequestAnimationFrameの導入用です。
未実装ブラウザではsetTimeoutで動くようになってます。(のハズ。)
今まではsetTimeoutだけでやってました。
もう一つはそこから派生させたfullcanvasブランチです。
こちらは、一つのcanvas上に全て描画させるって試みです。
元々HTML+JavaScript(一部にHTML5の機能)でやっててあんまりHTML5じゃなかったんですけど、canvasの仕様が決まってきたのもあって変更してみることにしました。
画像の表示だけcanvas使ってたんですけど理由としては画像のトリミング機能入れたかったのと画像の明度と色変換したかったからです。
でもクロスドメインだとセキュリティの都合で動かないんですよね・・・
負荷対策にリソースを別サーバーに置いてる場合は注意です。
一応基本的には元のコードでそのまま動くように変更する予定ですがdivコンテナをいじってたりstyleに何か加えている場合は動かなくなります。
そもそもelementを無くしてるのでstyleは使えません。
変更にあたって表示は特に問題なさそうなんですがタッチの判定がめんどくさそうなのでどうしようか悩み中です。
あとはパフォーマンス出るかどうかですね。
python3.3から入った__qualname__を使ってみる(前回の続き)
今回も前回のネタを引っ張ります。
前回のvalidate_methodデコレータの問題点として継承して定義したクラスに使用すると継承元のメソッドまでチェックしてしまいうまく動きません。
標準モジュールのクラスやサードパーティ製モジュールのクラスを継承することは良くあるはずなので問題があります。
という訳でうまいこと回避したいんですけど参照しているメソッドがどのクラスで定義されてるかを取得する方法がわかりません。
良い方法が見つからなかったんですけどpython3.3から入った__qualname__という変数を使えばなんとかなりそうです。
(PEP3155を見る限りでは使い方としてはそんなに間違ってない気がします。)
http://docs.python.org/3.3/glossary.html#term-qualified-name
split(".")して取得したクラス名と判定したいメソッドのクラス名を比較すれば自分のクラスで定義したメソッドかどうか判定できるはずです。
for name, func in getmembers(cls, isfunction): clsname = func.__qualname__.split(".")[-2] if cls.__name__ != clsname: continue
こんな感じですっ飛ばしました。
しかし、う〜ん、もっとスマートな方法がありそうな気がするんですけど・・・
良い方法知ってる方いたら教えて下さい。m(._.)m
python3の例外のfromキーワード(前回の続き)
前回の反省を踏まえて書き直しました。
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 関数の引数型を検証します。 """ from functools import wraps from inspect import getfullargspec, getmembers, isfunction class ArgumentError(Exception): def __init__(self, arg_name, val, typ): err = '引数 {} の {} は {} と型が違います。'.format(arg_name, val, typ) super().__init__(err) class RetValError(Exception): def __init__(self, retval, typ): err = '戻り値 {} は型が {} ではありません。'.format(retval, typ) super().__init__(err) class UndefinedArgTypeError(KeyError): def __init__(self): err = '引数の型が未定義です。' super().__init__(err) class UndefinedRetvalTypeError(KeyError): def __init__(self): err = '戻り値の型が未定義です。' super().__init__(err) def validate(func): """ >>> @validate ... def test(a: int, b: str) -> str: ... val = str(a) + b ... return val ... >>> test(1, "3") '13' """ anno = func.__annotations__ def check_type(key, value): try: obj_type = anno[key] except KeyError as err: if key == "return": raise UndefinedRetvalTypeError from err else: raise UndefinedArgTypeError from err def raise_error(): if key == "return": raise RetValError(value, obj_type) else: raise ArgumentError(key, value, obj_type) if type(obj_type) in (list, tuple, set): if type(value) not in obj_type: raise_error() else: if obj_type is None: obj_type = type(obj_type) if type(value) is not obj_type: raise_error() @wraps(func) def _validate(*args, **kwargs): argSpec = getfullargspec(func) for name, value in zip(argSpec.args, args): if name == "self": continue check_type(name, value) result = func(*args, **kwargs) if func.__name__ != "__init__": check_type("return", result) return result return _validate def validate_method(cls): """ >>> @validate_method ... class Hoge: ... def fuga(self, a: int, b: float) -> float: ... return a + b >>> h = Hoge() >>> h.fuga(7, 0.777) 7.777 """ for name, func in getmembers(cls, isfunction): func.__name__ = name func.__doc__ = getattr(cls, name).__doc__ setattr(cls, name, validate(func)) return cls def test(): import doctest doctest.testmod() if __name__ == "__main__": test()
前回の問題点はクラスデコレータ使うとデコったクラスがオブジェクトになってしまうところでこれは何かと問題があります。デコったクラスがクラスでは無くなってしまうので。
ということで普通に関数でデコレートしてクラスはそのまま返すことに。
デコレータの中でメソッドを上書きしてやることにしました。
表題の件はpython3から例外キャッチしたときにfrom句が使えるみたいで、実際例外を出してみるとどうなるかわかります。
>>> from validation import validate >>> @validate ... def a(b): ... pass ... >>> a(1) Traceback (most recent call last): File "./validation.py", line 47, in check_type obj_type = anno[key] KeyError: 'b' The above exception was the direct cause of the following exception: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "./validation.py", line 75, in _validate check_type(name, value) File "./validation.py", line 52, in check_type raise UndefinedArgTypeError from err validation.UndefinedArgTypeError: '引数の型が未定義です。'
超適当ですがこんな感じです。
The above exception was the direct cause of the following exception:
って出てますね。自作の例外クラス作った時なんかは追いやすくなりそうです。
ちなみにfrom使わないと
During handling of the above exception, another exception occurred:
って出ます。python2ではこのような表示は出ないのでpython3のが便利になっているのがわかります。
クラスデコレータ使ってバリデーションしてみた。(前回の続き)
前回のやり方だと関数一つ一つにデコレータいちいち付けてらんねぇよってなるので多少楽になるようにしてみます。
と言ってもクラスのメソッドのみです。
まず前回用意したtest.pyのvalidate関数に追記します。
argSpec = getfullargspec(func) + if "self" in argSpec.args: + argSpec.args.remove("self") for name, value in zip(argSpec.args, args):
おわかりのとおりメソッドの第一引数selfをスルー!
次にtest2.py
# -*- coding: utf-8 -*- from inspect import ismethod from test import validate class Deco: def __init__(self, cls): self.cls = cls self.instance = cls() def __call__(self): return self def __getattr__(self, name): attr = getattr(self.instance, name) if ismethod(attr): return validate(attr) return getattr(self.instance, name) @Deco class A: def output_num(self, num: int = 0) -> str: return "渡された数値は{}です".format(num)
クラスでデコレートしてみました。
で、実行してみます。
>>> from test2 import A >>> a = A() >>> a.output_num(3) OK '渡された数値は3です' >>> a.output_num("3") 引数 num の 3 は <class 'int'> と型が違います Traceback (most recent call last): File "<stdin>", line 1, in <module> File "test.py", line 28, in _validate raise ArgumentError(name, value, obj_type) test.ArgumentError
それっぽくなりました。
クラスデコレータ使うとデコったクラスのインスタンスを返しちゃうのでisinstance関数とかわかりにくくなるのが難点です。
何が言いたいかっていうと
>>> a.__class__ <class 'test2.Deco'> >>> a.instance <test2.A object at 0x10061e810> >>> a.instance.__class__ <class 'test2.A'> >>> A <test2.Deco object at 0x10061e990> >>> isinstance(a, A) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: isinstance() arg 2 must be a type or tuple of types >>> isinstance(a, a.instance.__class__) False >>> a <test2.Deco object at 0x10061e990>
継承とかしてるわけじゃないし別のインスタンスなんだから当たり前なんですけど何か良い方法無いですかね。こういうのってあまり意識しないで使いたいですから。
@Decoを付けるだけでチェックしてくれるようになるけど上の問題で違うインスタンスになっちゃってるもんだからまともに動かないよぉ。