ABOUT ME

-

  • [python] 파이썬의 변수, 객체, 그리고 참조 주소
    코딩 연습/코딩배우기 2020. 9. 19. 19:49

     

    ■ 파이썬에서 모든 자료(type)는 객체이기 때문에 변수에 객체를 대입하면 특정 메모리 주소를 할당받게 되고, 그 변수를 다른 변수에 대입하면 같은 객체 주소를 참조하게 된다.

    ■ 파이썬의 기본 자료형 중 int, float와 수정불가(immutable)한 객체인 str, tuple 등은 그 변수의 대입(할당) 값을 수정하면 다른 주소를 참조하게 되어 같은 변수라고 볼 수 없지만, 수정가능(mutable)한 객체는 값을 수정해도 참조 주소를 유지한다.

    a = 10
    print(id(a))  # 140729182426208
    b = a
    print(id(b))  # 140729182426208
    print(a is b)  # True
    
    a = 20
    print(id(a))  # 140729182426528  --> 참조 주소 다름
    
    
    s = 'python'
    print(id(s))  # 1313064861120
    #s[0] = 'P'  # TypeError: 'str' object does not support item assignment
    s = s.replace('p', 'P')
    print(s)  # Python 
    print(id(s))  # 1313155574616  --> 참조 주소가 다름
    
    
    lst_a = [1, 2, 3, 4]
    lst_b = lst_a
    print(id(lst_a))  # 1313157490696
    print(lst_a is lst_b)  # True
    
    lst_a[0] = 10
    print(lst_a, lst_b)  # [10, 2, 3, 4] [10, 2, 3, 4]
    print(id(lst_a))  # 1313157490696  --> 내용 수정되었지만, 참조 주소 같음
    print(lst_a is lst_b)  # True
    

    good4me.co.kr

     

    ■ 함수에 의한 객체(리스트) 값의 수정 여부와 수정 안되게 하는 방법

    def mutable_a(l1):
        l1.append(9)
        print(l1)
    
    lst = [1, 3, 5, 7]
    mutable_a(lst)  # [1, 3, 5, 7, 9]
    print(lst)  # [1, 3, 5, 7, 9]  --> 원본 수정됨
    
    
    def mutable_b(l1):
        l2 = l1
        l2.append(9)
        print(l2)
    
    lst2 = [1, 3, 5, 7]
    mutable_b(lst2)  # [1, 3, 5, 7, 9]
    print(lst2)  # [1, 3, 5, 7, 9]  --> 원본 수정됨
    
    
    
    def mutable_c(l1):
        l2 = l1[:]  # 리스트 슬라이싱으로 객체 대입
        l2.append(9)
        print(l2)
    
    lst3 = [1, 3, 5, 7]
    mutable_c(lst3)  # [1, 3, 5, 7, 9]
    print(lst3)  # [1, 3, 5, 7]  --> 원본 수정 안됨
    
    
    import copy
    
    def mutable_d(l1):
        l2 = copy.copy(l1)  # copy 함수 이용
        l2.append(9)
        print(l2)
    
    lst4 = [1, 3, 5, 7]
    mutable_d(lst4)  # [1, 3, 5, 7, 9]
    print(lst4)  # [1, 3, 5, 7]  --> 원본 수정 안됨
    

     

    ■ 얕은 복사 copy.copy(), 깊은 복사 copy.deepcopy() 알아보기

    lst5 = ['outer', ['inner']]
    
    cp = copy.copy(lst5)
    dcp = copy.deepcopy(lst5)
    
    print('lst5 :', lst5)
    print('  cp :', cp)
    print(' dcp :', dcp)
    
    print('\n복사 결과')
    print(id(lst5), id(lst5[0]), id(lst5[1]))
    print(id(cp), id(cp[0]), id(cp[1]))
    print(id(dcp), id(dcp[0]), id(dcp[1]))
    # copy, deepcopy 모두 리스트 값을 복사하였으나(참조 주소 다름)
    # copy()의 경우 outer, [inner] 모두 참조 주소가 같은 반면,
    # deepccopy()의 경우 outer는 같으나 [inner]는 참조 주소가 다른 것을 볼 수 있다.
    
    lst5.append('add_outer')
    
    print('\n리스트에 값 추가 결과')
    print('lst5 :', lst5)
    print('  cp :', cp)
    print(' dcp :', dcp)
    # lst5에만 추가됨
    
    lst5[1].append('add_inner')
    
    print('\n내부 리스트에 값 추가 결과')
    print('lst5 :', lst5)
    print('  cp :', cp)
    print(' dcp :', dcp)
    # lst5, cp 두 개에 추가됨 (deepcopy는 영향 없음)
    
    print('\n값 추가 후 참조 주소 변화 없음(mutable 객체(리스트)')
    print(id(lst5), id(lst5[0]), id(lst5[1]))
    print(id(cp), id(cp[0]), id(cp[1]))
    print(id(dcp), id(dcp[0]), id(dcp[1]))
    
    
    
    [실행 결과]
    
    lst5 : ['outer', ['inner']]
      cp : ['outer', ['inner']]
     dcp : ['outer', ['inner']]
    
    복사 결과
    1313157491400 1313065028272 1313157639816
    1313157492424 1313065028272 1313157639816
    1313157636488 1313065028272 1313157525320
    
    리스트에 값 추가 결과
    lst5 : ['outer', ['inner'], 'add_outer']
      cp : ['outer', ['inner']]
     dcp : ['outer', ['inner']]
    
    내부 리스트에 값 추가 결과
    lst5 : ['outer', ['inner', 'add_inner'], 'add_outer']
      cp : ['outer', ['inner', 'add_inner']]
     dcp : ['outer', ['inner']]
    
    값 추가 후 참조 주소 변화 없음(mutable 객체(리스트)
    1313157491400 1313065028272 1313157639816
    1313157492424 1313065028272 1313157639816
    1313157636488 1313065028272 1313157525320
    

     

    Life is Short, Use Python.

     

Designed by goodthings4me.