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()

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に変更すれば良い事が分かり、解決した。