有人向我反應,在程式碼裡同時用我的python模組uiautomation和其它另一個模組後,指令碼執行時會報錯,但單獨使用任意一個模組時都是正常的,沒有錯誤。issue連結
我用一個例子來演示下這個問題是如何出現的。
假設我需要寫一個module,這個module需要提供獲取當前滑鼠游標下視窗控制程式碼的功能,這需要呼叫系統C API來實現。
實現如下:
module1.py
#!python3 # -*- coding: utf-8 -*- import ctypes import ctypes.wintypes class POINT(ctypes.Structure): _fields_ = [("x", ctypes.wintypes.LONG), ("y", ctypes.wintypes.LONG)] ctypes.windll.user32.WindowFromPoint.argtypes = (POINT, ) ctypes.windll.user32.WindowFromPoint.restype = ctypes.c_void_p ctypes.windll.user32.GetCursorPos.argtypes = (ctypes.POINTER(POINT), ) def WindowFromPoint(x, y): return ctypes.windll.user32.WindowFromPoint(POINT(x, y)) def GetCursorPos(): point = POINT(0, 0) ctypes.windll.user32.GetCursorPos(ctypes.byref(point)) return point.x, point.y def WindowFromCursor(): x, y = GetCursorPos() return WindowFromPoint(x, y)
呼叫的程式碼如下
test.py
#!python3 # -*- coding:utf-8 -*- import module1 def main(): print('the handle under cursor is', module1.WindowFromCursor()) if __name__ == '__main__': main()
執行結果如下
the handle under cursor is 1839250
這時複製一份module1.py,重新命名為module2.py,他們的程式碼是完全一樣的
在test.py同時呼叫這兩個module,程式碼如下
#!python3 # -*- coding:utf-8 -*- import module1 import module2 def main(): print('the handle under cursor is', module1.WindowFromCursor()) print('the handle under cursor is', module2.WindowFromCursor()) if __name__ == '__main__': main()
執行就會報錯了
ctypes.ArgumentError: argument 1: <class 'TypeError'>: expected LP_POINT instance instead of pointer to POINT
但分開單獨呼叫任一個模組就是正常的,不會出錯。
這是因為,module1,module2呼叫的同一個C函式,在設定argtypes的時候,後面的修改會覆蓋前面的設定。
執行
import module1 import module2
後,C函式中的POINT引數必須是module2.POINT才是合法的。
在用module1呼叫時,傳入的引數型別是module1.POINT,執行時就會報錯了。
這種錯誤應該只有在引數中有結構體或結構體指標時才會出現。
假設module1, module2分別是兩個人寫,你又要同時用這兩個module,只要有一個module設定了argtypes,執行時可能就會出錯。
解決方法是,在module1, module2中註釋兩行程式碼
#ctypes.windll.user32.WindowFromPoint.argtypes = (POINT, ) ctypes.windll.user32.WindowFromPoint.restype = ctypes.c_void_p #ctypes.windll.user32.GetCursorPos.argtypes = (ctypes.POINTER(POINT), )
不要修改argtypes,再執行test.py就不會報錯了。
作為庫的作者,需要主要一下,最好不要設定系統C函式的argtypes。