Pythonの無名関数で再帰
やたーPythonの無名関数で再帰出来たよー(^o^)ノ
import sys, new for i in xrange(10): print i, (lambda n: n if n <= 1 else new.function(sys._getframe().f_code, globals(), None, None, None)(n - 1) + new.function(sys._getframe().f_code, globals(), None, None, None)(n - 2))(i)
実行結果:
0 0 1 1 2 1 3 2 4 3 5 5 6 8 7 13 8 21 9 34
ちゃんと動いてますね。
sys._getframe().f_codeに引数を渡してevalする方法が見つからなかったのでfunctionオブジェクトを作って呼んでいます。
もっと良い方法があれば教えてくださいヽ(´ー`)丿
プロセスを一時停止/再開するプログラム
プロセスを一時停止/再開するプログラムをPythonで書いた。標準ライブラリのみで行いたかったのでpywin32などサードパーティー製のライブラリは使用していない。
プロセスを一時停止/再開させる(ドキュメント化された)Windows APIは残念ながら存在しないので、SuspendThreadとResumeThreadにより一時停止/再開させたいプロセスが所有する全てのスレッドを一時停止/再開させるという手法を採っている。また、SuspendThreadとResumeThreadのサスペンドカウントを増減させ、0になったら再開するという仕様により、例えばこのプログラムを使用して3回プロセスを一時停止させたならば、再開するためには3回プロセスを再開させねばならない。
使い方
psusres.py
で、何もオプションを指定しなければプロセスIDとプロセスの名前の一覧を表示し、
psusres -s PID
で、PIDで指定されたプロセスの一時停止、
psusres -r PID
で指定されたプロセスの再開をする。
ソースコード
ソースコードを以下に示す。ここで使用しているWindows APIのラッパーは少し長いのでgithubに置いた。
#!/usr/bin/env python # coding: utf-8 # psusres: a tool to suspend/resume a process from __future__ import print_function from optparse import OptionParser from winapi import * def PauseResumeThreadList(dwOwnerPID, bSuspendThread): hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwOwnerPID) if hThreadSnap == INVALID_HANDLE_VALUE: return te32 = Thread32First(hThreadSnap) if te32: while True: if te32.th32OwnerProcessID == dwOwnerPID: hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID) if bSuspendThread: print("Suspending Thread 0x{0:04X}".format(te32.th32ThreadID)) SuspendThread(hThread) else: print("Resuming Thread 0x{0:04X}".format(te32.th32ThreadID)) ResumeThread(hThread) CloseHandle(hThread) te32 = Thread32Next(hThreadSnap) if not te32: break CloseHandle(hThreadSnap) def ProcessList(): hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) pe32 = Process32First(hProcessSnap) if (pe32): while True: print('PID\t', pe32.th32ProcessID, '\t', pe32.szExeFile, sep='') pe32 = Process32Next(hProcessSnap) if not pe32: break CloseHandle(hProcessSnap) def main(): usage = 'usage: %prog [options] PID' parser = OptionParser(usage) parser.add_option('-s', '--suspend', action='store_true', dest='suspend', help='suspend a specified process') parser.add_option('-r', '--resume', action='store_false', dest='suspend', help='resume a specified process') options, args = parser.parse_args() if options.suspend is None: parser.print_help() print() ProcessList() elif len(args) == 0: parser.print_help() else: try: pid = int(args[0]) except: print("Invalid PID number:", args[0]) else: PauseResumeThreadList(pid, options.suspend) return if __name__ == '__main__': main()
Delphi互換の擬似乱数生成コード
ちょっと必要になったのでDelphi互換の擬似乱数を生成するプログラムを書いた。
Linear congruential generator - Wikipediaを参考にした。
class DelphiRandom: def __init__(self, seed=0): self.seed = seed def __call__(self, max): self.seed = (self.seed * 134775813 + 1) & 0xFFFFFFFF result = (self.seed * max) & 0xFFFFFFFFFFFFFFFF return result >> 32
再帰下降構文解析による数式の評価
再帰下降構文解析を用いて数式を評価するプログラムを書いた。四則演算と括弧の使用ができる。演算子の優先順位は通常通り。以下にソースコードを示す。
ExpressionEvaluaterはクラスではなく関数にしても良いかもしれない。
#!/usr/bin/env python # coding: utf-8 # expression evaluater import re class Queue(list): def get(self): if len(self) == 0: raise IndexError('get from empty list') else: temp = self[0] self[:1] = [] return temp def put(self, value): list.append(self, value) class ExpressionLexer(): def __init__(self, expr): self.cur = None self.queue = Queue() callback = lambda scanner, token: self.queue.put(token) scanner = re.Scanner([ (r'\+|\-|\*|\/', callback), (r'[0-9]+(\.[0-9]+)?', callback), (r'\(|\)', callback), (r'\s+', None), ]) scanner.scan(expr) def next(self): try: self.cur = self.queue.get() except IndexError: self.cur = None class ExpressionEvaluater(): def eval(self, expr): self.lexer = ExpressionLexer(expr) self.lexer.next() return self.expression() def number(self): sign = '+' if self.lexer.cur == '-': sign = self.lexer.cur self.lexer.next() num = float(self.lexer.cur) self.lexer.next() if sign == '-': return -num else: return num def factor(self): if self.lexer.cur != '(': return self.number() self.lexer.next() x = self.expression() if self.lexer.cur != ')': raise Exception() self.lexer.next() return x def term(self): x = self.factor() while True: if self.lexer.cur == '*': self.lexer.next() x *= self.factor() elif self.lexer.cur == '/': self.lexer.next() y = self.factor() if y == 0: raise Exception() x /= y else: break return x def expression(self): x = self.term() while True: if self.lexer.cur == '+': self.lexer.next() x += self.term() elif self.lexer.cur == '-': self.lexer.next() x -= self.term() else: break return x def eval_expr(expr): return ExpressionEvaluater().eval(expr) def main(): import sys def puts(*text): text = ' '.join(map(str, text)) sys.stdout.write(text) sys.stdout.write('\n') sys.stdout.flush() def readline(): sys.stdout.write('>>> ') sys.stdout.flush() return sys.stdin.readline() for line in iter(readline, ''): t = line.rstrip() if t != '': try: puts(eval_expr(t)) except: puts('An error has occured.') if __name__ == '__main__': main()
PythonでGUIDを生成する
PythonでGUIDを生成する方法。
標準ライブラリのuuidモジュールを使えば良い。
>>> import uuid >>> str(uuid.uuid4()) '4155f6f5-fa9e-4669-87a1-7ee43a4a70c5'
Google App Engineでエラーが
久しぶりにGoogle App Engineでdev_appserver.pyを起動すると以下のようなエラーが出た。
INFO 2009-10-21 00:00:00,375 py_zipimport.py:108] zipimporter('C:\\Python25\\lib\\site-packages\\simplejson-2.0.9-py2.5-win32.egg', 'simplejson\\') Traceback (most recent call last): File "C:\Program Files\Google\google_appengine\dev_appserver.py", line 60, in <module> run_file(__file__, globals()) File "C:\Program Files\Google\google_appengine\dev_appserver.py", line 57, in run_file execfile(script_path, globals_) File "C:\Program Files\Google\google_appengine\google\appengine\tools\dev_appserver_main.py", line 496, in <module> sys.exit(main(sys.argv)) File "C:\Program Files\Google\google_appengine\google\appengine\tools\dev_appserver_main.py", line 413, in main SetGlobals() File "C:\Program Files\Google\google_appengine\google\appengine\tools\dev_appserver_main.py", line 89, in SetGlobals from google.appengine.tools import appcfg File "C:\Program Files\Google\google_appengine\google\appengine\tools\appcfg.py", line 59, in <module> from google.appengine.tools import bulkloader File "C:\Program Files\Google\google_appengine\google\appengine\tools\bulkloader.py", line 111, in <module> from google.appengine.ext import key_range as key_range_module File "C:\Program Files\Google\google_appengine\google\appengine\ext\key_range\__init__.py", line 24, in <module> import simplejson File "C:\Python25\lib\site-packages\PIL\__init__.py", line 108, in <module> File "C:\Program Files\Google\google_appengine\google\appengine\dist\py_zipimport.py", line 213, in load_module exec code in mod.__dict__ File "C:\Python25\lib\site-packages\simplejson-2.0.9-py2.5-win32.egg\simplejson\decoder.py", line 7, in <module> File "C:\Program Files\Google\google_appengine\google\appengine\dist\py_zipimport.py", line 213, in load_module exec code in mod.__dict__ File "C:\Python25\lib\site-packages\simplejson-2.0.9-py2.5-win32.egg\simplejson\scanner.py", line 5, in <module> File "C:\Program Files\Google\google_appengine\google\appengine\dist\py_zipimport.py", line 213, in load_module exec code in mod.__dict__ File "C:\Python25\lib\site-packages\simplejson-2.0.9-py2.5-win32.egg\simplejson\_speedups.py", line 7, in <module> File "C:\Python25\lib\site-packages\simplejson-2.0.9-py2.5-win32.egg\simplejson\_speedups.py", line 4, in __bootstrap__ File "C:\Python25\lib\site-packages\setuptools-0.6c9-py2.5.egg\pkg_resources.py", line 841, in resource_filename File "C:\Python25\lib\site-packages\setuptools-0.6c9-py2.5.egg\pkg_resources.py", line 1311, in get_resource_filename File "C:\Python25\lib\site-packages\setuptools-0.6c9-py2.5.egg\pkg_resources.py", line 1322, in _extract_resource File "C:\Program Files\Google\google_appengine\google\appengine\dist\py_zipimport.py", line 268, in __getitem__ info = _zipfile_cache[self._archive].getinfo(filename) File "C:\python25\lib\zipfile.py", line 462, in getinfo return self.NameToInfo[name] KeyError: 'simplejson\\_speedups.pyd'
エラーメッセージで検索すると*1、google_appengine/google/appengine/ext/key_range/__init__.pyのimport simplejsonをfrom django.utils import simplejsonに変更すれば良い事が分かり、解決した。