일하면서 2 : 파이썬 자료형 조심하자

27237 단어 IT > 창고ITIT

처음으로 운영성? 유지보수성 업무? 해서 비스무리하게 파악하게되어 정리

일단 문제는 여러개가 들어오던 데이터가 1개만 들어온 날에
(예를들어 실질적인 구분단위가 사람이고 그 안에 주렁주렁 데이터가 있는 형태고, '사람'=name 데이터가 1명만 들어온 케이스)

로그를 보니 갑자기 데이터 인덱싱에러가 난 상황.

그래서 의심점은 그냥 프로그램에러는 아닐것같았고 데이터 형태 문제-> 이전과 똑같이 왔다.

그래서 xml-> dictionary 에서 문제가 일어나거나 dictionary에서 key값 참조해 루프할 리스트 만드는 과정에서 에러 의심 (데이터가 단수개 들어온 상황에서)

결론적으로는 xml -> dictionary에서 하위엘레먼트가 단수/복수개일 경우 차이가 있었고(동일 key값 element가 복수개면 list로 감싸줌) 그래서 loop돌때 자료형 차이로 에러가 발생하는것이었음)

xml to dictionary : element 복수 케이스

input : xml파일

<info>
  	<name>
  	   <id>1</id>
           <id2>1</id2>
  	</name>
	<name>
  	   <id>2</id>
           <id2>2</id2>
  	</name>
  	<name>
          <id>3</id>
      	  <id2>3</id2>
  	</name>
</info>

대충 이런 xml데이터를 dictionary형태로 바꾸어서 리스트화 =>루프를 도는 코드였다.

import xmltodict

with open(path, 'r', encoding='utf-8') as f: xml_file = xmltodict.parse(f.read(), encoding='utf-8') 
received_data = dict(xml_file)
-> data_list = received_data['info']['name']

위와같이 데이터 저장 시 recieved data는

{'info': 
  OrderedDict([
    ('name', [
    	OrderedDict([
        	('id', '1'),('id2', '1') ]),
	OrderedDict([
    		('id', '2'),('id2', '2') ]),
	OrderedDict([
    		('id', '3'),('id2', '3') ]),
	] #key 'name'의 value (list)
    ) # ('name','value') end 괄호
  )] #ordereddict end괄호
}#dictionary end 괄호

위와 같이 저장된다. name의 value가 orderedDict의 List로 저장된다.

json으로 치면

{
  "info":
    {
       "name":{{
    		 {
                   "id":1,
      	           "id2":1
    		 },
  		 {
                   "id":2
		   "id2":2
		 },
                 {
            	   "id":3
              	   "id2":3
         	 },
           }}/*end name value*/
     }/*end info value
}/*end dictionary*/

약간 이런식

name값이 1개만 온다면 ? (내부 element가 1개뿐)

xml to dictionary : element 단수 케이스

<info>
  	<name>
  	   <id>1</id>
           <id2>1</id2>
  	</name>
</info>

데이터가 위와같이 온다면,

{'info': 
   OrderedDict([
      ('name', 
         OrderedDict([
            ('id', '1'), 
            ('id2', '1')
         ])
      )
   ])
}

똑같았다.
확인차 id가 1개뿐인경우도

{'info': 
   OrderedDict([
      ('name', 
         OrderedDict([
            ('id', '1')
         ])
     )]
  )
}

내부 element key:value는 단수:단일값자료형(integer등..)이 아니면 ordereddict로 감싸나온다.
( 단일값자료형이면 ('키','값')으로 아니면 ('키',orderedDict([])) )
의심했던건 단일값 자료형이 아니고 리스트같은 복수값 자료형(list..) 여도, 리스트에 값이 1개만 있다면 OrderedDict로 감싸지 않을 수 있다고 생각했는데, 그건아니었고,

*** ★ name의 value가 orderedDict의 List가 아닌 orderedDict 한개로 저장된다. =>
이부분이 나중에 루프를 돌때 indices 에러 발생시키는 원인이었다.

dictionary 참조 : 복수 element 케이스

data_list = received_data['info']['name']는

received_data['info']=OrderedDict([
    ('name', [
    	OrderedDict([
        	('id', '1'),('id2', '1') ]),
	OrderedDict([
    		('id', '2'),('id2', '2') ]),
	OrderedDict([
    		('id', '3'),('id2', '3') ]),
	] #key 'name'의 value (list)
    ) # ('name','value') end 괄호
  )] #ordereddict end괄호
received_data['info']['name']= [
    	OrderedDict([
        	('id', '1'),('id2', '1') ]),
	OrderedDict([
    		('id', '2'),('id2', '2') ]),
	OrderedDict([
    		('id', '3'),('id2', '3') ]),
	] #key 'name'의 value (list)
    ) # ('name','value') end 괄호

문제가 되었던 코드는

for a in data_list
    something = a['id'] ~~~

대충 이런 코드였는데
저 name value값인 list (orderdDict)가 루프에서 orderdict로 나오게 되어
차례로

idx0 : {"id":1, "id2";1}
idx1 : {"id":2, "id2";2}
idx2 : {"id":3, "id2";3}

요렇게 나온다.
=>각 루프 원소는 dictionary로 key값'id' 참조 가능하다.(정상케이스)

dictionary 참조 : 단수 element 케이스

data_list = received_data['info']['name']

++1개 오는 경우 received_data 다시한번 살펴보면

{'info': 
   OrderedDict([
      ('name', 
         OrderedDict([
            ('id', '1'), 
            ('id2', '1')
         ])
      )
   ])
}

이고,
data_list는

received_data['info'] = OrderedDict([
      ('name', 
         OrderedDict([
            ('id', '1'), 
            ('id2', '1')
         ])
      )
   ])
received_data['info']['name'] = 
         OrderedDict([
            ('id', '1'), 
            ('id2', '1')
         ])

=> data_list=received_data['info']['name'] 를 루프돌게되면
OrderedDict의 원소인

idx0 : ('id', '1'), 
idx1 : ('id2', '1')

이렇게 나온다. (데이터로부터 봤을때. (프로그래밍 돌린결과 X)
복수개일때와 비교해보면

#복수
data_list[0]: {"id":1, "id2";1}
data_list[1] : {"id":2, "id2";2}
data_list[2] : {"id":3, "id2";3}
#단수
data_list[0] : ('id', '1'),  # (X) , data_list['id']=1 (O)
data_list[1] : ('id2', '1') 

이 때 data_list[0]이 단수케이스일경우 가능한가 ?
=> X . 복수개일경우 data_list는 list자료형이지만,
단수개일경우 data_list는 OrderedDictionary이기때문에
data_list[0]은 0인 키값을 찾는것. **(복습하자면 dictionary는 순서가 없다. 인덱싱 X key-val)

이래저래 정리하느라 길게 쓰긴 했는데 결국 단수/복수개 처리가 없었어서 에러가 발생한것이었다.

약간 type선언 안해놓고 쓰는 js나 python에서는 이런 실수가 발생하기 쉽다~ 라고만 듣긴 들었던 것 같아서 스트링 리스트 / 인티저 플롯 / 스트링 인티저 / 쓰기전에 타입한번 확인해보자~ 조심 이정도수준으로만 생각했던거같은데
막상 이번에 업무에서 본 케이스에서 체감됬다고해야하나 그래서 정리해놓음.

좋은 웹페이지 즐겨찾기