copyreg

매일 공부(ML)·2022년 10월 1일
0

이어드림

목록 보기
141/146

copyreg를 사용하여 pickle를 더 신뢰성있게 만들어라

pickle

  • 직렬화 형식이 안전하지 않다.

  • 악의적인 pickle데이터가 자신을 역직렬화하는 파이썬 프로그램의 일부를 취약하게 만들 수 있다.


Json

  • 설계상 안전하다

  • 객체 계층 구조를 간단하게 묘사한 값이 들어있다.

  • 역직렬화해도 추가적인 위험에 노출될 일이 없다.

  • 서로 신뢰할 수 없는 프로그램 통신 시 JSON같은 형식 사용한다.


코드로 보는 예시

class GameState:
    def __init__(self):
        self.level = 0
        self.lives = 4

state = GameState()
state.level += 1
state.lives -= 1

print(state.__dict__)
{'level': 1, 'lives': 3}
#dump 함수를 사용해서 GameState 객체를 파일에 기록
import pickle

state_path = 'game_state.bin'
with open(state_path, 'wb') as f:
    pickle.dump(state, f)

#직렬화된 적이 없게 다시 돌려받기

with open(state_path,'rb') as f:
    state_after = pickel.load(f)

print(state_after.__dict__)

역직렬을 pickel을 활용하여 할 경우 클래스의 인스턴스 동작이 더 혼랍스럽다.

왜냐하면, pickle 모듈이 작동하는 방식의 부산물이기때문이다.


copyreg 내장 모듈 사용

  • 위의 문제 해결

  • pickel 동작 제어 및 동작의 신뢰성을 높인다.


방법1: 디폴트 애트리뷰트 값

디폴트 인자가 있는 생성자를 사용하면 GameState 객체를 언피클 했을 때도 함상 필요한 모든 애트리뷰트 포함

class GameState:
    def __init__(self, level=0, lives=4, points=0):
        self.level = level
        self.lives = lives
        self.points = points

#필요한 도우미 함수 만들기

def pickle_game_state(game_state):
    kwargs = game_state.__dict__
    return unpickle_game_state, (kwargs,)

def unpickle_game_state(kwargs):
    return GameState(**kwargs)


import copyreg

copyreg.pickle(GameState, pickle_game_state)

state = GameState()
state.points += 1000
serialized = pickle.dumps(state)
state_after = pickle.loads(serialized)
print(state_after.__dict__)

방법2: 클래스 버전 지정

하위 호환성으로 파이썬 객체의 필드가 제거되면 디폴트 인자를 사용할 수 없다.

해결: copyreg함수에게 전달하는 함수에 버전 파라미터 추가를하면 된다.

def pickle_game_state(game_state):
    kwargs = game_state.__dict__
    kwargs['version'] = 2
    return unpickle_game_state, (kwargs,)

#GameState 생성자에 전달할 인자를 적절히 변경 가능

def unpickle_game_state(kwargs):
    version = kwargs.pop('version', 1)
    if version == 1:
        del kwargs['lives']
    return GameState(**kwargs)

방법3: 안정적인 임포트 경로

클래스 이름을 바꾸면 코드가 깨지는 경우가 이ㅆ다.

프로그램이 존재하는 생명 주기에서 클래스 이름을 변경하거나 클래스를 다른 모듈로 옮기는 방식으로 코드 리팩터링

copyreg.pickle(BetterGameState, pickle_game_state)

Summary

  • 신뢰할 수 있는 프로그램 사이에 객체를 직렬화하고 역직렬화할 때는 pickle 내장 모듈이 유용하다.

  • 시간이 지남에 따라 클래스가 바뀔(애트리뷰트의 추가나 삭제 등)수 있으므로 이전에 피클한 객체를 역직렬화면 문제가 생긴다.

  • 직렬화한 객체의 하위 호환성을 보장하고자 copyreg 내장 모듈과 pickle를 함께 사용

profile
성장을 도울 아카이빙 블로그

0개의 댓글