python basic

들어가는 말

오늘은 인공지능 일반과 파이썬 수업에서 배운 흥미로운 기초 파이썬을 적어보겠습니다.
정말 별 거 없지만 그래도 수업 시간에 배울 때 C언어랑 다른 게 특히 더 느껴져서 흥미로웠던 부분에 대해서 말해보겠습니다... ㅎㅎ
C언어를 배울 때는 이렇게 막 신기하고 흥미로운 것들이 없었는데 파이썬은 재밌는게 많고 간단해서 좋은 것 같습니다.

리스트 복사

###코드 1

a = [1,2,3]
b = a

print("a =",a)
print("b =",b)

b[1] = 4

print("a =",a)
print("b =",b)

print(id(a), id(b))

실행 결과 1

a = [1, 2, 3]
b = [1, 2, 3]
a = [1, 4, 3]
b = [1, 4, 3]
2365055935488 2365055935488

파이썬에서 리스트a를 선언하고 같은 값을 넣고 싶어서 b = a를 하면 b에는 어떤 값이 들어가게될까요?
위의 코드에서 b의 리스트 값 중 하나를 바꾸고 프린트 해보면 a도 바뀌는 것을 확인할 수 있습니다.
마지막 줄에 주소값이 같은 것으로 인해 b는 리스트의 값만을 복사하는 것이 아닌 a의 리스트 주소값을 복사했다는 것을 알 수 있습니다.
이렇게 가변 객체를 복사 했을 때 주소값 만을 복사해서 참조하는 메모리가 달라지지 않아 복사된 변수의 값을 수정하면 복사한 변수의 값도 수정되는 상태의 복사를 얕은 복사라고 합니다.

그럼 값 자체를 복사하는 방법은 뭐가 있을까요?

코드 2

a = [1,2,3]
b = a
c = a[:]

b[1] = 4

print(b)
print(a)
print(c)

print(id(a), id(b), id(c))

실행 결과 2

[1, 4, 3]
[1, 4, 3]
[1, 2, 3]
2829775430016 2829775430016 2829775578112

위의 코드에서 [:]를 사용해 복사한 c는 같은 주소를 가르키지 않는다는 것을 알 수 있습니다.
하지만 [:]슬라이싱을 사용한 복사도 완전한 얕은 복사가 아닙니다.

코드 3-1

a = [3,4, [1,2]]
b = a
c = a [:]

b[0]=7
b[2][0] = 8

print(a)
print(b)
print(c)
print(id(a), id(b), id(c))

실행 결과 3-1

[7, 4, [8, 2]]
[7, 4, [8, 2]]
[3, 4, [8, 2]]
1700737046656 1700737046656 1700735639936

위의 코드에서의a는 리스트 안에 리스트가 또 들어있는 2차원 리스트 입니다.
a[:]슬라이싱을 사용해 복사하면 주소값은 다르지만 리스트 내부 리스트의 값을 바꾸면 같이 바뀌어 버립니다.

코드 3-2

print(id(a[2]), id(b[2]), id(c[2]))

실행 결과 3-2

2217715731264 2217715731264 2217715731264

당연히 그 이유는 세 변수 리스트 내부 리스트가 모두 같은 주소값을 참조하고 있기 때문입니다.
[:]를 이용한 복사도 리스트 내부의 리스트 값까지 전부 완전히 독립된 메모리로 복사하지는 않기 때문에 얕은 복사인 것입니다.
그러면 완전히 독립적인 메모리를 참조하는 복사인 깊은 복사를 하는 방법은 무엇이 있을까요?
copy 모듈의 deepcopy 함수를 사용하면 됩니다.

코드 4

import copy

a = [3,4, [1,2]]
b = a [:]
c = copy.deepcopy(a)

b[0]=7
b[2][0] = 8

print(a)
print(b)
print(c)
print(id(a), id(b), id(c))
print(id(a[2]), id(b[2]), id(c[2]))

실행 결과 4

[3, 4, [8, 2]]
[7, 4, [8, 2]]
[3, 4, [1, 2]]
1402826255552 1402826256256 1402825857152
1402824729600 1402824729600 1402828350336

위의 코드와 실행 결과를 보면 copy.deepcopy() 함수를 사용하여 복사된 두 객체는 완전히 독립적인 메모리를 차지합니다.
deepcopy 함수를 사용한 복사는 완전한 깊은 복사를 할 수 있습니다! 이렇게 깊은 복사를 사용하면 원본의 값을 바꾸더라도 복사한 객체의 값은 바뀌지 않아야 하는 경우에 유용하게 사용할 수 있습니다.

이렇게 대입을 하면 같은 주소값을 참조하는 이유는 파이썬이 값 기반인 C언어랑 다르게 참조 기반의 객체 관리 시스템을 가지고 있기 때문입니다.
이렇게 참조를 기반으로 하는 파이써느이 객체는 C언어에서의 배열과 포인터와 비슷한 기능을 가지고 있습니다.
리스트의 복사를 공부하고 변수가 기본적으로 값을 직접 저장하는 C언어와 참조를 기반으로 객체를 관리하는 파이썬의 차이가 느껴져서 흥미로웠습니다.

특수변수 __name__과 메인 스크립트와 모듈 실행 구분

코드 1

#t1.py

print(__name__)
print("1-5")
#p20250904.py

import t1
#__name__: 글로벌 변수 / 파일의 실행위치
print(__name__)

실행 결과 1

t1
1-5
__main__

위 코드는 import를 이용해 파일 자체를 실행 시키는 것이 main 함수를 실행 시키며 파일을 실행 시킬 일이 없는 C언어와의 차이가 잘 느껴져 흥미로웠습니다.
main 함수가 엔트리 포인트인 C언어와 달리 파일 전체가 실행되는 파이썬이 신기하고 흥미로웠다.

코드 2

#t1.py

if __name__=='__main__':
    print(__name__)
    print("1-5")
#p20250904.py

import t1
#__name__: 글로벌 변수 / 파일의 실행위치
print(__name__)

실행 결과 2

__main__

파이썬을 더 열심히 배워서 생각하는 것들을 다 만들어 보고싶다!