2009-10-18
■[Python][C++]デフォルト引数で失敗した
2009-10-19 追記
コメントで指摘してもらっているようにデフォルト引数ではなくて、キーワード引数の問題だった。
よく分からないものを無理して使った上に、ブログに間違いを載せるとか、恥の上塗りでしかなかった。
最近は特に勉強もせず、ネトゲやったりしてダラダラ過ごしてしまっている。
そんな中、ちょっとしたミスからなかなかバグがとれなかったので、ここに晒して戒めとしよう。
それは似たようなコードをC++とPythonで使い回していて、次のような関数のデフォルト引数を使ったコードで発生した。
# Python def func(a = 10): print(a) def main(): a = 20 func(a = 30) print(a) if '__main__' == __name__: main()
// C++ #include <iostream> using namespace std; void func(int a = 10) { cout << a << endl; } int main() { int a = 20; func(a = 30); cout << a << endl; return 0; }
出力は以下の通り。
Python
30
20
C++
30
30
このコードなら大した話ではないので間違いにはすぐ気がつくが、他のロジックに混ざっていると突然変数の中身が変化したような錯覚に。
根本的には、変数名の付け方が悪かったことに起因するんだろうなぁ。
2009-07-16
■[Python]ctypesで関数ポインタを扱う
ctypesを使うとDLLが呼び出せることを前に書いた。
こんな感じで。
from ctypes import * user32 = windll.user32 user32.MessageBoxW(0, u'Python ctypes test', 0, 0)
ctypesの便利さはこんなものじゃない。
Pythonの関数を関数ポインタのように扱って、callback関数にしたり、CreateThreadしたりできる。
from ctypes import * user32 = windll.user32 kernel32 = windll.kernel32 def callbackFunction(): user32.MessageBoxW(0, u'MessageBox from callback function', 0, 0) return 0 functionType = CFUNCTYPE(c_int) functionPointer = functionType(callbackFunction) threadId = c_ulong(0) threadHandle = kernel32.CreateThread(0, 0, functionPointer, 0, 0, byref(threadId)) result = kernel32.WaitForSingleObject(threadHandle, 60*1000) if result: print('Timeout') else: print('Thread exited')
ctypesのおかげでWin32 API使ったコードでも、こんなに簡単にPythonだけで書くことが出来るようになっている。
2009-07-14
■[Python]ctypesの三つのロード方法
ctypesではDLLのロード方法が三つある。
cdll、windll、oledllの三つだが、その違いはcallされた時のスタックの扱いと、戻り値だ。
ややっこしいのでまとめてみる。
cdllで呼び出すべき関数
- cdecl呼び出し規約に従う
- intを返す
windllで呼び出すべき関数
- stdcall呼び出し規約に従う
- intを返す
oledllで呼び出すべき関数
- stdcall呼び出し規約に従う
- HRESULTを返す
cdeclとstdcallの違いは、Wikipediaが詳しい。
要は、引数をスタックにpushして関数を呼び出すのは同じだが、そのスタックを元に戻す責任があるのが、呼び出された関数側なのか、呼び出した側なのかの違い。
2009-07-13
■[Python]ctypesを使ってみる
ctypesを使うとPythonからDLLや、Shared libraryを呼び出すことが出来る。
ctypes_test.py
from ctypes import * msvcrt = cdll.msvcrt message = "Python ctypes test\n" msvcrt.printf(message)
以下は型の対応表。
| ctypes type | C type | Python type |
|---|---|---|
| c_char | char | 1-character string |
| c_wchar | wchar_t | 1-character unicode string |
| c_byte | char | int/long |
| c_ubyte | unsigned char | int/long |
| c_short | short | int/long |
| c_ushort | unsigned short | int/long |
| c_int | int | int/long |
| c_uint | unsigned int | int/long |
| c_long | long | int/long |
| c_ulong | unsigned long | int/long |
| c_longlong | __int64 or long long | int/long |
| c_ulonglong | unsigned __int64 or unsigned long long | int/long |
| c_float | float | float |
| c_double | double | float |
| c_longdouble | long double | float |
| c_char_p | char * (NUL terminated) | string or None |
| c_wchar_p | wchar_t * (NUL terminated) | unicode or None |
| c_void_p | void * | int/long or None |