복붙노트

[PYTHON] 파이썬에서 문자열로부터 모듈로드하기

PYTHON

파이썬에서 문자열로부터 모듈로드하기

나는 문자열의 형태로 몇 가지 코드를 가지고 있으며 디스크에 쓰지 않고 모듈을 만들고 싶습니다.

imp 및 StringIO 객체를 사용하여이 작업을 수행하면 다음과 같이 나타납니다.

>>> imp.load_source('my_module', '', StringIO('print "hello world"'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: load_source() argument 3 must be file, not instance
>>> imp.load_module('my_module', StringIO('print "hello world"'), '', ('', '', 0))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: load_module arg#2 should be a file or None

실제 파일이 없어도 모듈을 만들려면 어떻게해야합니까? 또는 디스크에 쓰지 않고 파일에서 StringIO를 어떻게 랩핑 할 수 있습니까?

최신 정보:

참고 :이 문제는 또한 python3의 문제입니다.

로드하려고하는 코드는 부분적으로 만 신뢰할 수 있습니다. 나는 ast를 통해 그걸 가져 왔고, 아무것도 가져 오지 않거나 좋지 않은 일을한다고 결정했다. 그러나 그 주위를 돌고있는 지역 변수가있을 때 그것을 실행할만큼 충분히 신뢰하지 않는다. 내가 가져 오려고하는 코드의 방해가되지 않도록 내 자신의 코드를 신뢰하지 않습니다.

다음을 포함하는 빈 모듈을 만들었습니다.

def load(code):
    # Delete all local variables
    globals()['code'] = code
    del locals()['code']

    # Run the code
    exec(globals()['code'])

    # Delete any global variables we've added
    del globals()['load']
    del globals()['code']

    # Copy k so we can use it
    if 'k' in locals():
        globals()['k'] = locals()['k']
        del locals()['k']

    # Copy the rest of the variables
    for k in locals().keys():
        globals()[k] = locals()[k]

그런 다음 mymodule을 가져 와서 mymodule.load (code)를 호출 할 수 있습니다. 이것은 내가로드하는 코드가 전역을 사용하지 않도록하기 때문에 저에게 효과적입니다. 또한 global 키워드는 구문 분석기 지시문 일 뿐이며 exec 외부의 것은 참조 할 수 없습니다.

이것은 실제로 디스크에 쓰지 않고 모듈을 가져 오는 데 너무 많은 작업이지만, 이것을 원한다면 가장 좋은 방법이라고 생각합니다.

해결법

  1. ==============================

    1.다음은 문자열을 모듈로 가져 오는 방법입니다 (Python 2.x).

    다음은 문자열을 모듈로 가져 오는 방법입니다 (Python 2.x).

    import sys,imp
    
    my_code = 'a = 5'
    mymodule = imp.new_module('mymodule')
    exec my_code in mymodule.__dict__
    

    파이썬 3에서 exec는 함수이므로 다음과 같이 작동해야합니다.

    import sys,imp
    
    my_code = 'a = 5'
    mymodule = imp.new_module('mymodule')
    exec(my_code, mymodule.__dict__)
    

    이제 모듈 속성 (및 함수, 클래스 등)에 액세스합니다.

    print(mymodule.a)
    >>> 5
    

    가져올 다음 시도를 무시하려면 모듈을 sys :

    sys.modules['mymodule'] = mymodule
    
  2. ==============================

    2.모듈의 코드가 문자열에 있으면 StringIO를 사용하지 않고 exec와 함께 직접 사용할 수 있습니다 (아래에 dynmodule.py라는 파일이 있음). Python 2 및 3에서 작동합니다.

    모듈의 코드가 문자열에 있으면 StringIO를 사용하지 않고 exec와 함께 직접 사용할 수 있습니다 (아래에 dynmodule.py라는 파일이 있음). Python 2 및 3에서 작동합니다.

    from __future__ import print_function
    
    class _DynamicModule(object):
        def load(self, code):
            execdict = {'__builtins__': None}  # optional, to increase safety
            exec(code, execdict)
            keys = execdict.get(
                '__all__',  # use __all__ attribute if defined
                # else all non-private attributes
                (key for key in execdict if not key.startswith('_')))
            for key in keys:
                setattr(self, key, execdict[key])
    
    # replace this module object in sys.modules with empty _DynamicModule instance
    # see Stack Overflow question: http://bit.ly/ff94g6)
    import sys as _sys
    _ref, _sys.modules[__name__] = _sys.modules[__name__], _DynamicModule()
    
    if __name__ == '__main__':
        import dynmodule  # name of this module
        import textwrap  # for more readable code formatting in sample string
    
        # string to be loaded can come from anywhere or be generated on-the-fly
        module_code = textwrap.dedent("""\
            foo, bar, baz = 5, 8, 2
    
            def func():
                return foo*bar + baz
    
            __all__ = 'foo', 'bar', 'func'  # 'baz' not included
            """)
    
        dynmodule.load(module_code)  # defines module's contents
    
        print('dynmodule.foo:', dynmodule.foo)
        try:
            print('dynmodule.baz:', dynmodule.baz)
        except AttributeError:
            print('no dynmodule.baz attribute was defined')
        else:
            print('Error: there should be no dynmodule.baz module attribute')
        print('dynmodule.func() returned:', dynmodule.func())
    

    산출:

    dynmodule.foo: 5
    no dynmodule.baz attribute was defined
    dynmodule.func() returned: 42
    

    execdict 사전에서 '__builtins__'항목을 없음으로 설정하면 코드가 __import__와 같은 내장 함수를 직접 실행하지 못하도록하므로 코드를 더 안전하게 실행합니다. 당신은 당신이 느끼고있는 것들을 선별 적으로 추가함으로써 그러한 제한을 완화 할 수 있습니다.

    코드에서 사용할 수있게하려는 미리 정의 된 유틸리티와 속성을 추가하여 해당 코드가 실행될 사용자 정의 실행 컨텍스트를 만들 수도 있습니다. 이런 종류의 일은 "플러그인"또는 다른 플러그인을 구현하는 데 유용 할 수 있습니다 사용자 확장 가능 아키텍처.

  3. ==============================

    3.간단히 Module 객체를 만들고이를 sys.modules에 채우고 코드를 내부에 넣을 수 있습니다.

    간단히 Module 객체를 만들고이를 sys.modules에 채우고 코드를 내부에 넣을 수 있습니다.

    같은 것 :

    import sys
    from types import ModuleType
    mod = ModuleType('mymodule')
    sys.modules['mymodule'] = mod
    exec(mycode, mod.__dict__)
    
  4. ==============================

    4.exec 또는 eval을 사용하여 파이썬 코드를 문자열로 실행할 수 있습니다. 여기, 여기, 여기를 참조하십시오.

    exec 또는 eval을 사용하여 파이썬 코드를 문자열로 실행할 수 있습니다. 여기, 여기, 여기를 참조하십시오.

  5. ==============================

    5.imp.load_source에 대한 문서는 (필자의 강조) :

    imp.load_source에 대한 문서는 (필자의 강조) :

    ...이 방법으로 운이 나빠질 수도 있습니다, 두렵습니다.

    아마도이 경우 eval만으로도 충분할 것입니까?

    이것은 다소 놀라운 요구 사항처럼 들리지만 실제로 해결하려고하는 문제에 대해 질문에 더 추가하면 도움이 될 수 있습니다.

  6. from https://stackoverflow.com/questions/5362771/load-module-from-string-in-python by cc-by-sa and MIT license