首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >进口AST修改

进口AST修改
EN

Stack Overflow用户
提问于 2022-03-26 11:25:00
回答 1查看 126关注 0票数 1

在导入之前,我正在尝试动态重写pywin32 win32com.client模块,下面的代码似乎有效--但我不满意导入的6行代码(在最后的注释之后)。有人能推荐一种更简洁的方法来创建/导入结果模块(包)吗?

代码语言:javascript
复制
import sys, ast, types
import os.path
import importlib.util

import win32com

# import ast
_win32com_client_spec = importlib.util.find_spec("win32com.client")
_win32com_client_ast = ast.parse(open(_win32com_client_spec.origin).read())

(_win32com_client_dispatch_ast,) = (x for x in _win32com_client_ast.body if isinstance(x, ast.FunctionDef) and x.name == 'Dispatch')

# rename Dispatch
_win32com_client_dispatch_ast.name = '_OldDispatch'

# create new Dispatch
_my_dispatch_mod_ast = ast.parse("""
def Dispatch(*args, **kwds):
    base_inst = _OldDispatch(*args, **kwds)
    spec_inst = _OldDispatch(base_inst)
    return spec_inst
""")
(_my_dispatch_ast,) = _my_dispatch_mod_ast.body

# insert new Dispatch in module
_win32com_client_ast.body.insert(_win32com_client_ast.body.index(_win32com_client_dispatch_ast)+1, _my_dispatch_ast)

# import the package
_my_win32com_client_co = compile(_win32com_client_ast, '<patched win32com.client>', 'exec')
_my_win32com_client_mod = types.ModuleType('win32com.client')
_my_win32com_client_mod.__path__ = (os.path.dirname(_win32com_client_spec.origin),)
sys.modules[_my_win32com_client_mod.__name__] = _my_win32com_client_mod
win32com.client = _my_win32com_client_mod
exec(_my_win32com_client_co, _my_win32com_client_mod.__dict__)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-26 15:46:12

进一步阅读文档说明使用ModuleSpec对象比使用types.ModuleType更可取。

参考文献:https://docs.python.org/3/library/importlib.html#importlib.util.module_from_spec

生成的代码隐式地处理包的__path__,并允许在整个过程中重用spec对象。请注意,如果使用规范原点显示补丁如下,则文件属性应显式设置如下。

模块应该在执行之前导入,这对于子模块导入来说似乎很重要,就像在gencache模块(例如import win32com.client.CLSISToClass )中发现的那样

代码语言:javascript
复制
import sys, ast
import importlib.util

import win32com

if 'win32com.client' not in sys.modules:
    # import ast
    _win32com_client_spec = importlib.util.find_spec("win32com.client")
    _win32com_client_path = _win32com_client_spec.origin
    _win32com_client_spec.origin = '<patched win32com.client>'
    _win32com_client_ast = ast.parse(open(_win32com_client_path).read())

    # rename Dispatch
    (_win32com_client_dispatch_ast,) = (x for x in _win32com_client_ast.body if isinstance(x, ast.FunctionDef) and x.name == 'Dispatch')
    _win32com_client_dispatch_ast.name = '_OldDispatch'

    # create new Dispatch (disregard line numbers)
    _my_dispatch_mod_ast = ast.parse("""
def Dispatch(*args, **kwds):
    base_inst = _OldDispatch(*args, **kwds)
    spec_inst = _OldDispatch(base_inst)
    return spec_inst
""")
    (_my_dispatch_ast,) = _my_dispatch_mod_ast.body

    # insert new Dispatch in module
    _win32com_client_ast.body.insert(_win32com_client_ast.body.index(_win32com_client_dispatch_ast)+1, _my_dispatch_ast)

    # compile (original path for debugging), create, import and exec the module
    _my_win32com_client_co = compile(_win32com_client_ast, _win32com_client_path, 'exec')
    _my_win32com_client_mod = importlib.util.module_from_spec(_win32com_client_spec)
    _my_win32com_client_mod.__file__ = _win32com_client_path
    win32com.client = sys.modules['win32com.client'] = _my_win32com_client_mod
    try:
        exec(_my_win32com_client_co, _my_win32com_client_mod.__dict__)
    except:
        del win32com.client, sys.modules['win32com.client']
        raise
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71627631

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档