고급 파이썬 개발 과정
챕터
>
레벨

직렬화 모듈
구조체 모듈

목표

struct 모듈을 사용하여 새 농지에 대한 최종 데이터 분석을 설정하십시오.

도로 끝에는 이미 구축되어 있고 작물이 이미 심어진 새 농지를 관리하는 서비스 스테이션이 있습니다. 여기서 우리는 이미 심어진 작물과 농지의 예상 수확량에 대한 데이터를 검사하고 처리할 것입니다. 이 챕터의 다른 레벨과 마찬가지로 데이터를 직렬화 및 역직렬화하는 작업을 수행하며, 마지막으로 struct 모듈을 도입합니다.

struct 모듈은 이진 형식으로 데이터를 패킹하는 일련의 직렬화 함수를 제공합니다. 우리가 이전에 작업한 다른 모듈과 달리, 데이터를 직렬화 및 역직렬화할 때 구조를 세밀하게 제어할 수 있어 다른 모듈보다 더 유연합니다. 데이터 처리를 위해 다음 함수를 사용하려면 import struct를 사용하세요:

  • struct.calcsize(): 주어진 포맷 문자열이 패킹될 때 몇 바이트를 사용하는지 결정합니다. 하나의 인수(확인할 포맷)를 받습니다. 우리가 사용할 포맷은 다음과 같습니다:
    • integer: 전체 수(정수)를 나타내는 데이터의 포맷은 'i'입니다.
    • float: 소수점을 포함한 숫자 데이터를 나타내는 포맷은 'f'입니다.
    • double: float 포맷으로는 부족한 복잡한 소수점 숫자를 나타내는 포맷은 'd'입니다.
  • struct.pack(): 데이터를 이진 형식으로 직렬화하며, 원하는 포맷으로 패킹합니다. 최소 두 개의 인수(사용할 포맷과 직렬화할 값)를 받으며, 이전에 설명한 포맷 기호를 인수 개수에 맞추어 나열해야 합니다.
  • struct.unpack(): 패킹된 이진 데이터를 역직렬화합니다. 두 개의 인수(직렬화 시 사용한 포맷과 역직렬화할 데이터를 저장한 변수)를 받습니다.
  • struct.iter_unpack(): 패킹된 이진 데이터를 역직렬화하며, struct.unpack()과 동일하게 작동하지만 반복문을 통해 각 데이터 블록을 개별적으로 순회합니다.
  • struct.pack_into(): struct.pack()의 고급 버전으로, 네 개의 인수(사용할 포맷, 데이터를 저장할 버퍼, 버퍼에서 데이터를 저장할 위치, 직렬화할 값)를 받습니다.
  • struct.unpack_from(): struct.unpack()의 고급 버전으로, 세 개의 인수(사용할 포맷, 역직렬화할 버퍼, 역직렬화를 시작할 버퍼 내 위치)를 받습니다. 이를 통해 데이터의 특정 부분만 역직렬화할 수 있습니다.

서비스 스테이션 내 밝은 X 표식 지점으로 이동하여 책상을 바라보고, 다음 세 개의 변수를 만드세요: integer, float, double. 각 포맷의 크기를 struct.calcsize() 함수로 바이트 단위로 확인할 것입니다. integer 변수에는 'i'를 인수로, float 변수에는 'f'를 인수로, double 변수에는 'd'를 인수로 사용하세요. 예: integer = struct.calcsize('i'). 마지막으로 세 변수를 모두 미리 작성된 write() 함수에 전달하세요.

금색 X 표식 지점으로 이동하여 read() 함수를 사용해 새 농지에 대한 데이터를 수집하세요. 향후 사용할 데이터 포인트와 포맷, 즉 Resources, Size, Estimate를 기록해두세요. 기록이 끝나면 파란색 카펫 위의 밝은 X 표식 지점으로 이동하여 blue_data라는 변수를 만드세요.

이제 blue_data 변수에 struct.pack() 함수의 반환값을 저장하세요. 인수로는 앞서 기록한 포맷과 값을 전달합니다. 포맷을 지정할 때는 포맷 기호를 하나의 문자열로 결합해야 합니다. 예를 들어 정수 포맷은 'i'이므로 정수 세 개를 패킹할 때는 'iii'로, 정수 하나, 실수 하나, 더블 하나를 패킹할 때는 'ifd'로 작성합니다. 값을 추가할 때는 각 값을 개별 인수로 전달합니다. 전체 예시는 다음과 같습니다:

data_1 = 8 # is an integer data_2 = 2.25 # is a float data_3 = 900.702938103 # is a double blue_data = struct.pack('ifd', data_1, data_2, data_3)

struct.pack() 함수는 포맷을 자유롭게 설정하고 여러 데이터 포인트를 한 번에 직렬화할 수 있는 유연성을 제공합니다. 앞서 읽은 데이터를 위 예시를 참고하여 추가하세요. display(blue_data)를 사용해 패킹된 데이터를 확인하세요.

파란색 카펫 위의 어두운 X 표식 지점으로 이동하여 터미널을 바라보세요. blue_unpack라는 변수를 만들고 struct.unpack() 함수의 반환값을 저장하세요. 인수로는 데이터를 패킹할 때 사용한 동일한 포맷과 blue_data 변수를 전달합니다. 포맷은 struct.pack()처럼 작성하여 처음 직렬화한 방식대로 역직렬화할 수 있게 합니다. 마지막으로 write(blue_unpack)를 사용해 이전에 패킹한 데이터를 확인하세요.

같은 위치에서 struct.iter_unpack() 함수도 사용합니다. 이 함수는 struct.unpack()과 동일한 인수를 받지만, for 루프 형태로 각 데이터 블록을 반복 처리할 수 있습니다. 사용 예시는 다음과 같습니다:

for values in struct.iter_unpack(-insert value-, -insert value-): player.speak(values)

값을 표시하기 위해 speak() 함수를 사용합니다. struct.iter_unpack()의 인수에는 struct.unpack()에서 사용한 것과 동일한 포맷과 데이터를 전달하세요. 두 함수는 사용법이 동일한 변형입니다.

빨간색 카펫 위의 금색 X 표식 지점으로 이동하여 책상을 바라보고 read() 함수를 사용해 작물별 수량을 확인하세요. 각 작물의 수량과 포맷을 기록해두세요. 그런 다음 빨간색 카펫 위의 밝은 X 표식 지점으로 이동하여 buffer라는 객체를 만들고 bytearray(16)을 할당하세요. 이 객체는 데이터를 채우기 전에 바이트별로 접근할 수 있는 바이트 배열로, 일종의 데이터 뱅크처럼 수동으로 데이터를 저장할 수 있습니다. 인수 16buffer 객체에 저장할 수 있는 바이트 수입니다.

struct.pack_into() 함수를 사용해 생성한 buffer 객체에 데이터를 채워 넣으세요. 반환값을 저장할 변수를 따로 만들 필요 없습니다. 함수가 직접 buffer 객체에 값을 삽입합니다. 이전에 기록한 각 값에 대해 이 함수를 사용하고, 인수에 해당 포맷과 위치, 값을 전달하세요.

예를 들어 첫 번째 작물 값의 포맷, 바이트 위치, 수량이 주어졌다고 가정합니다. 첫 번째 인수에는 포맷을, 두 번째 인수에는 직렬화할 대상인 buffer 객체를 전달하세요. 세 번째 인수에는 buffer 내에서 값을 삽입할 위치를 지정합니다. 포맷에 따라 차지하는 바이트 수가 결정되므로 이미 사용된 영역을 피해 입력하세요. 마지막 인수에는 직렬화해 buffer에 패킹할 값을 전달합니다.

struct.pack_into('i', buffer, 0, 82)

buffer 객체는 앞서 언급한 대로 16 바이트를 가지고 있습니다. 위 코드에서 정수 포맷은 4 바이트를 차지하며 위치 0에 삽입됩니다. 즉, 해당 값(82)이 buffer의 위치 0~3에 저장된 후에는 12 바이트만 남습니다. 이전에 읽고 기록한 모든 작물 데이터(총 3개)에 대해 이 과정을 반복하세요. display(buffer)를 사용해 직렬화된 데이터를 확인하세요.

빨간색 카펫 위의 어두운 X 표식 지점으로 이동하여 터미널을 바라보세요. 이제 데이터를 역직렬화해 올바르게 저장되었는지 확인합니다. lettuce, carrots, melons라는 세 개의 변수를 만들고, 각 데이터 포인트를 개별적으로 역직렬화하세요. 각 변수에는 struct.unpack_from() 함수의 반환값을 저장합니다. 인수로는 먼저 포맷, 두 번째로 역직렬화할 버퍼(buffer), 세 번째로 버퍼 내에서 역직렬화를 시작할 위치를 전달합니다. 예를 들어:

lettuce = struct.unpack_from('i', buffer, 0)

위 예시에서 패킹한 데이터와 대응되며, 나머지 두 변수도 동일하게 처리하세요. 마지막으로 write(lettuce), write(carrots), write(melons)을 호출해 레벨을 완료합니다.

코드북