Class / super / 상속 / 오버라이드 / operator / classmethod / staticmethod / property / private

markyang92·2021년 4월 23일
0

python

목록 보기
17/42
post-thumbnail
post-custom-banner

Class

class Car():
    def __init__(self, company, details):
        self.company=company
        self.details=details


# car1 instance 생성
car1=Car('Hyundai', 300)
print(car1)

# ==== 출력 ==== #
<__main__.Car object at 0x위치>

Class

Class Variable

  • Class 변수: Class계의 전역 변수
  1. 클래스 멤버는 외부에서 클래스멤버를 바꿀 수 있다.
  • Dog class 에 영향 줄 수 있다.
  1. 아래와 같을 때, Car의 인스턴스들이 공통으로 가지는 것이 Class 변수 !!
    2.1 Car.car_cnt, car1.car_cnt두 방법 모두 사용해서 접근할 수 있다.

classmethod

  1. Class 변수를 건드리는
  2. Class 기반으로 생성된 객체가 공통으로 가지는
    = Class Method

staticmethod

  • Class, instance 다 쓸 수 있는 애.매.한 메소드
class Car:
    def __init__(self, car_name):
        self._car_name=car_name
        
    # Static Method
    @staticmethod
    def is_bmw(inst):
        if inst._car_name == 'Bmw':
            return 'Ok! This car is {}'.format(inst._car_name)
            
car1=Car('Bmw')
print(Car.is_bmw(car1))

# ===== 출력 ===== #
Ok! This car is Bmw

instance

instance variable

private

  • private 할 함수, 변수__ 를 PREFIX로 선언
  • 주의! private 멤버는 초기화하지 않으면, Error!
  • Class Hello를 상속 했을 때에도, 감추어져있다.

@property,getter,setter를 사용하여 접근만 할 수 있게 하자!

  • 위의 private는 너무 엄격하다.
  • 접근(Read-only)로 하고 write권한은 주지 말게하자!!!!!
  • @property

현재까지의 한계


setter의 사용


protected

  • protected 할 함수, 변수_<Class Name> + __ 를 PREFIX로 선언

instance method

class Student:
    def __init__(self, name):
        self._name=name
    
    def whatIsMyName(self): # self
        print(self._name)
        

magic method(special method)

  • Class 내에서, 정의할 수 있는 Built-in 메소드

__dict__ : 네임스페이스 확인


dir(obj) : 네임스페이스의 key값 확인


  • dir(obj) 해보면, obj class의 built-in method를 볼 수 있다.
num=8
print( dir(num) )


# ===== 출력 ===== #

['__abs__', '__add__', '__and__', '__bool__', \
'__ceil__', '__class__', '__delattr__', '__dir__', \
'__divmod__', '__doc__', '__eq__', '__float__', '__floor__', \
'__floordiv__', '__format__', '__ge__', '__getattribute__', \
'__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', \
'__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', \
'__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', \
'__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', \
'__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', \
'__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', \
'__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', \
'__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', \
'__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', \
'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']


# =============================================================================== #

a = 1000
class A():
    def __init__(self):
        pass
    def __cal__(self,y):
        global a
        a = a /y
        return a

print(dir(A))

# ===== 출력 ===== #
['__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', \
'__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', \
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', \
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', \
'__sizeof__', '__str__', '__subclasshook__', '__weakref__' ]

  • 즉, 사실 num<class 'int'>의 인스턴스 이고, int클래스의 magic method__add__()가 있는 것!

이를 활용한, 매직메소드 override!

  • Class의 instance1 + instance2 를 할 때, 그냥 더하면.. 당연히 안되겠으나.. 매직메서드(__add__)를 오버라이드해서 사용해보자.

__str__(self)

  • 그냥 print( )에서 object를 찍으면, object의 위치 주소가 나오기 때문에, 불편할 수도 있다.
    이럴때, __str__(self) 메소드를 사용하자.
    • __str__print( object )를 했을 때, return 값을 STDOUT으로 표시한다.
    • 사용자 레벨에서 print 출력은, __str__ 을 사용한다.

__repr__(self)

  • 개발자 레벨에서, object의 여러 속성을 보고 싶으면, __repr__을 사용해야한다.
  • __str__처럼 print( ) 를 사용했을 때, 어떠한 값을 보여 줄지 결정한다.
    1. return str 형식 이면, STDOUT 으로 str을 출력
    2. return repr( ) 로 튜플을 STDOUT으로 출력할 수 있다.

__call__

  • 인스턴스가 따로 메서드 실행 지정을 하지 않아도 아규먼트를 넣으면 메서드를 실행하게 해줌


__init__, __del__

class Dog:
    def __init__(self):
    	# constructor = 생성자
        생성하면서 할 행동
    def __del__(self):
    	# destructor = 소멸자
        소멸할 때 할 행동

instance 지우기: del

  • list[idx]도 그렇고 list도 그렇고 객체도 del 객체 하면 파괴됨

obj.__dict__

  • Instance내 Namespace의 MemberValueobj.__dict__에서 dictionary형태로 관리된다.
  • Class의 self.company, self.details는 아래처럼 dictionary 형태로 관리된다.

obj.__slots__: Member를 제한함. 메모리 사용량 감소


obj.__doc__

  • object 내 주석 설명을 출력한다.

obj.__name__, obj.__code__, obj.__file__


line 번호 찍기

import inspect

def line_no():
    return inspect.getlineno(inspect.getouterframes(inspect.currentframe())[-1][0])

if __name__ == '__main__':
    print(line_no())

상속

자식에 생성자가 없는 경우

  • 자동으로 부모 생성자 activation

자식 생성자 X, 부모 생성자가 argument 요구


자식에 생성자가 있는 경우

  • 자식클래스의 생성자 activation
  • 하지만 이경우.. Error의 가능성이 있다.

자식에 생성자가 있는데 Error

  • 자식클래스의 생성자 activation 되어 부모 생성자deactivate!!! 부모의 일부만 activate되지 않음!!

자식생성자 in 부모생성자

  • 자식클래스의 생성자에서 부모 생성자 activation

  • 자식클래스에서 부모 생성자를 쓰지 않으면, 상속 받은 메서드 Error 생길 수 있음

  • 자식클래스에서 부모 생성자를 사용해 부모 객체Activation!

  • 자식클래스에서 부모 생성자를 사용해 부모 객체Activation! + 자식클래스에서 일부 덮어쓰기 가능

super()

  • super() 를 사용하면, 상속 원본 메서드을 사용 가능
    • super().메서드()

  • super() 를 이용한 부.모.클.래.스생성자 Activate

다중상속

  • MRO를 사용하여, 다중상속관계를 살펴볼 수 있다.
    • <ClassName>.mro() 로 확인가능

  • ClassC.mro(): [<class '__main__.ClassC'>, <class '__main__.ClassA'>, <class '__main__.ClassB'>, <class 'object'>]

다중상속에서 super()

  • 위 예제를 보면, 다시 mro가 ClassC.mro(): [<class '__main__.ClassC'>, <class '__main__.ClassA'>, <class '__main__.ClassB'>, <class 'object'>]이다.
  • super( '타입', 객체 ).메서드()
    • '타입' +1 번째의 메서드() 사용

Descriptor

  • Descriptor: __get__(self), __set__(self), __delete__(self) 중 하나라도 사용하는 'Class'
    • 특징: Descriptor Type의 '클래스 속성'(static field) 접근 시, __get__, __set__ 메서드가 자동 호출

__get__

  1. n2=Sample.y (Sample Class의 클래스 인스턴스(static field)) 접근
  2. Sample.y는 Descriptor type인 클래스(__get__, __set__)임
  3. 이는 __get__ 혹은 __set__을 호출 (원래 그럼)
  4. 이런 Descriptor는 3개의 argument를 요구함
    -> __get__(self): argument가 1개임 -> Error!

  • __get__에 args 3개를 만들어보자.

operator 모듈: idx, 멤버 이름 접근

1. operator 모듈 사용

  • from operator import itemgetter, attrgetter 로 class의 멤버를 기준으로 sort 가능
    • itemgetter: 소트 기준 키 값을 idx로 선정
    • attrgetter: 소트 기준 키 값을 '멤버 이름'으로 지정해 선정
from operator import itemgetter, attrgetter

class Word:
    def __init__(self, name):
        self.name=name
        self.len=len(self.name)
    def __repr__(self):
        return repr((self.word))

if __name__ == '__main__':
    word_list=list()
    list.append(Word('단어'))
    
    word_list=sorted(word_list, key=attrgetter('len')) # len 기준으로 sort
    
    for i in range(0, len(word_list)):
        print(word_list[i].name)

abstract class

  • abstract class: 추상 클래스
    • 메서드의 목록만 가진 클래스
    • 상속받는 클래스에서 메서드 구현을 강제하기 위해 사용

  1. abc 모듈 (abstract base class)
  • import abc
  • from abc import *
  • from abc import ABCMeta, abstractmethod

  • 파생클래스(상속 받는 클래스)는 부모의 abstracemothod를 전부 구현해야됨
    • 미 구현시 Error
  • 추상클래스instance로 만들 수 없다.
    • 오로지 상속용으로만 사용함

overload


상속, override

  • 재재 상속해 override해보자.
profile
pllpokko@alumni.kaist.ac.kr
post-custom-banner

0개의 댓글