- 14
- NoYeah
- 조회 수 497
만약 리스트 형으로
A = [20, 55, 67, 82, 45, 33, 90, 87, 100, 25]
가 있다고 하고 이 중에 50점 이상인 점수만 뽑아내려고 했습니다.
그래서 제가 처음에 생각한 코드는
while A: if A.pop() >= 50: print(A.pop())
으로 작성하였으나
결과물에는
87 33 67 20
이렇게만 나옵니다.
그래서 애초에 A.pop() 부분을 변수로 아래처럼 치환하였습니다.
while A: b = A.pop() if b>= 50: print(b)
이렇게 A.pop() 을 b로 지정해서 돌려보니 올바른 결과값인
100 87 90 82 67 55
가 나왔습니다.
A.pop() 을 변수로 치환한거 말고는 별다른 과정이 없는데 왜 이렇게 결과값이 달라지는 것인지 궁금하네요.
작성자
댓글 14
아하!
제가 이해한게 맞는지 궁금하군요.
변수로 b=A.pop()을 지정하지 않은 경우 A.pop()으로 값을 뽑아낸 즉시, 리스트에서 삭제가 되는데
b=A.pop()으로 지정하면 pop()으로 리스트에 삭제가 되어도 b의 값은 같은 값을 갖은 채로 유지되기 때문이라고 할 수 있군요.
id(b) 값과 is(A.pop()) 의 값이 같은 값을 갖게 되는 건가요?
빙고~! 말씀하신 것이 정확하십니다 :)
while문이 반복되면서 pop() 메서드가 실행될 때마다 마지막 요소의 값을 뽑아내면서 동시에 그 요소가 삭제됩니다.
반면 변수 b에 대입을 하면 그 값은 다른 값을 대입하기 전까지 유지가 되죠.
id() 함수는 객체의 고유값(주소)을 반환합니다.
제가 정확하게 아는 것인지 모르겠지만 그 값은 대체로 메모리 주소값이라고 알고 있습니다.
A.pop()을 b에 대입하면 그 id() 값은 동일하게 됩니다.
조금 변형된 스크립트를 실행해보시면 값이 동일함을 확인할 수 있습니다.
list_a = [20, 55, 67, 82, 45, 33, 90, 87, 100, 25] n = 0 while n<len(list_a): var_b = list_a[n] print(id(list_a[n])) print(id(var_b)) n+=1
보다 간단히 is() 함수를 사용하여 두 객체의 고유값이 동일한지 여부를 보다 직관적으로 확인할 수 있습니다.
list_a = [20, 55, 67, 82, 45, 33, 90, 87, 100, 25] n = 0 while n<len(list_a): var_b = list_a[n] print(var_b is list_a[n]) n+=1
그런데 id()의 값은 변수캐싱도 있어서 그 값이 동일하지 않을 것 같은데 동일한 경우도 있고 상당히 복잡하다고 알고 있습니다 ㅠㅠ
예컨대 n=100, m=100으로 대입하면 우연히 정수값이 같기 때문에 캐싱에 의해 n과 m이 동일한 객체의 고유값을 지닌다고 나올 수 있습니다.
+)
제가 파이썬을 주로 오토핫키 같은 업무 자동화 용도로 사용하다보니 이런 부분은 평소에 깊이 생각하지 않고 책만 훑어보고 지나갔네요~!
이런 부분을 깊게 파고들면 너무 어려워서 프로그래밍 언어 책을 던져버리고 싶은 충동이 들던데 그래서 제가 프로그래밍을 할 줄 모르는 것 같네요 ^^
점프 투 파이썬과 SoloLearn 사이트에서 기초부터 차근차근 연습중입니다.
답변 감사합니다! 덕분에 잘 이해가 되었어요!
참고로 추후에 나오는 익명함수와 filter를 사용하면 아래와 같이 간결하게 작성하실 수 있습니다.
A = [20, 55, 67, 82, 45, 33, 90, 87, 100, 25] for item in filter(lambda x: x>=50, A): print(item)
아니면 list comprehension을 사용해도 비슷하게 사용이 가능합니다.
A = [20, 55, 67, 82, 45, 33, 90, 87, 100, 25] B = [x for x in A if x >= 50] for item in B: print(item)
앗 역시 파이썬에서 람다와 list comprehension을 사용하는지 여부는 하늘과 땅 차이네요~!
파이썬다운 정말 아름답고 간결한 스크립트이군요 ^^
이걸 보고 다시 제 스크립트를 보니 눈이 썩는 것 같네요 ㄷㄷ
for문을 사용하면 더 간결한 처리가 가능한데 제가 습관적으로 while문을 사용하는 버릇이 있네요 ㅠㅠ
항상 humit 님 덕분에 많이 배우고 갑니다!
감사합니다 :)
아무래도 C언어와 같이 절차 지향으로 코딩하시는 습관 때문에 습관적으로 루프를 변수로 만들어 사용하는 경우가 많더라고요..
물론 그 방식이 나쁘다는 건 아니지만 그래도 저렇게 코딩을 하면 어느 정도 아래와 같은 실수를 줄일 수 있습니다.
ex) 루프를 도는 변수를 증가시키는 것을 하지 않음, 증가시키는 변수를 잘못 설정
사실 저는 C언어도 제대로 다루지 못하는데 굉장히 부끄럽네요 ㅠㅠ
절차지향 vs 객체지향에 대해서는 이론적으로만 알고 있고,
C언어는 고등학교 수업에서만 배웠습니다 ㅜㅜ
(예전에 배웠던 do while문이 정말 오래간만에 떠오르네요)
굳이 핑계를 찾자면 오토핫키에 loop문과 while문이 있고,
파이썬의 for문에 해당하는 반복문이 없어서 그런 습관이 생긴 것 같기도 하네요 ^^;
앞으로는 파이썬의 for문이나 PHP의 foreach문을 보다 활용해야겠어요~!
그럼 날씨가 살짝 춥지만 humit 님께서도 좋은 주말 되세요!!
그래도 질문 자체가 while문을 공부하던 도중이라 while 문에 한정지어서 연습한거라 도움이 많이 되었어요.
아직 기초부터 차근차근 연습해가는 중입니다.
역시 전문가 레벨이 되면 더 다양하고 효율적인 방법이 존재하는군요!
코딩에는 스타일이 있다는게 이해가 됩니다.
감사합니다. 신세계네요!
저같은 영어무능력자가 구사하는 "Do you know Gangnam style?" 수준의 영어와
셰익스피어의 희곡의 주옥같은 문장이 수준 차이가 있듯이,
제가 발로 작성한 스크립트를 보다가 humit 님 같은 고수님들의 스크립트를 보면
뭔가 아름다운 영어 문장을 들은 것처럼 마음을 울리는 감동이 있네요 ^^
Ruby의 문법이 우아하다는 평을 듣지만 파이썬의 문법도 그에 못지 않게 아름답죠.
그리고 파이썬은 수렴하는 하나의 답이 있다는 철학이 굉장히 매력적인 것 같아요.
Perl에 대해 아주 조금밖에 모르지만 다양한 표현을 존중하는 Perl과 대비되는 특징이라고 하더군요.
사실 산양이 그려져 있는 Perl Cookbook을 구입해놓고 거의 읽지 못했습니다 ㅠㅠ
물론 잘 짜여진 PHP 스크립트를 보더라도 배우는 점이 많지만,
파이썬의 이러한 특징 때문에 고수님들의 스크립트를 보면 깨닫고 느끼는 바가 더 큰 것 같습니다.
이렇게 쓰다보니 제가 파이썬을 잘 다루는 것처럼 보이지만 "Do you know while?" 수준입니다 ^^;
아이들이 한글을 배울 시기에 글자가 하나 둘 보이기 시작하면 여기저기 글씨를 읽고 다니려고 합니다.
길거리 간판을 자꾸 읽으려고 하고 글자 모양만 보이면 쓰지는 못하지만 읽어보려고 하듯이 요즘 제가 그러네요.
파이썬 구조가 대충 보이기 시작하니 대충 뭘 하고자 하는지 해석이 되는데 아직은 창의적으로 만들지 못하는게 애석합니다. ㅋㅋ
그래도 고수들의 코딩을 보다보면 다양하게 응용하고 늘어나는 날이 생기겠죠?
고수님들이 작성하신 스크립트를 보면
그 명령어 하나하나를 명확히 파악하지 못해도 어렴풋이 숲이 보이는 그런 단계가 있죠.
제가 바로 그 단계여서 아무 생각없이 과감하게 ctrl+c, v를 합니다
구글링을 하다가 KLDP에서 다음과 같은 댓글을 찾았네요.
https://kldp.org/node/122745
"전에 다른 글타래에서 언급한 적도 있지만 말씀하신 바와 같이 프로그램이 돌아가는
기본 원리를 이해할 수 있도록 해 주는 언어로서의 C의 위치는 조금은 특별합니다.
그러나, 이와는 다르게 Perl이나 Python은 많은 부분이 추상화(OOP의 추상화가 아닙니다)된
언어로서 "어느 것을 먼저 배워야 하는 가?"라는 질문에 대해 보다 실용적인 관점에서
접근하는 것이 좋을 듯 싶습니다. 다시말해, 내 성격과 어떤 언어가 더 잘 맞는가?
내가 필요로 하는 기능이 어떤 언어에 더 잘 구현되어 있는가? 등 실용적 관점에서
보다 빨리 익힐 수 있는 언어를 먼저 선택하시고 후에 다른 언어를 공부하시는 것이
질문에 대한 한 가지 답이 되지 않을까 생각해 봅니다."
굉장히 제 마음에 와닿는 글인데 제 처지에 맞게 조금 의역하면
아주 사소하고 간단한 것이라도 제가 필요로 하는 기능을 스크립트로 작성해보면
비록 프로그래밍 언어가 어렵지만 보다 재미있고 빠르게 공부할 수 있는 것 같아요 ^^
그리고 파이썬은 그런 용도로 꽤 적절한 언어인 것 같구요.
오래 전에 고등학교 수업에서 C언어를 배우기는 했지만
그 때에는 너무 수험적(?)으로만 접근하고 실용적으로 사용하지 않아서 큰 흥미를 느끼지 못했던 것 같네요.
(사실 학교에서 시험 과목으로 공부하면 결코 재미있는 과목이 있을리가 없죠 ㅠㅠ)
당시에 영어 수업에서 저희 담임 선생님(영어)께서 성문종합영어에 빈 칸을 뚫어서 출제를 하셨기 때문에
C언어로 빈 칸을 뚫어서 문제화하는 프로그램을 작성하기는 했는데 하필 그 달에 학교를 자퇴했던 것 같네요 ㅠㅠ
(관사나 be 동사는 피해서 출제하고, 명사의 단수와 복수를 잘못 입력하면 조심하라고 경고를 띄우는 방식으로 작성했던 것 같네요)
엉뚱한 방향으로 댓글이 길어졌는데 마스터 님께서 이미 학습하신 내용이 결코 적지 않으니
(반복문은 모든 프로그래밍의 기본으로 알고 있습니다. 심지어 MS-DOS의 명령어 프롬프트도 반복문일거에요.)
problem solving의 차원에서 실용적으로 접근하시면 보다 재미있게 공부를 하실 것 같습니다!
다행이 for 문의 경우 shell 에서도 많이 쓰이는 명령어라 https://studyforus.com/share/168109 이 백업스크립트에도 DB 백업시 for문을 사용했기 때문에 그나마 조금 나았던 것 같습니다.
그리고 94년 C 언어를 처음 배울때 저도 수험식으로
"이럴땐 무조건 이걸 넣고~" 하는 식으로 배워서인지 머리에 남지도 않고 재미도 없었던 기억이 나는데 지금은 배우고 싶다는 갈망이 있어서 인지 재밌네요.
우선 pop() 메서드에 대해 말씀드리면 이 메서드는 리스트의 마지막 요소의 값을 반환하면서 그 요소를 삭제합니다.
그 결과 pop() 메서드가 실행될 때마다 리스트의 마지막 요소가 삭제됩니다.
이는 if문이나 print() 함수 내에 있더라도 마찬가지입니다.
while A:는 리스트의 요소가 존재하는 동안에는 bool 값이 true이니 계속 반복이 되구요.
따라서 처음에 작성하신 스크립트에서는 리스트 A의 뒤에서부터 삭제가 되는데
A(8) = 100 >= 50이므로 if문 안이 실행되는데 A(8)이 삭제되었으므로 print(A(7))이 출력되고(87)
A(6) = 90, A(3) = 82, A(1) = 55 또한 마찬가지로 33, 67, 20을 출력합니다.
반면 두 번째 작성하신 스크립트는 제2행의 b = A.pop()에서 리스트 A의 마지막 요소의 값을 변수 b에 대입하면서 그 요소를 삭제를 하고
if문에서 b의 값이 50 이상인지 확인하여 b의 값을 출력하기 때문에 때문에 정상적으로 출력이 되는 것입니다.
개인의 취향차이겠지만 저라면 리스트 A의 값을 모두 삭제해야 하는 경우가 아닌 일반적인 경우에는
굳이 pop() 함수를 사용하지 않고 다음과 같이 작성할 것 같네요 ^^
저도 직업적으로 파이썬을 하는 것이 아니기 때문에 이 스크립트 또한 업계의 표준과는 거리가 멀 수 있습니다 ㄷㄷ