본문 바로가기
IT/파이썬 기초 (Python)

#033 파이썬 기초 - 객체지향 프로그래밍 II

by DoitSQL 2023. 3. 16.
728x90

Python기초강의강좌, 파이썬기초강의강좌, Object-Oriented programming, class, method, init

#033 파이썬 기초 - 객체지향 프로그래밍 II

객체지향 프로그래밍 II

지난 시간에는 클래스와 객체가 어떤 기능을 갖도록 하는 방법, 즉 메서드에 대해 공부했습니다. 객체지향 프로그래밍 두 번째 시간입니다. 이번 시간에는 데이터의 경우 어떻게 하는지 공부합니다.


클래스 변수와 객체 변수

데이터, 즉 필드는 일반적인 변수와 다를 것이 없으나 딱 한 가지, 그 클래스 혹은 객체의 네임스페이스에 묶여 있다는 점이 다릅니다. 이것은 필드의 이름은 그 클래스 혹은 객체 내부에서만 의미가 있음을 의미합니다. 그래서 이것을 이름이 통용되는 공간이라고 하여 네임스페이스라고 부릅니다.

 

필드 에는 두 종류가 있는데, 클래스 변수와 객체 변수입니다. 각각은 그것을 소유하고 있는 대상이 클래스인지 객체인지에 따라 구분됩니다.

 

클래스 변수는 공유됩니다. 즉, 그 클래스로부터 생성된 모든 인스턴스들이 접근할 수 있습니다. 클래스 변수는 한 개만 존재하며 어떤 객체가 클래스 변수를 변경하면 모든 다른 인스턴스들에 변경 사항이 반영됩니다.

 

객체 변수는 클래스로부터 생성된 각각의 객체/인스턴스에 속해 있는 변수입니다. 이 경우에는, 각각의 객체별로 객체 변수를 하나씩 따로 가지고 있으며, 서로 공유되지 않고 각 인스턴스에 존재하는 같은 이름의 필드끼리 서로 어떤 방식으로든 간섭되지 않습니다.

 

예제를 통해 좀 더 자세히 알아봅시다

예제 : oop_objvar.py로 저장하세요.

# Filename : oop_objvar.py # -*- coding:utf-8 -*- class Robot: ​​​​"""Represents a robot, with a name.""" ​​​​# A class variable, counting the number of robots ​​​​population = 0 ​​​​def __init__(self, name): ​​​​​​​​"""Initializes the data.""" ​​​​​​​​self.name = name ​​​​​​​​print("(Initializing {})".format(self.name)) ​​​​​​​​# When this person is created, the robot ​​​​​​​​# adds to the population ​​​​​​​​Robot.population += 1 ​​​​def die(self): ​​​​​​​​"""I am dying.""" ​​​​​​​​print("{} is being destroyed!".format(self.name)) ​​​​​​​​Robot.population -= 1 ​​​​​​​​if Robot.population == 0: ​​​​​​​​​​​​print("{} was the last one.".format(self.name)) ​​​​​​​​else: ​​​​​​​​​​​​print("There are still {:d} robots working.".format( ​​​​​​​​​​​​​​​​Robot.population)) ​​​​def say_hi(self): ​​​​​​​​"""Greeting by the robot. ​​​​​​​​Yeah, they can do that.""" ​​​​​​​​print("Greetings, my masters call me {}.".format(self.name)) @classmethod ​​​​def how_many(cls): ​​​​​​​​"""Prints the current population.""" ​​​​​​​​print("We have {:d} robots.".format(cls.population)) droid1 = Robot("R2-D2") droid1.say_hi() Robot.how_many() droid2 = Robot("C-3PO") droid2.say_hi() Robot.how_many() print("\nRobots can do some work here.\n") print("Robots have finished their work. So let's destroy them.") droid1.die() droid2.die() Robot.how_many()

▶ 실행 결과

C:\Anaconda\envs\study_39\python.exe E:\python_study\oop_objvar.py (Initializing R2-D2) Greetings, my masters call me R2-D2. We have 1 robots. (Initializing C-3PO) Greetings, my masters call me C-3PO. We have 2 robots. Robots can do some work here. Robots have finished their work. So let's destroy them. R2-D2 is being destroyed! There are still 1 robots working. C-3PO is being destroyed! C-3PO was the last one. We have 0 robots.

▶ 동작 원리

예제가 좀 길지만, 클래스/객체 변수의 이해를 돕도록 만들어져 있습니다. 여기서 population 은 Robot 클래스에 속해 있는 클래스 변수입니다. 또, name 변수는 객체에 소속되어 있는 (즉 self를 이용하여 사용되는) 객체 변수입니다.

 

또한, population 클래스 변수는 Robot.population과 같이 사용하며 self.population과 같이 사용하지 않습니다. 반면 객체 변수 name 은 그 객체 안에서 self.name과 같이 사용됩니다. 이러한 클래스 변수와 객체 변수의 작은 차이점에 유의하시기 바랍니다. 또, 클래스 변수와 같은 이름을 가진 객체 변수는 클래스 변수를 감춘다는 점을 기억하세요!

 

Ropot.population 대신에 self.class.population라고도 사용할 수 있는데 이것은 모든 객체는 그 객체를 생성하는 데 사용되었던 클래스를 self.class 속성을 통해 참조하고 있기 때문입니다.

 

메서드 how_many는 객체에 소속되어 있지 않고 클래스에 소속되어 있는 메서드입니다. 여기서 우리가 해당 클래스의 어떤 부분까지 알아야 할 지에 따라 메서드를 클래스 메서드(class mathod)로 정의할지 스태틱 메서드(static method)로 정의할지 결정할 수 있습니다. 여기서는 클래스 변수를 사용할 것이므로, 클래스 메서드를 사용합니다.

 

여기서는 how_many 메서드를 클래스 메서드로 만들어 주기 위해 데코레이터를 이용하였습니다.

 

데코레이터는 어떤 일을 추가로 해 주는 더 큰 함수로 해당 부분을 감싸주는 것이라고 생각하면 됩니다. 즉, @classmethod 데코레이터는 아래처럼 호출하는 것과 같습니다:

how_many = classmethod(how_many)

init 메서드는 Robot의 인스턴스를 초기화시킬 때 사용됩니다. 이 메서드를 통해 로봇이 하나 추가될 때마다 로봇의 개수를 의미하는 변수 population을 1 씩 증가시켜 줍니다. 또한 각 생성된 객체별로 객체 변수 self.name의 값을 따로따로 지정해 주었습니다.

 

객체에 속해 있는 변수와 메서드에 접근하기 위해서는 반드시 self를 사용해야 한다는 점을 기억하시기 바랍니다. 이것을 다른 말로 속성 참조(attribute reference)라 부릅니다.

 

프로그램을 살펴보면 메서드에 정의된 것처럼 클래스에도 DocString 이 정의되어 있는 것을 보실 수 있습니다. 마찬가지로 이 DocString에도 Robot.doc을 통해 접근할 수 있고, 또 메서드의 DocString 은 Robot.say_hi.doc과 같이 접근할 수 있습니다.

 

die 메서드가 실행되면, 간단히 Robot.population을 하나 줄여 줍니다.

 

모든 클래스 멤버는 클래스 외부에 공개되어 있습니다. 한 가지 예외가 있는데, 여러분이 밑줄 두 개로 시작하는 데이터 멤버를 정의할 때, 즉 예를 들어 __privatevar와 같이 하면, 파이썬이 이것을 클래스 외부로 드러나지 않도록 숨겨 줍니다.

 

이것은 클래스나 객체에 속해 있는 어떤 변수에나 적용됩니다. 클래스와 객체에 정의된 모든 이름은 밑줄로 시작하지 않는 이상 외부로 공개하고 다른 클래스나 객체에서 불러와 사용할 수 있도록 하는 규칙을 따르는 것이 좋습니다. 그러나 이것은 파이썬에서 강제하는 것이 아니며 (밑줄 두 개로 시작하는 경우를 제외하고) 프로그래머들끼리의 약속입니다.

C++/Java/C# 프로그래머를 위한 주석
모든 클래스 멤버는 (데이터 멤버를 포함하여) public이며 따라서 파이썬의 모든 메서드는 virtual입니다.

오늘 내용은 좀 어려운 듯합니다. 차근히 몇 번 보시면 이해되리라 생각합니다.

"객체지향 프로그래밍 III"로 다음 시간에 계속합니다.

 

감사합니다.

Do it! SQL을 찾아 주셔서 감사합니다. ♥ 댓글이 큰 힘이 됩니다.

 

728x90

댓글