子プロセス起動時に管理者権限での実行を強制する
ShellExecuteExでlpVerb=runasにすれば良いらしい。
#include <windows.h> #include <shellapi.h> #include <cstdio> int main(int, const char**) { SHELLEXECUTEINFO sei = {}; sei.cbSize = sizeof(sei); sei.fMask |= SEE_MASK_WAITFORINPUTIDLE; sei.fMask |= SEE_MASK_FLAG_NO_UI; sei.fMask |= SEE_MASK_NO_CONSOLE; sei.fMask |= SEE_MASK_NOASYNC; sei.fMask |= SEE_MASK_NOCLOSEPROCESS; sei.lpVerb = "runas"; sei.lpFile = "notepad"; sei.nShow = SW_SHOWNORMAL; if(!ShellExecuteEx(&sei)) { return -1; } std::printf("hInstApp = 0x%08llx\n", uintptr_t(sei.hInstApp)); std::printf("hProcess = 0x%08llx\n", uintptr_t(sei.hProcess)); WaitForSingleObject(sei.hProcess, INFINITE); return 0; }
ShellExecuteExってCreateProcessに渡すSTARTUPINFOにあるような子プロセスの標準出力をリダイレクトで拾うにはどうしたらいいんだろうか?
WindowsのキーボードタイプにENが現れてしまったときの対処
言語設定で「英語(英国)」を一度追加して削除すると消える。
デコレータで関数に属性を付与
def note(**kw): def applier(func): __notes__ = getattr(func, '__notes__', None) if __notes__ is None: __notes__ = dict() setattr(func, '__notes__', __notes__) __notes__.update(kw) return func return applier @note(foo='this is add') @note(bar='加算') def add(a, b): return a + b print('add(10, 20) ->', add(10, 20)) print('add.__notes__ ->', add.__notes__)
$ python hoge.py add(10, 20) -> 30 add.__notes__ -> {'bar': '加算', 'foo': 'this is add'}
cdefクラスとcpdefの挙動
Cythonでネイティブ実装のPythonクラスを作る。(Cython 0.24 で確認)
# hoge.pyx from libc.stdio cimport printf from libcpp.string cimport string cdef class Hoge: cdef string name_ property name: def __get__(self): return self.name_.c_str().decode() def __init__(self): self.name_ = b'josh' def hello(self): self.chello() cdef inline void chello(self) nogil: printf('my name is `%s`\n', self.name_.c_str()) cpdef void greeting(self): self.chello() def hey(self): self.hello() self.greeting()
>>> import hoge >>> obj = hoge.Hoge() >>> obj.hello() my name is `josh` >>> obj.greeting() my name is `josh` >>> obj.name 'josh' >>> obj.hey() my name is `josh` my name is `josh`
上記実装だとcdefで定義されたchelloやname_はPythonからアクセス出来ない。
ネイティブPythonクラスを純粋Pythonクラスから継承出来るが、逆は出来ない。
↓def宣言されたhello()のC++コード。
2つ関数があり1つ目がPythonから呼ばれる関数で2つ目がネイティブ実装。
Pythonから呼びだされたらネイティブ版へ移譲している。
/* "hoge.pyx":16 * self.name_ = b'josh' * * def hello(self): # <<<<<<<<<<<<<< * self.chello() * */ /* Python wrapper */ static PyObject *__pyx_pw_4hoge_4Hoge_3hello(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ static PyObject *__pyx_pw_4hoge_4Hoge_3hello(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("hello (wrapper)", 0); __pyx_r = __pyx_pf_4hoge_4Hoge_2hello(((struct __pyx_obj_4hoge_Hoge *)__pyx_v_self)); /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_4hoge_4Hoge_2hello(struct __pyx_obj_4hoge_Hoge *__pyx_v_self) { PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("hello", 0); /* "hoge.pyx":17 * * def hello(self): * self.chello() # <<<<<<<<<<<<<< * * cdef inline void chello(self) nogil: */ __pyx_f_4hoge_4Hoge_chello(__pyx_v_self); /* "hoge.pyx":16 * self.name_ = b'josh' * * def hello(self): # <<<<<<<<<<<<<< * self.chello() * */ /* function exit code */ __pyx_r = Py_None; __Pyx_INCREF(Py_None); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; }
↓cpdef宣言されたgreeting()のC++コード。
3つ関数があり1つ目がネイティブ実装で2つ目がPythonから呼び出される関数、3つ目の関数は2つ目に統合出来るような。分けてる意味はあるのだろうか?
/* "hoge.pyx":22 * printf('my name is `%s`\n', self.name_.c_str()) * * cpdef void greeting(self): # <<<<<<<<<<<<<< * self.chello() * */ static PyObject *__pyx_pw_4hoge_4Hoge_5greeting(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ static void __pyx_f_4hoge_4Hoge_greeting(struct __pyx_obj_4hoge_Hoge *__pyx_v_self, int __pyx_skip_dispatch) { __Pyx_RefNannyDeclarations PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; PyObject *__pyx_t_3 = NULL; PyObject *__pyx_t_4 = NULL; __Pyx_RefNannySetupContext("greeting", 0); /* Check if called by wrapper */ if (unlikely(__pyx_skip_dispatch)) ; /* Check if overridden in Python */ else if (unlikely(Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0)) { __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_greeting); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 22, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); if (!PyCFunction_Check(__pyx_t_1) || (PyCFunction_GET_FUNCTION(__pyx_t_1) != (PyCFunction)__pyx_pw_4hoge_4Hoge_5greeting)) { __Pyx_INCREF(__pyx_t_1); __pyx_t_3 = __pyx_t_1; __pyx_t_4 = NULL; if (CYTHON_COMPILING_IN_CPYTHON && unlikely(PyMethod_Check(__pyx_t_3))) { __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3); if (likely(__pyx_t_4)) { PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); __Pyx_INCREF(__pyx_t_4); __Pyx_INCREF(function); __Pyx_DECREF_SET(__pyx_t_3, function); } } if (__pyx_t_4) { __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 22, __pyx_L1_error) __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; } else { __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 22, __pyx_L1_error) } __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; goto __pyx_L0; } __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; } /* "hoge.pyx":23 * * cpdef void greeting(self): * self.chello() # <<<<<<<<<<<<<< * * def hey(self): */ __pyx_f_4hoge_4Hoge_chello(__pyx_v_self); /* "hoge.pyx":22 * printf('my name is `%s`\n', self.name_.c_str()) * * cpdef void greeting(self): # <<<<<<<<<<<<<< * self.chello() * */ /* function exit code */ goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); __Pyx_XDECREF(__pyx_t_4); __Pyx_WriteUnraisable("hoge.Hoge.greeting", __pyx_clineno, __pyx_lineno, __pyx_filename, 0, 0); __pyx_L0:; __Pyx_RefNannyFinishContext(); } /* Python wrapper */ static PyObject *__pyx_pw_4hoge_4Hoge_5greeting(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ static PyObject *__pyx_pw_4hoge_4Hoge_5greeting(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("greeting (wrapper)", 0); __pyx_r = __pyx_pf_4hoge_4Hoge_4greeting(((struct __pyx_obj_4hoge_Hoge *)__pyx_v_self)); /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_4hoge_4Hoge_4greeting(struct __pyx_obj_4hoge_Hoge *__pyx_v_self) { PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations PyObject *__pyx_t_1 = NULL; __Pyx_RefNannySetupContext("greeting", 0); __Pyx_XDECREF(__pyx_r); __pyx_t_1 = __Pyx_void_to_None(__pyx_f_4hoge_4Hoge_greeting(__pyx_v_self, 1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 22, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0; /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("hoge.Hoge.greeting", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; }
↓hello()とgreeting()を呼び出すhey()の実装。
helloと同じでPythonから呼ばれる関数とネイティブ実装のペア。
なるほど。def宣言のhelloはPyObjectからメソッドを拾う段階でオーバーライドが解決されるが、
cpdef宣言のgreetingの方は__pyx_skip_dispatch=0にして呼び出し先でオーバーライドを解決している。
/* "hoge.pyx":25 * self.chello() * * def hey(self): # <<<<<<<<<<<<<< * self.hello() * self.greeting() */ /* Python wrapper */ static PyObject *__pyx_pw_4hoge_4Hoge_7hey(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ static PyObject *__pyx_pw_4hoge_4Hoge_7hey(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("hey (wrapper)", 0); __pyx_r = __pyx_pf_4hoge_4Hoge_6hey(((struct __pyx_obj_4hoge_Hoge *)__pyx_v_self)); /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_4hoge_4Hoge_6hey(struct __pyx_obj_4hoge_Hoge *__pyx_v_self) { PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations PyObject *__pyx_t_1 = NULL; PyObject *__pyx_t_2 = NULL; PyObject *__pyx_t_3 = NULL; __Pyx_RefNannySetupContext("hey", 0); /* "hoge.pyx":26 * * def hey(self): * self.hello() # <<<<<<<<<<<<<< * self.greeting() * */ __pyx_t_2 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_hello); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 26, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __pyx_t_3 = NULL; if (CYTHON_COMPILING_IN_CPYTHON && likely(PyMethod_Check(__pyx_t_2))) { __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2); if (likely(__pyx_t_3)) { PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2); __Pyx_INCREF(__pyx_t_3); __Pyx_INCREF(function); __Pyx_DECREF_SET(__pyx_t_2, function); } } if (__pyx_t_3) { __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 26, __pyx_L1_error) __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; } else { __pyx_t_1 = __Pyx_PyObject_CallNoArg(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 26, __pyx_L1_error) } __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; /* "hoge.pyx":27 * def hey(self): * self.hello() * self.greeting() # <<<<<<<<<<<<<< * */ ((struct __pyx_vtabstruct_4hoge_Hoge *)__pyx_v_self->__pyx_vtab)->greeting(__pyx_v_self, 0); /* "hoge.pyx":25 * self.chello() * * def hey(self): # <<<<<<<<<<<<<< * self.hello() * self.greeting() */ /* function exit code */ __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); __Pyx_AddTraceback("hoge.Hoge.hey", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; }
ネイティブからしか呼び出さない関数はcdefで良いとしてPythonからも呼び出す場合には、
Pythonからの呼び出しが多い場合はdef、ネイティブからの呼び出しが多い場合はcpdef、が良いのかな?
cpdefにしておくとネイティブ側で関数ポインタをvtabに保持しているが、defだと保持していない。最適化のひとつとしてdef/cpdefを選択するのが良いようだ。
.pyxはutf-8-sigにしてはいけない
# -*- coding: utf-8-sig -*- print(b'abc') print('abc') print('abc'.encode('utf-8-sig')) print('abc'.encode('utf-8'))
env = Environment() env.Append( CPPPATH=['C:/Python34/include'], LIBPATH=['C:/Python34/libs'], ) env.Command('hoge.cpp', 'hoge.pyx', 'python -m cython --embed --cplus -3 -o $TARGET $SOURCE') env.Program('hoge.cpp')
$ python -m cython --version Cython version 0.24 $ scons hoge.exe $ ./hoge.exe b'\xef\xbb\xbfabc' abc b'\xef\xbb\xbfabc' b'abc'
Cythonはヘッドラインを解析して文字列のエンコードを変えてるっぽいんだけど、utf-8-sigが来ることを想定していなくてBOMが入る。ソースファイルにutf-8-sigは使うなということか。
if括弧内で定義した変数の生存期間
ifの括弧内で定義した変数ってelseのスコープでも有効なのね。知らなかった。
// hoge.cpp #include <string.h> #include <stdio.h> int main(int argc, const char** argv) { if(int len = strlen(argv[1])) { printf("then, '%s' len = %d\n", argv[1], len); } else { printf("else, '%s' len = %d\n", argv[1], len); // ここでも len が使える } return 0; }
$ g++ hoge.cpp && ./a "xyz" && ./a "" then, 'xyz' len=3 else, '' len=0
vc14から同一スコープ内で同名の変数を定義すると警告が出るようになったので、始めて気付きました。
// 最初に見つかったインターフェースを使う if(auto ptr = get_primary_interface()) { ptr->doit(); } else if(auto ptr = get_secondary_interface()) { ptr->doit(); } else if(auto ptr = get_avoid_interface()) { ptr->doit(); } else { assert(!"絶望的"); }
こんなことをよく書いてたので怒られまくり。
luajit vs pypy 2016
前回検証した記事がもう4年前。
id:shive:20120112:1326376896
luajitがちらほら使われるのを見かけるようになったので久しぶりに再検証してみました。
https://github.com/shive/try_luajit
前に記事を書いた直後にpypyはluajitに抜かれていたので、その後変わらずな状況のようです。
今回はいくつか自前ビルドしてみましたが、luajitはポータビリティも高いのでやっぱ使うならこれかなぁ、というところでした。