self 는 해당 class 안에 있는 variable 을 implicitly refer to 해주기 위해 사용한다.
다음의 class Monster() 예시를 보자.
class Monster(): hp = 100 alive = True def damage(self, attack): self.hp = self.hp - attack if self.hp < 0: alive = False def check_status(self): if self.alive: print('Alive!') else: print('Dead!') # monster instances m1 = Monster() m1.damage(120) m1.check_status() m2 = Monster() m2.damage(40) m2.check_status()
위의 코드를 통해 게임 상에서 괴물을 공격하고자 할 때 하나의 해당 괴물에 대한 hp (health point) 를 체크해 괴물이 죽었는지 살았는지에 대한 정보를 알 수 있다. 깔끔하게 잘 짜여진 코드같아 가져와봤다.
마지막 부분을 보면 m1 과 m2, 두 개의 instances 가 만들어졌다.
이후 m1 과 m2 가 각각 Monster class 에 속하는 self variables 그 자체로서 damage() 와 check_status() 함수들에 들어감을 알 수 있다. 참고로 위의 코드를 적다보면 def 의 parameters 에 저절로 self 가 채워지는데, 이처럼 class 안에 있는 함수들은 모두 self 를 첫 parameter 로 갖게 된다.
단, m1.damage(120) 에서도 볼 수 있듯이 함수를 이용할 때 self 의 자리는 놔두도록 한다.
그동안 애매모호했던 init function 의 개념이 조금은 명확해진 것 같다.
class test: def __init__(self, a, b): self.x = a self.y = b
이와 같이 init 은 어떠한 class 내에서 instance variables 에 대한 값을 initialize 해주는 함수이다. 그렇다면 instance variable 은 무엇인지 class variable 과 비교하여 좀 더 자세히 알아보자.
class variable 은 모든 instance 끼리 공유하는 static 한 값인 반면에 instance variable 은 해당 함수 안에서 init 을 이용해 값이 initialize 되는 variable 이다.
class Dog 에 관한 예시를 들어보겠다.
강아지는 다리가 4개, 꼬리가 1개이므로 이는 static 한 변수이다.
class Dog: # class variables legs = 4 tail = 1 def __init__(self, name, age): self._name = name self._age = age # Dog instances dog1 = Dog('max', 5) print(dog1._name) # -> max print(dog1._age) # -> 5 dog2 = Dog('roy', 12) print(dog1._name) # -> roy print(dog1._age) # -> 12
이렇듯 dog1 과 dog2 는 다른 이름과 나이를 갖는데 이는 _name 과 _age 가 instance variables 로 initialize 되었기 때문이다.
print(dog1.legs) # -> 4
print(dog2.legs) # -> 4
반면, legs 는 class variable 로서 instances 와는 independent 하게 값의 변화가 없음을 알 수 있다.
앞서 배운 init 과 같은 함수들을 python 에서는 magic methods 라고 한다. 또 다른 magic methods 로는 name 과 main 을 들 수 있다.
name 과 main 의 가장 핵심적인 부분은 python 코드가 직접 작성된 파일 자체에서 run 되는지, 아니면 import 된 파일에서 실행되는지의 구분이다.
- Recall: C
# include <stdio.h> void main(void) { ... }
- Recall: Java
public class Hello_World { public static void main(String args[]) { ... } }
오랜만에 예전에 사용했던 C 와 Java 의 기본 틀을 가져와봤다.
Python 또한 main 을 갖고 있지만 위의 C 또는 java 처럼 explicit 하지 않다.
if __name__ == "__main__":
print(__name__)
이 조건문을 보면 name 이 main 과 같다면 name 을 프린트 할 수 있다.
name 은 현재 module 의 이름을 담고 있는 variable 이다.
따라서, 이 python module 이 직접 실행된다면 name 은 main 을 가진다. 하지만 다른 python file 에서 해당 module 을 import 해 와 실행하게 된다면 name 은 해당 module 이지만 main 은 import 해 온 제 2의 파일의 name 을 갖게 된다. 그렇기 때문에 위의 조건문은 성립하지 않고, 결국 name 또한 프린트되지 않음을 알 수 있다.
module.py 와 main.py 의 두 파일을 예를 들어보자.
📁 module.py
def say_hi(): print('Hi!) print(__name__)📁 main.py
import module module.say_hi()
위와 같이 코드를 완성 후 module.py 를 실행시켜보면 아래와 같은 결과가 나온다.
__main__
즉, name 이 main 과 일치함을 알 수 있고, 이는 앞서 말했듯이 say_hi() 함수가 만들어진 해당 파일에서 실행시킨 것이기에 name 과 main 이 같음을 알 수 있다. 이 때, main.py 를 실행시켜보면 module 의 name 이 바로 print 된 것이 확인된다.
module
Hi!
반면에, module.py 에 아래와 같은 조건을 걸었다고 해보자.
📁 module.py
def say_hi(): print('Hi!) if __name__ == "__main__" print(__name__)
그렇다면 main.py 를 실행시켰을 경우 다음과 같은 결과를 얻게 된다.
Hi!
즉, name 과 main 이 같지 않았기에 module.py 의 name 은 print 되지 않은 것이다. 따라서 우리는 이 때의 main 은 현재 함수가 실행된 main.py 의 name 과 일치할 뿐 module 의 name 과 동일하지 않아 if 문의 조건이 성립되지 않았음을 알 수 있다.
그동안은 VS Code 를 써왔는데 이번에 새로 강의를 들으며 Pycharm 이라는 프로그램을 쓰게 된 와중에 둘의 차이가 궁금해져 살짝 알아보았다.
VS Code 는 generally 호환이 좋아 다양한 언어들을 실행시키기에 적합하다. 또한 최소한의 메모리를 사용하여 "가볍다" 는 장점이 있는 대신 debugging 을 하기에는 친절하지 않다고 한다.
Pycharm 은 특히 python 에 특화되어 debugging 또한 용이한 반면에 다양한 packages 가 많아 "무겁다" 고 한다.