pickeled 함수를 호출 할 때 RecursionError [중복]
다음 코드를 실행하려고합니다.
import pickle
def foo():
print("i am foo")
pickle_foo = pickle.dumps(foo)
def foo():
print("i am the new foo")
fkt = pickle.loads(pickle_foo)
return fkt()
foo()
예상되는 동작은 다음과 같습니다.
- 새로 정의 된 함수 "foo"가 호출됩니다.
- 새 함수에서 이전 함수는 선택 해제 된 다음
출력 을 호출 합니다.
i am the new foo
i am foo
실제로 일어나는 일은 다음과 같습니다.
- 새 함수 foo가 호출 된 다음 재귀 오류가 발생할 때까지 자신을 재귀 적으로 호출합니다.
RecursionError: maximum recursion depth exceeded while calling a Python object
두 함수의 이름이 다르게 지정되면 오류가 발생하지 않지만 내 프로젝트에는 매우 실용적이지 않습니다. 누구든지이 동작이 발생하는 이유와이를 방지하는 방법 (함수 이름을 변경하지 않고)을 설명 할 수 있습니까?
답변
pickle모듈 절임 기능은 완전한 이름 레퍼런스를 기반으로. 즉, 함수가 코드의 어딘가에 재정의 된 다음 피클 참조를 해제하면이를 호출하면 새 정의가 호출됩니다.
Python 문서 에서 pickle:
함수 (내장 및 사용자 정의)는 값이 아닌 "정규화 된"이름 참조로 피클됩니다. 2 이것은 함수가 정의 된 모듈의 이름과 함께 함수 이름 만 선택됨을 의미합니다. 함수의 코드 나 함수 속성은 선택되지 않습니다. 따라서 정의 모듈은 언 피클 링 환경에서 가져올 수 있어야하며 모듈에는 명명 된 객체가 포함되어야합니다. 그렇지 않으면 예외가 발생합니다.
그러나 할 수있는 일은 inspect.getsource()함수의 소스 코드를 검색하고이를 피클하는 데 사용하는 것입니다. 이를 위해서는 코드가 파일 시스템의 어딘가에서 소스로 사용 가능해야하므로 컴파일 된 C 코드를 가져 오거나 다른 외부 소스 (인터프리터 입력, 동적으로로드 된 모듈)가 작동하지 않습니다.
피클을 풀 때를 사용 exec하여 함수로 변환하고 실행할 수 있습니다.
참고 : 이것은 foo매번 재정의 되므로에 대한 호출 foo이 동일한 효과를 갖는다 고 보장 할 수 없습니다.
참고 2 : exec안전하지 않으며 일반적으로 외부 소스와 상호 작용하는 코드에 적합하지 않습니다. exec임의의 코드를 실행하려는 잠재적 인 외부 공격으로부터에 대한 호출을 보호해야합니다 .