Post

(python) 함수, 클래스, 객체, \*args, \*\*kwargs

1
2
3
4
5
\*args
## 가변인수
\*\*kwargs
## 가변 키워드 인수. key=value 형태의 가변 길이 인수를 받을 때. dict 형태로 넘겨받게 된다.

키워드 인수를 반드시 key=value 형식으로만 받고 싶을 때
1
2
3
4
def test(arg, key=None):
pass
test(1, 2)

positional arg 다음에 이어서 그냥 인자를 넘기면 알아서 위치대로 키워드 인자로 들어간다. 반드시 key=3처럼 지정해주어야만 동작하도록 하고 싶은 경우, \*을 적는다. 라이브러리 코드 보면 저런게 꽤 많다.

1
2
def test(arg, \*, key=None):

return

return (a, b) C 였다면 여러 (타입의) 값을 외부에 전달하기 위해 구조체를 사용하거나, 포인터를 이용했을 것. 리스트, 투플에 들어갈 타입을 한정하지 않기 때문에 투플을 만들어서 바로 리턴할 수 있음. return x > 0 return에 조건을 적을 수 있다. 조건에 맞게 True, False를 반환한다. * return에 조건식을 적지 못하는 다른 언어였다면 삼항 연산자를 이용하거나, if로 처리했을 것이다.

1
2
3
4
5
6
7
return x > 0 ? true : false
또는
if x > 0
return true
else
return false

global 붙이면 외부 변수에 접근할 수 있지만 역시 안쓰는게 좋다.

Class

클래스는 다음과 같이 정의한다

1
2
class 클래스명[(상속 클래스명)]:

상속하는 경우 메소드 오버라이딩할 수 있다.

instance method, class method / self, cls
1
2
3
4
5
6
7
8
class Tst:
def funcTst(self, a, b):

  

@classmethod
def classTst(cls, a, b):

객체에서 메서드(클래스 함수)를 호출할 때 객체 자기 자신(self)이 첫 번째 인자로 넘어간다. 그래서 ob.funcTst(3, 2)이렇게 두 개의 인자를 넘겨도 실제로는 python self, 3, 2 세 개의 인자가 넘어가게 된다. 그래서 메서드를 정의할 때 관례적으로 첫번째 인자는 self를 사용한다. 자바의 this같은거라고 생각하면 된다. class method로 정의된 method의 첫번째 인자로는 self가 아니라 cls를 사용한다.

@classmethod

@classmethod를 붙이면 class method가 된다. class method는 객체 정의 안하고 바로 호출한다.

1
2
Tst.classTst(a, b)

@staticmethod

이 것도 있는데 잘 안쓴다.

클래스 변수, 객체 변수(인스턴스 변수)

class 바로 하위에 선언된 변수는 클래스 변수다. 자주 쓰지는 않는다.

java의 static 변수와 비슷 하다고 생각하면 된다. 한 클래스에 하나만 만들어져서 어떤 인스턴스에서 수정하든 하나 수정하면 다 수정된다.

클래스 내에서 클래스 변수 에 접근하기 위해서는 클래스명. 을 사용한다.

클래스 내에서 객체 변수 에 선언/접근하기 위해서는 self. 을 사용한다. 그냥 var를 사용하면 메서드에 var라는 변수가 만들어지니 주의.

1
2
3
4
5
6
7
8
9
10
11
class Tst:
var = "Tst, string var"
def \_\_init\_\_(self, name):
self.name = name
Tst.var = 33
def funcTst(self, a, b):
result = a + b
print("Tst," + self.name + "funcTst : "+str(result))
def \_\_del\_\_(self):
pass # 소멸자

클래스 변수, 객체 변수 둘 다 외부에서 접근 가능하다.

클래스 변수 varob.var / Tst.var둘 다 가능하지만, 구분을 위해 python Tst.var로 쓰는 것이 좋다. nameob.name만 가능하다. \_\_init\_\_을 호출하면서 객체 변수 name이 생성되기 때문에, 이는 객체 ob에 종속된다.

getter / setter

property(get\_var, set\_var)또는python @property / @var.setter를 이용해 getter / setter를 설정할 수 있으나 굳이 이렇게 해야 하는 경우는 잘 없다.

Special method names

__slots__

클래스의 인스턴스는 기본적으로 attribute storage를 위한 딕셔너리를 가지고 있다.(여기서 attribute는 instance attribute를 말하는 듯) 이로인해 인스턴스 변수가 별로 없는 경우 객체의 공간을 낭비하게 된다. * attribute = 변수

__slots__를 override해서 인스턴스 변수를 리스트나 투플로 지정 하고 나서 사용하면 메모리 낭비를 줄이고 속도를 향상시킬 수 있다.

1
2
\_\_slots\_\_ = ('url', 'file')

__slots__를 지정하는 경우 그 인스턴스에 대해 __dict__가 자동으로 생성되는 것을 막아주고 지정한 변수를 위한 공간만 할당하기 때문에 메모리가 절약되는 것이라고 한다.

Notes on using__slots__
  • __dict__가 없기 때문에 인스턴스는 __slots__에 명시되지 않은 새로운 변수를 할당할 수 없다. 할당하는 경우 AttributeError가 발생한다.
  • 만약 새로운 변수를 동적으로 할당해야 하는 상황이라면 __slots__에 지정된 변수 목록에 __dict__를 추가하는 방식으로 사용 가능하다.
  • __slots__가 없는 class에서 상속받는 경우 __dict__가 자동으로 상속되기 때문에 subclass에서 __slots__구현은 무의미하다.
  • 반대로 __slots__가 있는 class에서 상속받더라도 subclass에서 자동으로 __dict__가 생성되는 것을 막으려면 __slots__를 구현해주어야 한다.
  • https://docs.python.org/3/reference/datamodel.html#slots

__slots__을 지정하지 않아 __dict__가 있는 경우, 클래스에 없는 변수도 객체에 생성할 수 있다. 오타 조심.

__repr__

정의하면 print(obj)했을 때 이 메소드에 지정된 형식 대로 출력된다.

연산자 오버로딩

\_\_add\_\_(self, other)

\_\_eq\_\_(self, other)

등등을 사용하면 객체끼리 연산자를 사용할 수 있으며 연산자를 사용하면 앞쪽 함수의 \_\_add\_\_(self, other) 등이 호출된다.

This post is licensed under CC BY 4.0 by the author.