해결된 질문
작성
·
122
·
수정됨
1
2-4. [응용] 엑셀문서 값을 필드에 입력하기 관련입니다.
※ 원 질문글 올린 이후, 공부해서 이 글에 자문자답하였습니다. 검토 부탁드립니다. 감사합니다.
질문을 드리기 위하여 파이썬 콘솔(IPython 적용)에서 진행한 코드를 아래에 먼저 제시 후 말씀드리겠습니다.
excel = win32.gencache.EnsureDispatch("Excel.Application")
excel.Visible = True
wb = excel.Workbooks.Open(r"c:\Users\user\desktop\취미.xlsx")
ws = wb.Worksheets(1)
row = 2
data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value[0])
print(data[2])
1984-05-14 00:00:00+00:00
row = 2
data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value)
print(data[2])
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\site-packages\IPython\core\interactiveshell.py", line 3577, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-9-a5cbf3d139c3>", line 1, in <module>
print(data[2])
IndexError: list index out of range
# 아래는, data = ~~~.value[0] 일 경우의 데이터 형태를 출력해 보기 위함.
data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value[0])
print(data)
['마크', '남', pywintypes.datetime(1984, 5, 14, 0, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), 'VR']
# 아래는, data = ~~~.value 일 경우의 데이터 형태를 출력해 보기 위함.
data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value)
print(data)
[('마크', '남', pywintypes.datetime(1984, 5, 14, 0, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), 'VR')]
# 위에서 확인 결과, data = ~~~.value[0] 일 경우와 data = ~~~.value 일 경우에,
# print로 데이터 출력한 결과는 거의 비슷하나,
# data = ~~~.value 일 경우에는 대괄호 안에 괄호가 하나 더 있음.
위의 과정에서 아래와 같이 진행하면 물론 정상적으로 출력됩니다.
row = 2
data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value[0])
print(data[2])
1984-05-14 00:00:00+00:00
하지만 아래와 같이 진행하면 오류가 납니다. 원 코드에서 ~~~.Value 뒤에 [0] 만 빼 본 것입니다.
row = 2
data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value)
print(data[2])
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\site-packages\IPython\core\interactiveshell.py", line 3577, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-9-a5cbf3d139c3>", line 1, in <module>
print(data[2])
IndexError: list index out of range
row = 2 로 지정했으므로,
data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value) 은
엑셀의 (2,1)부터 (2,4)의 값을 리스트로 가져오는 것일테고,
원 코드인 data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value[0]) 도 역시,
지정한 범위의 값들 중 첫번째 행의 값만 가져오므로,
엑셀의 (2,1)부터 (2,4)의 값을 리스트로 가져오는 것은 두 경우에 같아 보이는데,
[질문 1]
왜 원 코드에서는 print(data[2]) 입력했을 때 정상적으로 출력이 되고,
원 코드에서 [0] 만 뺀 경우에는 print(data[2]) 입력했을 때 오류가 나는 것이지요?
__________________________________________________________________________________
P.S. _1 --- 이 질문글 올리고 천천히 강의내용을 다시 읽어 보니,
위 코드의 두 번째 라인을 보면, 리턴되는 값을 리스트로 변환하는 코드가 들어 있습니다.
기본적으로 ws.Cells나 ws.Range가 리턴하는 값은 튜플인데,
이 중 특정 값을 수정하기 위해 튜플을 수정 가능한 리스트 자료형으로 변환을 해 주었습니다.
라는 글이 눈에 들어오네요.
(※ 처음 읽었을 때는 무슨 말인지 잘 몰랐는데, 강의 내용에 다 써 있는데 제가 이해를 못했던 부분이 많네요.)
[('마크', '남', pywintypes.datetime(1984, 5, 14, 0, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), 'VR')]
요러한 형태가 말씀하신 튜플이라는 것이죠? 이런 형태의 data는 값을 수정할 수 없다는 말씀이죠?
반면에,
['마크', '남', pywintypes.datetime(1984, 5, 14, 0, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), 'VR']
요러한 형태는 튜플이 아닌 리스트 자료형이라는 것이죠? 이런 형태만이 data 값을 수정할 수 있다는 말씀이죠?
[질문 2]
튜플 형태의 데이터에 대하서는 data 값을 수정할 수 없는 것 뿐만 아니라 0, 1, 2번째의 데이터를 선택하는
data[0]
data[1]
data[2]
이러한 형태의 명령어조차도 쓸 수 없는 것이죠?
제가 쓴 이 내용들이 맞는지만 확인 부탁드립니다.
__________________________________________________________________________________
P.S. _2 --- 왕초보들이 더 쉽게 이해할 수 있게 개선의견을 말씀드리면, 아래와 같은 간단한 언급을 추가해주시면 더 좋지 않을까 합니다. (아래 쓴 내용이 맞다면요.)
튜플 형태의 data는 값을 수정할 수 없는데,
튜플 형태의 data를 print(data) 했을 때는 [( ~~~~ )] 형태로 확인되고,
리스트 형태의 data는 값을 수정할 수 있는데,
리스트 형태의 data를 print(data) 했을 때는, 괄호 ( ) 가 없이 [ ~~~ ] 형태로 확인되니 참고하세요.
참고로 튜플 형태의 data에 대해서는 data[2] 와 같은 형태로 데이터를 선택하는 명령어도 사용 불가능합니다. 튜플 형태의 data를 리스트 형태의 데이터로 바꿔야만 data[0] 와 같이 데이터를 선택하는 명령어를 사용 가능합니다.
확인 부탁드립니다. 감사합니다.
__________________________________________________________________________________
__________________________________________________________________________________
위 질문 글을 쓴 이후에 더 공부해 보고 아래와 같이 원인을 추정했습니다. 아래 내용이 위 [질문 1] 과 [질문 2]에 대한 답이 맞나요? 일코님이 바쁘실텐데 낮은 수준의 질문에 답변하느라 애쓰실 것에 죄송하여 그 사이에 자문자답(?)을 해보았습니다.
[질문 1] Value[0]을 사용한 경우에는 정상적으로 출력되고, Value만 사용한 경우에는 오류가 발생하나요?
[원인 분석]
엑셀에서 win32com을 사용하여 특정 셀 범위의 값을 가져올 때, Range.Value는 튜플 형태로 반환됩니다. 이때 반환된 값은 2차원 배열처럼 행(row) 단위로 묶여있습니다.
ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value는 튜플 안의 튜플 형태로 데이터를 반환합니다.
예를 들어, (2,1)부터 (2,4)까지의 값을 가져오면 결과는 다음과 같습니다:
(('마크', '남', datetime 객체, 'VR'),)
반면에 ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value[0]은 첫 번째 행의 값을 선택하는 것이므로, 단일 튜플이 됩니다:
('마크', '남', datetime 객체, 'VR')
따라서 data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value)의 경우 data는 튜플 안에 또 다른 튜플이 있는 상태입니다. 이때 data[2]를 호출하면 "IndexError"가 발생하는 이유는 data가 한 개의 튜플을 포함하고 있기 때문입니다. 즉, data 안에는 튜플이 있고, 실제 데이터는 그 튜플 안에 들어 있기 때문입니다.
반면에 data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value[0])을 사용하면 튜플 중 첫 번째 행의 데이터를 직접 리스트로 변환하므로 data[2]를 정상적으로 호출할 수 있습니다.
[위 내용 요약] Value[0] 사용하면 첫 번째 행의 데이터를 직접 가져오기 때문에 인덱싱이 가능하지만, Value만 사용하면 전체 범위가 튜플로 감싸져 있어 인덱싱 시 오류가 발생합니다.
[질문 2] 튜플 형태의 데이터에서 값을 수정하거나 인덱싱할 수 있나요?
[내용 추정]
튜플은 불변(immutable) 자료형이기 때문에 한 번 생성된 후에는 그 값을 수정할 수 없습니다.
하지만 튜플 내의 요소들을 조회하는 것은 가능합니다.
즉,
수정 불가: 튜플 내의 데이터를 변경하거나 삭제할 수 없습니다.
mytuple = (1, 2, 3)
mytuple[0] = 100
# TypeError 발생
조회 가능: 튜플 내 특정 인덱스의 데이터를 조회하는 것은 가능합니다.
mytuple = (1, 2, 3)
print(mytuple[0])
# 출력: 1
따라서 질문에서 언급한 것처럼 튜플 형태의 데이터에서는 값을 수정할 수 없지만, 인덱싱을 통해 특정 요소에 접근하는 것은 가능합니다.
즉:
data[0] # 가능
data[1] # 가능
data[2] # 가능
따라서 인덱스 접근은 가능하지만 수정은 불가능합니다.
다만, 주의할 점은 위에서
data[0] # 가능
이라고 하였지만, 이것은 data가 튜플일 경우입니다.
data가 튜플 내에 튜플인 경우, 즉 이중 튜플인 경우에는,
data[0] # IndexError 발생
[위 내용 요약] 튜플은 불변 자료형으로 값을 수정할 수 없지만, 인덱스를 통해 요소를 조회하는 것은 가능합니다. 다만, 이중 튜플인 경우 인덱스를 통해 요소를 조회 시도 시 IndexError가 발생합니다.
답변 1
1
헉 답변이 늦었어요!^^;
문제정의를 하고 스스로 학습해 가시는 과정을 보니,
학생 때에도 관심분야 공부를 잘 하셨을 듯 해요ㅎ
아래 제 설명이 다소 장황하더라도 천천히 읽어주시면 좋겠어요!^^
우선
data = list(ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value[0])
print(data[2])
1984-05-14 00:00:00+00:00
위 코드 첫 라인 끝의 [0]
을 빼겠다는 것은
리스트나 튜플(혹은 문자열) 전체를 data에 담겠다는 뜻이지요. (주현님이 이해하신 바와 같아요.)
(기존 코드는 배열 전체가 아니라 배열이 첫 번째 원소 [0]
만 data에 담겠다고 명령한 거고요.)
근데 위와 같은 경우에는 Value가 어떤 형식인지, 혹은 사이즈가 어떻게 되는지 대략 알고 있어야 해요.
우선 ws.Range(ws.Cells(row,1), ws.Cells(row,4)).Value
만 출력을 해보면
빨간 네모를 보면 좀 특이하지 않나요?
괄호가 2중이거든요. 두 겹 튜플인 거죠. (2차원이라고도 부르고요.)
엑셀의 ws.Range 메서드는 파이썬으로 값을 전송할 때, 특이하게 항상 2차원 튜플로만 내보내요.
행이 하나든 여러개든 말예요. 이게 핵심인데 제가 설명을 빠뜨린 것 같네요ㅜ
하여튼 ws.Range로 값을 뽑으면 행이 하나라도
(('A1셀', 'B1셀', 'C1셀', 'D1셀'),)
식으로 두 겹이 되는데요.아직은 좀 생소할 수 있지만 조금만 파이썬에 익숙해지면,
그냥 자연스럽고 당연하게 shape을 체크하게 되는 시점이 있을 거예요^^
조금 거리가 있는 예시이긴 하지만
예를 들어 케라스, 파이토치나 사이킷런 같은 머신러닝/딥러닝 프레임워크에서는
데이터셋 한 개를 모델에 넣어야 할 때 [[1,2,3,4,5]] 라고 입력해야 하는데
초보자들이 가장 많이 하는 실수 중 하나가 [1,2,3,4,5] 라고 넣는 거거든요. (우리랑 비슷하죠?^^;)
혹은 OpenCV 같은 이미지 라이브러리를 다룰 때에도 그렇고, 하여튼 shape이 중요해요.
다시 우리 예제로 돌아와서 보면,
파이썬으로 가공할 때 가장 바깥쪽의 있으나마나한 튜플 한 겹을 걷어내려고
[0]
인덱싱을 더한 거예요.
그리고 [0]
을 넣지 않고 코드를 실행했을 때 오류가 났던 이유는 복잡한 게 아니라,
현재 data
튜플 안에 요소가 딱 한 개(요소가 네 개 들어있는 튜플) 밖에 안 들어 있으니까
세 번째 요소(data[2]
)를 출력하라고 할 때 인덱스 오류가 발생한 거고요.
(이 상태에서 오류가 나지 않게 조회하려면 data[0][2]
라고 명령하면 되고요.)
이미 대부분 스스로 답을 찾으셨던데,
하여튼 모든 의문이 해소되었길 바랍니다.
저는 아직도 파이썬 코딩 하면서
IndexError, FileExistsError, TypeError 같은 오류를 정말 숨쉬듯이 만나거든요ㅋ
주현님도 실수로 오류가 나왔을 때, 어떤 오류가 왜 나왔는지
오류메시지를 (필요하면 트레이스백까지) 꼭 읽고, 이해하는 습관을 들이시면 좋겠어요.
오류가 너무 길면 제일 아래에 출력되는 오류 종류와 설명만 읽으셔도 돼요.
예를 들어 주현님이 만났던 IndexError: list index out of range
라는 오류는
"해당 리스트의 크기보다 인덱스가 커서 요소를 인덱싱할 수 없어요!" 라는 뜻이니까,
그때 그냥 생각 흐르는 대로,
'왜 data의 크기가 2보다 작지? 값이 네 개 아니었나? data를 확인해볼까?'라며
오류가 나는 라인 앞에 print(data)나 print(len(data))를 추가해보기도 하고,
'아, data가 튜플을 하나 담고 있는 튜플이구나! 그 안의 튜플이 열데이터구나!?'를 알게 된다든지...
이런 식으로 오류메시지를 활용하시면 코딩에 큰 도움이 돼요.
오류를 만나는 게 그리 나쁜 건 아닌 듯 해요. (자꾸 이야기가 오류 쪽으로 흘러가는데...)
저도 퇴근하고 피곤한데, 일은 또 해야 하니까 컴퓨터 앞에 앉아 코딩을 할 때가 있거든요.
그런 컨디션에서 에너지를 최대한 효율적으로 쓰면서 코딩을 무리없이 해낼 수 있는
일종의 노하우가 있어요.
그건 바로, 오류를 가이드 삼아 코드를 작성하고 고치는 거예요.
정신 바짝 차리고 긴장한 상태에서 모든 변수와 타입, 함수명을 머리에 담은 상태로 코딩을 하면
뭔가 오류도 줄고 코딩이 잘 될 것 같은데, 그런 상태는 에너지 소모가 정말정말 크거든요?ㅜ
근데,
① 머리를 비우고(IDE가 다 보여주니까),
② 오류에 놀라거나 스트레스 받지 않으면서(오히려 고마워하면서)
코딩을 하고 있으면, 어느 시점에 자연스레 몰입도 되고
그러면 코딩도 즐겁게 잘 마쳐지는 경우가 많아요.
(의외로 EDD, Error Driven Development라는 용어도 실제로 쓰인답니다^^;)
아직은 주현님이 파이썬 문법 기초에 조금만 더 비중을 두시면 좋겠어요.
엑셀이나 아래아한글 API 사용은 사실 간단하거든요?
명령어 종류나 사용법이 너무 많으니까 복잡해 보이는 거지..
(한컴 포럼에 보면 아래아한글 개발하시는 분들도 아래아한글 메서드 다 못 외워요..)
오히려 파이썬 기본 문법(반복문, 조건문)이랑 기본자료형(문자열, 숫자, 리스트, 튜플, 딕셔너리),
기본자료형의 인덱싱과 메서드 사용법 정도까지만 먼저 익혀보셔도
업무자동화 코딩이 정말 훨~씬 수월해질 거예요.
파이썬 기초는 자칫 따분하고 지루할 수도 있는 내용이지만,
박응용 작가님의 점프투파이썬이나, 윤인성 작가님의 혼공파 같은 책들
앞부분만 서너 번 반복해서 훑어보시면 주현님께 큰 도움이 될 거라고 믿어요.
특히 점프투파이썬은 온라인으로 무료로도 읽어보실 수 있으니까요. 링크
그리고 win32com을 직접 다루는 내용은 아니지만
pyhwpx라는 모듈로 아래아한글을 조작하는, 입문난이도의 무료 이북도 있거든요?
인터페이스 차이는 조금 다르지만, 주현님이 다루시기에 좀 더 편하지 않을까 생각도 들어요. 링크
답글을 무슨 장문편지 쓰듯이 남겨버렸네요ㅜㅜㅜ
정말 마지막으로 드리고 싶은 말씀은,
완강하고 나서 꼭 도전하고 싶은 업무 프로그램이 있다면
지금 알려주세요.
제가 간결한 코드, 꼼꼼한 주석에 컴파일로 exe파일까지 첨부해서
답글로든 영상으로든 남겨드릴게요!ㅎ
제가 할 수 없는 영역이라면, 학습루트나 다른 전문가를 소개해드릴게요.
그럼 행복한 하루 되세요^^
안녕하세요, 일코님. 주말에도 감동적인 답변 정말 감사합니다. ^^
강의 자체도 좋지만, 언제나 답변주신 내용마다 더 명확히 이해하게 돕는 내용이 많아서 정말 좋습니다.
원래는 지금 쓰는 이 답글에는 이런이런 부분 설명주신 게 명확하게 이해하는데 너무 많은 도움이 되었어요~ 라는 식으로 콕 집어서 쓰려고 했는데 쓰다 보니 일코님 답글 전부를 그대로 다시 쓰고 있는 저를 발견하였습니다.
그래도 딱 하나만 고르면 2차원 튜플에 대한 설명이 제일 명쾌했어요. 저의 어설펐던 이해를 아주 깔끔하게 만들어 주셨네요.
아무튼 답글 전체를 되새길 겸 아래에 다시 정리합니다;;
■ 2차원 튜플에 대한 설명
엑셀의 ws.Range 메서드는 파이썬으로 값을 전송할 때, 항상 2차원 튜플로만 내보냄.
강의 예제에서는,
2차원 튜플 중 불필요한 바깥쪽 튜플 한 겹을 걷어내려고 [0] 인덱싱을 더한 것임.
[0]을 넣지 않고 코드 실행 시 오류가 났던 이유는,
data튜플 안에 요소가 1개(요소가 4개 들어있는 튜플)뿐이므로,
3번째 요소(data[2])를 출력 시도 시 인덱스 오류가 발생.
(이 상태에서 data[0][2]라고 명령하면 조회 가능.)
■ 오류를 이해하는 습관의 중요성
실수로 오류가 나왔을 때, 어떤 오류가 왜 나왔는지 오류메시지를 (필요하면 트레이스백까지) 꼭 읽고, 이해하는 습관을 들이는 걸 권장.
(오류가 너무 길면 제일 아래에 출력되는 오류 종류와 설명만 읽더라도.)
■ 파이썬 기본문법 숙달은 원활한 업무자동화의 토대.
원활한 업무자동화 코딩을 위해 파이썬 기본문법을 탄탄히 익힐 것을 권장. (추천 공부 범위는 아래)
1. 파이썬 기본 문법(반복문, 조건문)
2. 기본자료형(문자열, 숫자, 리스트, 튜플, 딕셔너리)
3. 기본자료형의 인덱싱과 메서드 사용법
■ 전자책 및 자료 링크 (원 답글 참고)
1. 점프투파이썬
2. pyhwpx 관련 자료
■ 꼭 도전하고 싶은 업무 프로그램 있다면 일코님에 문의
고행하듯 강의 완강하려고 애쓸 필요 없음.
모든 걸 다 이해하고 나서 만들려고 하는 건 힘들고 비효율적이라는 말씀이신 듯.
구현하고 싶은 자동화 업무가 생긴다면 주저하지 말고 그것을 도와줄 수 있는 분(일코님)에게 도움을 요청해서 빠른 길을 찾는 게 유리함.