카테고리 없음

[패캠 네카라쿠배 2기] 2차 테스트 - 5일차. Reference

닉네임이 멋이 중헌디 2021. 6. 18. 20:14

Object Reference

1. reference

파이썬 참조 심화 // 실수할 수 있는 부분이나 중급 이상 문법 

1)파이썬 객체 참조 다양한 특징 

2)Copy 

3)Deep copy - 깊은 복사 

4)매개변수 전달 주의할 점 

 

# Chapter05-1

# 파이썬 심화

# 객체 참조 중요한 특징들

# Python Object Referrence

 

print('EX1-1 -')

print(dir()) #dir 함수를 바로 쓰면 이 05_01 파일에 대해 나올 수 있다

# __name__으로 실행




# id vs __eq__ (==) 증명

x = {'name''kim''age'33'city''Seoul'}

y = x

 

print('EX2-1 -'id(x), id(y)) #두 변수의 id가 같다/ 다른 변수로 하나의 주소 (얕은 복사) - 같은 객체,x의 주소를 복사한다

print('EX2-2 -'x == y#값이 같은지 - true / / 객체가 복사되었고 여러가지 변수가 하나를 보고 있는 것(즉 별개의 객체가 아니다!)

print('EX2-3 -'x is y#id값이 같은 객체를 보고 있는지- true

print('EX2-4 -'xy#같은 값이 출력이 된다

 

x['class'] = 10 #class:10을 딕셔너리에 넣으면

print('EX2-5 -'xy#둘다 위에 추가된 값이 들어간다

 

print()

print()

 

z = {'name''kim''age'33'city''Seoul''class'10}

 

print('EX2-6 -'xz# 값만 같은 다른 객체

print('EX2-7 -'x is z# 같은 객체 아님 - false

print('EX2-8 -'x is not z#true

print('EX2-9 -'x == z# 값이 같다 - true (값은 같지만 같은 객체는 아니다)

 

# 객체 생성 후 완전 불변 -> 즉, id는 객체 주소(정체성)비교, ==(__eq__) 는 값 비교

#즉 z는 x와 id가 다르지만 ==는 맞다(magic method로 __eq__)

#그러므로 is로 id값이 같은지를 확인하는 것이 훨씬 정확 

 

print()

print()

 

# 튜플 불변형의 비교

tuple1 = (1015, [1001000])

tuple2 = (1015, [1001000])

 

print('EX3-1 -'id(tuple1), id(tuple2)) #다른 객체. 값은 같지만 다른 주소

print('EX3-2 -'tuple1 is tuple2# false

print('EX3-3 -'tuple1 == tuple2# true

print('EX3-4 -'tuple1.__eq__(tuple2)) #위와 같은 말(매직 메서드)

 

print()

print()

 

# Copy, Deepcopy( 얕은 복사,깊은 복사)

 

# Copy(얕은 복사: x= y 같은 형식)

tl1 = [10, [100105], (51015)]

tl2 = tl1

tl3 = list(tl1)

 

print('EX4-1 -'tl1 == tl2#값은 같다

print('EX4-2 -'tl1 is tl2#id값도 같다

print('EX4-3 -'tl1 == tl3#값은 같다

print('EX4-4 -'tl1 is tl3#false - 타입형의 생성자를 이용해서 새롭게 만들면 다른 주소를 가지게 된다

 

# 증명

tl1.append(1000)

tl1[1].remove(105)

 

print('EX4-5 -'tl1#변경 

print('EX4-6 -'tl2#변경 

print('EX4-7 -'tl3#변경되지 않는다(다른 객체니까)

 

print()

 

# print(id(tl1[2])) #튜플에 원소를 추가하기 전 - id주소가 아래 추가후와 다르다 

tl1[1] += [110120]

tl1[2] += (110120)

 

print('EX4-8 -'tl1)

print('EX4-9 -'tl2# 튜플 재 할당(객체 새로 생성)// 튜플은 불변 그러므로 원래의 튜플과 다른 id값을 가진 새 튜플이 생긴 것 

print('EX4-10 -'tl3)

# print(id(tl1[2])) #튜플에 원소 추가 후 - 다른 객체가 되어서 id주소가 달라진다

#즉 리스트 안에 튜플은 위험성이 있다(수정되면 다른 객체가 되니까)

print()

print()

 

#얕은 복사: 값이 같고 x=y했으면 id 주소도 같다. 즉, 수정시 함께 수정된다.  x, y각각 같은 값을 지정해주었으면 당연히 id가 다르다(다른 객체)

# Deep Copy

 

# 장바구니 // 인터넷 쇼핑 장바구니- copy, deep copy를 혼동하면 큰 문제가 생긴다

 

class Basket:

    def __init__(selfproducts=None): #아무것도 넣지 않았으면 기본값 None

        if products is None

            self._products = [] #아무것도 안 들어있으면 리스트 선언

        else:

            self._products = list(products#안에 뭐가 있으면 product라는 변수를 가지고 또 다른 list를 생성(값은 같은 다른 객체)/초기화 

                                            #원본이 수정되지 않도록 새로운 리스트 생성

 

    def put_prod(selfprod_name): #장바구니에 담기

        self._products.append(prod_name)

 

    def del_prod(selfprod_name): #장바구니에서 빼기

        self._products.remove(prod_name)



import copy #원본이 수정되지 않도록 (객체 복사 시)해주는 패키지

 

basket1 = Basket(['Apple''Bag''TV''Snack''Water'])

basket2 = copy.copy(basket1# copy패키지의 copy 메서드를 호출해서 basket1을 복사

basket3 = copy.deepcopy(basket1#copy패키지의 deepcopy 메서드로 복사

 

print('EX5-1 -'id(basket1), id(basket2), id(basket3)) #각각의 id값 확인 : 다 다르다 (객체를 copy매서드, deepcopy메서드를 쓰든 모두 id가 다르다)

print('EX5-2 -'id(basket1._products), id(basket2._products), id(basket3._products)) #바구니로 접근하기 위해서는 인스턴스 변수로 접근 (클래스 Basket을 이용해서 만든 인스턴스들 안에 있는 인스턴스 변수를 copy했으니까)

# copy로 하면 _products는 모두 같음 [얕은 복사] : 인스턴스 (basket1, 2)와 안에 있는 product도 같은 주소// 표면적인 객체, 안에 있는 리스트 모두 복사 - 그러므로 원본을 수정하면 2도 수정이 된다 (문제가 있다)

# deepcopy는 _products(인스턴스 변수에 할당된 id reference주소까지 깊게 쫓아가서 다른 주소로 복사를 한다 : 안에까지 다른)

print()

 

basket1.put_prod('Orange')

basket2.del_prod('Snack')

 

print('EX5-3 -'basket1._products#Orange추가, Snack 삭제 (그러므로 원본이 아니어도 같은 객체를 참조하고 있기 때문에 어느쪽에서 변경하든 원본, 복제본 모두 변화 수용)

print('EX5-4 -'basket2._products#Orange추가, Snack삭제

print('EX5-5 -'basket3._products#아무런 변경 없음

#즉 deepcopy가 가장 안전(포함 변수까지 복사해서 새로운 객체에 할당)

#copy는 바로 접근 가능한 데이터 타입만 복사

print()

print()

 

# 함수 매개변수 전달 사용법

 

def mul(xy):   #함수: x와 y를 더해서 다시 x에 할당// 매개변수 x,y

    x += y

    return x

 

x = 10

y = 5

# 정수일 때는 문제 없음

print('EX6-1 -'mul(xy), xy)

print()

 

a = [10100]

b = [510]

 

print('EX6-2 -'mul(ab), ab#[10,100,5,10] [10,100,5,10] [5,10]

# a가 가변형 원본 데이터 변경// 왜냐? a의 주소를 매개변수로 같이 보내게 되어서 수정되는 값이 반영된다 

 

c = (10100)

d = (510)

 

print('EX6-2 -'mul(cd), cd)   #(10,100,5,10) (10,100) (5,10)

# 불변형 c -> 원본 데이터 변경 안됨// 튜플은 불변이지만 합해서 아예 새로운 튜플이 됨, 불변형이라 매개변수로 주소가 넘어가도 변하지 않음



# 파이썬 불변형 예외

# str, bytes, frozenset, Tuple : 사본 생성 X -> 참조 반환

#복사해서 원본 주소를 공유해도 어차피 원본 변경이 일어나지 않으니까

# 위의 불변형들은 그냥 할당해서 써도 좋음. 

 

tt1 = (12345)

tt2 = tuple(tt1# 생성자를 사용해서 할당 - 복사가 된다

tt3 = tt1[:] # 슬라이싱을 통해 복사 

 

print('EX7-1 -'tt1 is tt2id(tt1), id(tt2)) #tuple로 직접 생성해서 할당을 했는데도 다른 객체처럼 주소가 달리 나오지 않음. 어차피 불변이라 파이썬이 효율적으로 사용하기 위해 같은 주소로 참조

print('EX7-2 -'tt3 is tt1id(tt3), id(tt1)) #마찬가지로 같은 id. 같은 객체. 어떻게 복사를 하든 하나의 id주소로 통일. 

 

tt4 = (1020304050)

tt5 = (1020304050

ss1 = 'Apple'

ss2 = 'Apple'

 

print('EX7-3 -'tt4 is tt5tt4 == tt5id(tt4), id(tt5)) #위의 tuple()처럼 같은 값을 가진 새로운 객체를 만드는 것 같지만 튜플은 불변형, 다 같은 id, 객체로 취급

print('EX7-4 -'ss1 is ss2ss1 == ss2id(ss1), id(ss2)) #string도 마찬가지

#효율성을 위해 같은 값을 가진 불변형들은 하나로 본다 (컴퓨터가 보기에는 수정 가능성도 없으니까 하나로 본다

# Deep Copy는 안에 있는 변수까지 다 새롭게 복사해서 만드니까 시간이 더 오래 걸릴 수 있다