programing

파이썬 함수(또는 코드를 직렬화)를 쉽게 피킹할 수 있는 방법이 있습니까?

powerit 2023. 7. 27. 22:26
반응형

파이썬 함수(또는 코드를 직렬화)를 쉽게 피킹할 수 있는 방법이 있습니까?

네트워크 연결을 통해 함수를 전송하려고 합니다(아시코어 사용).이렇게 전송하기 위해 파이썬 함수(이 경우 적어도 부작용이 없는 함수)를 직렬화하는 쉬운 방법이 있습니까?

다음과 유사한 기능을 사용하는 것이 이상적입니다.

def transmit(func):
    obj = pickle.dumps(func)
    [send obj across the network]

def receive():
    [receive obj from the network]
    func = pickle.loads(s)
    func()

함수 바이트 코드를 직렬화한 다음 호출자에서 재구성할 수 있습니다.마샬 모듈은 코드 객체를 직렬화하는 데 사용할 수 있으며, 코드 객체는 함수로 재조립될 수 있습니다.i:

import marshal
def foo(x): return x*x
code_string = marshal.dumps(foo.__code__)

그런 다음 원격 프로세스에서(code_string 전송 후):

import marshal, types

code = marshal.loads(code_string)
func = types.FunctionType(code, globals(), "some_func_name")

func(10)  # gives 100

몇 가지 주의 사항:

  • 마샬의 형식(해당 사항에 대한 파이썬 바이트 코드)은 주요 파이썬 버전 간에 호환되지 않을 수 있습니다.

  • cypthon 구현에서만 작동합니다.

  • 함수가 선택해야 하는 글로벌(가져온 모듈, 기타 기능 등)을 참조하는 경우 이러한 글로벌도 직렬화하거나 원격에서 다시 생성해야 합니다.이 예제에서는 원격 프로세스의 글로벌 네임스페이스를 제공합니다.

  • 폐쇄나 발전기 기능과 같은 더 복잡한 사례를 지원하려면 좀 더 많은 작업이 필요할 것입니다.

Python의 피클 라이브러리를 확장하여 다음 기능을 포함한 더 다양한 유형을 지원하는 Dill을 확인하십시오.

>>> import dill as pickle
>>> def f(x): return x + 1
...
>>> g = pickle.dumps(f)
>>> f(1)
2
>>> pickle.loads(g)(1)
2

또한 함수의 폐쇄에 있는 개체에 대한 참조도 지원합니다.

>>> def plusTwo(x): return f(f(x))
...
>>> pickle.loads(pickle.dumps(plusTwo))(1)
3

파이로가 당신을 위해 이것을 할 수 있습니다.

가장 간단한 방법은 아마도inspect.getsource(object)(검사 모듈 참조) 함수 또는 메서드에 대한 소스 코드가 포함된 String을 반환합니다.

이 모든 것은 런타임에 함수를 생성하는지 여부에 따라 달라집니다.

당신이 한다면,inspect.getsource(object)동적으로 생성된 함수는 객체의 소스를 가져올 때 작동하지 않습니다..py실행 전에 정의된 함수만 소스로 검색할 수 있습니다.

그리고 기능이 파일에 저장되어 있다면 수신자에게 해당 기능에 대한 액세스 권한을 부여하고 모듈 및 기능 이름만 전달하는 것이 어떻습니까?

동적으로 생성된 함수에 대한 유일한 해결책은 전송 전에 문자열로 함수를 구성하고 전송 소스를 만든 다음eval()수신기 쪽에 있습니다.

집편:marshal꽤 , 할 수 있는지 내장된 다른 것을 직렬화할 수 있는지 몰랐습니다.

현대의 파이썬에서는 함수와 다양한 변형을 피클링할 수 있습니다.이 점을 고려해 보십시오.

import pickle, time
def foobar(a,b):
    print("%r %r"%(a,b))

당신은 그것을 피클로 만들 수 있습니다.

p = pickle.dumps(foobar)
q = pickle.loads(p)
q(2,3)

당신은 피클 클로저를 사용할 수 있습니다.

import functools
foobar_closed = functools.partial(foobar,'locked')
p = pickle.dumps(foobar_closed)
q = pickle.loads(p)
q(2)

폐쇄가 로컬 변수를 사용하더라도

def closer():
    z = time.time()
    return functools.partial(foobar,z)
p = pickle.dumps(closer())
q = pickle.loads(p)
q(2)

그러나 내부 기능을 사용하여 닫으면 실패합니다.

def builder():
    z = 'internal'
    def mypartial(b):
        return foobar(z,b)
    return mypartial
p = pickle.dumps(builder())
q = pickle.loads(p)
q(2)

실수로

피클.피클링 오류:피클할 수 없습니다. <function mypartial at 0x7f3b6c885a50>: __main_.mypartial로 검색되지 않습니다.

Python 2.7 및 3.6으로 테스트됨

cloud패키지(인스턴스 설치 클라우드)는 종속성을 포함하여 임의 코드를 피클링할 수 있습니다.https://stackoverflow.com/a/16891169/1264797 을 참조하십시오.

code_string = ''defo(x):반환 x * 2정의 막대(x):반환 x ** 2'''
obj = pickle.dll(code_string)

지금이다

exec(pickle.bullet(obj))
foo(1)> 2막대(3)> 9

클라우드 피클은 아마도 당신이 찾고 있는 것일 것입니다.클라우드 피클은 다음과 같이 설명됩니다.

클라우드 피클은 네트워크를 통해 Python 코드가 전송되어 데이터에 가까운 원격 호스트에서 실행되는 클러스터 컴퓨팅에 특히 유용합니다.

사용 예:

def add_one(n):
  return n + 1

pickled_function = cloudpickle.dumps(add_one)
pickle.loads(pickled_function)(42)

다음을 수행할 수 있습니다.

def fn_generator():
    def fn(x, y):
        return x + y
    return fn

지금이다,transmit(fn_generator())는 실제 합니다.fn(x,y)모듈 이름에 대한 참조 대신 사용합니다.

동일한 방법을 사용하여 네트워크를 통해 클래스를 보낼 수 있습니다.

이 모듈에 사용되는 기본 기능은 쿼리를 포함하며, 와이어를 통해 최상의 압축을 얻을 수 있습니다. 지침 소스 코드:

y_serial.py 모듈 :: SQLite를 사용하는 웨어하우스 Python 개체

"Serialization + persistance :: 몇 줄의 코드로 Python 객체를 SQLite로 압축 및 주석 처리한 다음 나중에 SQL 없이 키워드별로 시간순으로 검색합니다.데이터베이스가 스키마가 없는 데이터를 저장하는 데 가장 유용한 "표준" 모듈입니다."

http://yserial.sourceforge.net

다음은 함수를 선택할 수 있도록 래핑하는 데 사용할 수 있는 도우미 클래스입니다.다에 대이 언된주사항에 대해 된 주의 marshal적용되지만 가능할 때마다 피클을 사용하도록 노력합니다.연속화 전반에 걸쳐 전역 또는 폐쇄를 보존하려는 노력은 없습니다.

    class PicklableFunction:
        def __init__(self, fun):
            self._fun = fun

        def __call__(self, *args, **kwargs):
            return self._fun(*args, **kwargs)

        def __getstate__(self):
            try:
                return pickle.dumps(self._fun)
            except Exception:
                return marshal.dumps((self._fun.__code__, self._fun.__name__))

        def __setstate__(self, state):
            try:
                self._fun = pickle.loads(state)
            except Exception:
                code, name = marshal.loads(state)
                self._fun = types.FunctionType(code, {}, name)

언급URL : https://stackoverflow.com/questions/1253528/is-there-an-easy-way-to-pickle-a-python-function-or-otherwise-serialize-its-cod

반응형