본문 바로가기

노력/인공지능

7. 파이썬 개인공부 7 (객체)

OOP 


파이썬은 모든 것이 객체이다. -> 기본 패러다임이 객체지향


우리가 풀 문제가 간단하면 함수형, 객체형 패러다임 필요없다.


절차적으로도 가능.


하지만 실제 문제는 굉장히 복잡하다. 이럴 때 함수형, 객체형 패러다임이 필요하다.




공통된 특성을 객체로 만든다.


사용하기 위해 인스턴스화 한다.




함수, 클래스 선언:


함수 사용 : 함수 호출


클래스 사용 : 인스턴스화




인스턴스화 할 때 클래스 안의 __init__의 파라미터와 맞춰서 사용한다.



class Door:

    def __init__(self, number, status):

        self.number = number

        self.status = status

        

    def open(self):

        self.status = 'open'

        

    def close(self):

        self.status = 'closed'

        

self : 인스턴스 변수,


open과 close는 인스턴스 메소드이다.



객체지향의 장점 : 객체 안의 내용을 변경하면 객체가 모두 함께 변한다.





type(5) == 5.__class__ : 5의 타입이 뭔지, 5의 클래스 이름이 뭔지




a = 5


print(a.__class__.__bases__) : 이 인스턴스가 속한 클래스가 어떤 클래스들을 상속받아서 만들어졌는지... 부모 대 까지만 출력된다. 그 위는 출력안된다.

(<class 'object'>,) : 파이썬은 다중상속이며, 상속을 받는 순위가 있다.


튜플이라는 sequence형으로 썼기 때문



object.__bases__

() : 최상위 부모라는 뜻. 파이썬 객체의 시조이다. None.



print(type(int)) :

type이 나온다.



print(type(float)) : 

type이 나온다.



type에 클래스를 치면 type이 나오고, type에 인스턴스를 치면 클래스명이 나온다.



type(type) : type -> 클래스다.


클래스의 클래스 : 메타클래스.


callable : 함수냐 메소드냐, __init__냐 확인할 수 있는 것



function과 class를 똑같이 사용한다.



type(무언가 무언가) : type, function / method, class이름 -> 무언가 무언가가 무엇인지 알 수 있는 것.



dir(객체이름), vars(객체이름) -> 객체의 인스턴스 이름 == x.__dict__





Door를 만들면 heap 영역에 만들어진다. 인스턴스화 하는 순간 메모리에 올라가고 이름이 namespace로 가고 타입도 네임스페이스에 저장된다. 


파이썬은 모든 것이 객체이다. 인스턴스화를 자주쓰는 것에 대해서 리터럴로 만들어둔것뿐. 모두 결국 인스턴스화한 것이다.




syntatic sugar :  



class Door:

    def __init__(self, number, status):

        self.number = number

        self.status = status

    

    def __init__(self):

        print(a)

    

    def open(self):

        self.status = 'open'

        

    def close(self):

        self.status = 'closed'

        

오버로딩, __init__이 덮어써버린다. 기본적으로 덮어버린다. 나중의 __init__이 처음의 __init__을 덮어쓴다. 오버로딩을 지원하지 않는다.



오버라이딩 : 부모에게 물려받은 것을 덮어쓰는것. object의 __init__을 Door에서 재정의할 수 있다.



hex(), oct(), bin() : 각각 16진수, 8진수, 2진수로 변환해준다.



hex(id(door1)) : 값을 16진수로 변경한다. door1이 인스턴스화 되어 저장된 메모리를 알려준다.



==, is(id 값까지 비교한다)





class Door:

    colour = 'brown'


    def __init__(self, number, status):

        self.number = number

        self.status = status

        

    def open(self):

        self.status = 'open'

        

    def close(self):

        self.status = 'closed'

        

        

인스턴스 메소드 3개라고 봐야함...


door1 = Door(1, 'closed')

door2 = Door(2, 'closed')



Door.colour = 'white'

Door.colour

'white'


door1.colour

'white'


door2.colour

'white'



id를 쳐보면 세 개 모두 같은 곳을 가리킨다.


Door의 컬러를 변경하면 함께 선언받은 인스턴스들도 변경된다.


vars(클래스이름) : 클래스가 어디에 정의되어 있을 때, 연관된 값들을 다 보여주는 것.

mappingproxy({'__dict__': <attribute '__dict__' of 'Door' objects>,

              '__doc__': None,

              '__init__': <function __main__.Door.__init__>,

              '__module__': '__main__',

              '__weakref__': <attribute '__weakref__' of 'Door' objects>,

              'close': <function __main__.Door.close>,

              'colour': 'white',

              'open': <function __main__.Door.open>})

              

proxy는 대리인이라는 뜻임.


vars : 

1. vars 인스턴스가 나오면 인스턴스에 저장된 값들을 알려준다.

2. vars 클래스가 나오면 클래스에 저장된 값들을 알려준다.




try:

    door1.__dict__['colour']

except KeyError as e:

    print("Cannot find key {}".format(e))

Cannot find key 'colour'


dictionary 같은 경우 이렇게 예외처리 해도 되지만,


door1.__dict__.get('colour', 1)

1


이렇게 예외처리해도 된다.



Door.open(door1) : 내부적으로 __getattribute__()로 변경하여, 


door1.__class__.open(door1) 이렇게 변환해서 사용한다.



파이썬은 항상 다른 것으로 뭔가 바꿀 수 있다. 연산자도 바꿀 수 있고, Class.도 바꿀 수 있다.




파이썬의 철학이 딥러닝, 머신러닝과 매우 비슷하기 때문에 자주 쓰는 것이다.




먼저 get이 있는지 확인하고, getattribute를 부른다.



내부적인 구조!!!! : 까먹지 말자. Python_3_OOP..... 한번 다시 읽어야 한다.




Door.open : classmethod로 선언하거나 Door.open(Instance) 이런식으로 사용한다.



클래스메소드는 인스턴스가 사용가능하다.


나한테 없으면 부모한테서 찾는다. 인스턴스 메소드가 없으면 클래스 메소드를 찾는다.


관례상 인스턴스메소드는 첫번째 인자는 (self)를 넣고, 클래스 메소드는 첫번째 인자에 (cls)를 넣는다.


이것은 관례상 그런것이고 이름은 그냥 아무거나 써도된다. 아아아무거나 써도 다 된다.





우리는 파이썬을 도구적관점에서 사용한다. 파이썬을 모르면 고급에서 굉장히 어려워진다.








delegate:위임하다


class SecurityDoor(Door):

    colour = 'gray'

    locked = True

    

    def open(self):

        if self.locked:

            return

        Door.open(self)

        

    Door.open을 위임한다. 부모에게

    

delegation이라고 부른다. 이런현상을



여기에서는 Door.와 똑같은 의미가 super().라고 쓴다. 같은 의미다.



거의 같지만 다른 경우가 있다.



Door.처럼 쓰면 할아버지에게도 받을 수 있다. D.처럼 쓰면 된다. (예를들어서 Door는 D에게 상속받았따.)



하지만 족보꼬이고 틀릴 확률이 매우 높다. 그렇기 때문에 어지간한 상황에서는 super를 사용한다.


Composition:


class SecurityDoor:

    colour = 'gray'

    locked = True

    

    def __init__(self, number, status):

        self.door = Door(number, status)

        

    def open(self):

        if self.locked:

            return

        self.door.open()

        

    def close(self):

        self.door.close()

        

        

        

상속은 빚까지 상속받는다. 즉, 상속은 내가 필요없는 데이터까지 상속받게 된다. 내가 몇가지만 필요하다면, 몇가지만 위임시키는 방식이 Composition이다. 이 합성을 얼마나 잘 하는가가 디자인패턴의 강자로 만들어준다.


합성은 어렵다. 부모의 구조를 알아야 사용할 수 있다.