고려대학교 지능정보 SW 아카데미 4기/정리노트

프로그래밍 심화 (5) - Python Class 클래스

2realzoo 2024. 3. 11. 19:51

Function

  • encapsulation 캡슐화

Class

  • 캡슐화를 해도 기본 접근 제한 없음 -> descriptor

Class 기본 용어

attribute : class 내부 모든 것
method : 클래스 안의 함수
class variable : 클래스 내의 변수
instance variable : 인스턴스 내의 변수
instance or object : class가 생성한 구체적인 값

class 작성

class A:
  x = 1
  def xx(self, t):
    print(self, t)

Type과 Class의 관계

a = 1 #Literal
a = int(1) #객체지향 기본 방식

int도 class이지만 c의 영향을 받아 대문자가 아닌 소문자로 작성되어 있다.
다른 type도 마찬가지이다.

Class 변수

class A:
  x = 1 #Class variable

Instance 변수

(1) class 생성 후 변수 정의

#instance variable
a1.t = 3 
a2.t = 4
a3.t = 'a' 

(2) class 내부에서 self에 변수 정의

class B:
  def bb(self):
    self.t = 1

b = B()

vars(b) #{}

b.bb()

vars(b) #{'t' : 1}

이때 instance 변수는 method가 실행 후 생성된다.
method가 실행된 모든 instance에 생성된다.

Class 변수와 Instance 변수의 차이

class A:
  x = 1 #Class variable

a1 = A()
a2 = A()
a3 = A()

#instance variable
a1.t = 3 
a2.t = 4
a3.t = 'a' 

a1.x #1
a2.x #1
a3.x #1

vars(a1) {}

위 예제를 보면 class A의 instance a1, a2, a3는 모두 class 변수 x에 접근이 가능하다.
class 변수는 생성한 모든 instance에서 접근이 가능하다.
vars로 살펴보았을 때 인스턴스 a1에는 어떠한 변수도 정의되지 않은 것을 확인할 수 있다.

그렇다면 인스턴스에 같은 이름의 변수를 정의할 경우엔 어떻게 될까?

a3.x = 3

vars(a3) #{'x': 3}

a3 #3
a1 #1

인스턴스 local내에 같은 이름의 변수가 정의된 것을 확인할 수 있다.
따라서 a3.x는 local에 있는 변수의 값이 된다.
다른 인스턴스의 경우 global 값인 class 변수의 값이다.

init

__init__
정의
: __new__()에 의해 인스턴스가 만들어진 후에, 호출자에게 돌려주기 전에 호출된다. 인스턴스를 커스터마이즈(초기화)한다.

class C:
  def __init__(self):
      self.t = 1

c = C()
vars(c) #{'t': 1}

metaclass : class 역시 metaclass의 instance이다.따라서 instance화 하지 않고 class 자체로 사용이 가능하다.

class X:
  def t(self, x):
    self.x = x
  def tt(self):
    print(self.x)

 X.t() #error
 X.t(1) #error
 X.t(1,1) #error

self

self : instance를 가리키며, javascript에서의 this와 일맥상통한다.

class X:
  def t(self, x):
    self.x = x
  def tt(self):
    print(self.x)

#self 개념
a = X()
X.t(a, 3)

a.t #<function>
#self -> 공유하기 위해 생성되어 있음 (instance, class)
#a.t(a,3) -> a 중복되니 간편한 구문 위해 생략 -> error

###call
() 연산자의 세가지 사용

  1. func() => 함수실행
  2. class() => 인스턴스화
  3. instance() => call 정의된 class로 생성된 instance
class T:
  def __init__(self):
    self.a = 1
    print('init')

t = T() #init

t() #callableerror

__call__ 정의하지 않은 class의 instance는 callable하지 않다.

class T:
  def __init__(self):
    self.a = 1
    print('init')
  def __call__(self):
    print('call')

tt = T() #init
tt() #call

T()() #init call

class도 함수처럼 사용 가능하다.
tensorflow에서는 __call__ 대신 call 사용
delegator 사용하여 call 로 바꿈

질문 (1) instance 변수로 call 정의해도 class변수처럼 작동할까?

namespace

def sin(self):
  print('sin')
  #다른 함수랑 이름이 겹쳐서 오버라이딩 될 수 있음

class Math:
  def sin(self):
    print('sin')
  def cos(self):
    print('cos')
    #namespace로 사용
    #instance로도 사용할 수 있는 문제 생김

scope 개념을 사용해서 namspace 생성한다.

Static method, 정적 메서드

: 함수이지만 클래스의 네임스페이스만 차용한 것. 인스턴스, self 없음.

(1) 기본 문법

class T:
  @staticmethod
  def ss():
    print('static')

T.ss() #static

첫번째 인자로 self가 들어가지 않았다.

(2) @staticmethod를 쓰지 않았을 때

class T2:
  def ss():
    print('static')

T2.ss() #static

t = T2()
t.ss() # self가 없어서 사용 불가
#Typeerror: T2.ss() missing 1 required positional argument: 'a'

@classmethod

class Y:
  @classmethod
  def z(cls):#self 대신 cls사용
    cls.x = 1
    print('cls')

Y.z() #cls

#instance 생성
yy = Y()
yy.z() #cls
yy.x #1
vars(yy) #{}
#LEGB , instance에 없는 method는 class에서 가져다 사용

self 대신 cls 사용한다.
@ => decorator

Single dispatch

하나의 메서드에서 arg의 타입에 따라 다른 행동을 보일 수 있다.

사용 방법

len({'a':1}) #1
#type에 따라 다르게 행동하지만 같은 함수 또는 메서드이다.
#list, dict 다른 결과
# => generic function

from functools import singledispatch
@singledispatch #arg가 한개라 single dispatch, 두개 이상은 multiple dispatch
def x(a):
  print(a)

@x.register(int)
def _(a):
  print('int')

@x.register(str)
def _(a):
  print('str')

x(3.0) #3.0

x(3) #int

x('a') #str

Predicate(술어)

predicate

  • 반환값이 보통 True, False이며, is나 callable이름을 가진 함수

예시

isinstance(3,int) #True