Introducing Python(처음 시작하는 파이썬)
Chapter 6. 객체와 클래스
6.1 What Are Objects? (객체란 무엇인가?)
- 파이썬에서는 숫자에서 모듈까지 모든 것이 객체이다.
- 객체는 어떤 구체적인 것의 유일한 Instance이다.
* Object(객체) = Data(데이터) + Code(코드)
- Data = Variable = Attribute
- Code = Function = Method
6.2 Define a Class with class (클래스 선언하기: class)
class Person(): # Person 클래스 정의
def __init__(self, name):
self.name = name
...
someone = Person('Elmer Fudd') # Person 클래스 객체 someone
# __init__() 메서드를 호출한다.
# self에는 someone 객체가 전달되고,
# name에는 'Elmer Fudd'가 전달된다.
* __init__() 메서드
- 파이썬 특수 메서드이다.
- 클래스 정의에 위치하여, 객체를 초기화할 때 이용된다. (C++의 Constructor)
- __init__() 메서드는 같은 클래스에서 생성된 다른 객체들을 서로 구분짓기 위한 작업을 수행한다.
- 첫 번째 매개변수는 반드시 self이어야 한다.
+ 두 개의 언더스코어(__)를 "Dunder"라 부르기도 한다.
※ 모든 클래스 정의에 __init__() 메서드에 대한 정의가 필수적이지는 않다.
* self
- 객체 자기 자신을 가리키는 인자이다. (C++의 this 포인터)
- self는 예약어가 아니다. 관용적으로 "self"라 표현하는 것이다.
6.3 Inheritance (상속)
- 문제를 해결하려할 때, 대부분의 기능을 수행하는 기존의 클래스에 필요한 기능을 추가하여 문제를 해결하려 한다.
- 상속은 기존의 클래스의 기능을 해치지 않으면서 기능을 추가할 수 있도록 한다.
- 즉, Code Reuse(코드 재사용)을 구현할 수 있는 수단이다.
* Existing Class(기존 클래스) = Parent Class(부모 클래스) = Super Class(슈퍼 클래스) = Base Class(베이스 클래스)
* New Class(새 클래스) = Child Class(자식 클래스) = Sub Class(서브 클래스) = Derived Class(파생 클래스)
* 상속 방법
class Car(): # Parent Class "Car"
def exclaim(self):
print("I'm a Car!")
class Yugo(Car): # Yugo Is-A Car
pass
>>> give_me_a_car = Car()
>>> give_me_a_yugo = Yugo()
>>> give_me_a_car.exclaim()
I'm a Car!
>>> give_me_a_yugo.exclaim()
I'm a Car!
6.4 Override a Method (메서드 오버라이드)
- 상속받은 부모 클래스의 메서드를 자신에게 맞추어 재정의하는 것을 의미한다.
- __init__() 메서드를 포함하여, 클래스의 모든 메서드를 오버라이드할 수 있다.
>>> class Car():
... def exclaim(self):
... print("I'm a Car!")
...
>>> class Yugo(Car):
... def exclaim(self):
... print("I'm a Yugo! Much like a Car, but more Yugo-ish.")
...
>>> give_me_a_car = Car()
>>> give_me_a_yugo = Yugo()
>>> give_me_a_car.exclaim()
I'm a Car!
>>> give_me_a_yugo.exclaim()
I'm a Yugo! Much like a Car, but more Yugo-ish.
6.5 Add a Method (메서드 추가하기)
- 자식 클래스는 부모 클래스에 없는 메서드를 추가할 수 있다.
>>> class Car():
... def exclaim(self):
... print("I'm a Car!")
...
>>> class Yugo(Car):
... def exclaim(self):
... print("I'm a Yugo! Much like a Car, but more Yugo-ish.")
... def need_a_push(self):
... print("A little help here?")
...
>>> give_me_a_car = Car()
>>> give_me_a_yugo = Yugo()
>>> give_me_a_yugo.need_a_push()
A little help here?
>>> give_me_a_car.need_a_push() # 추가된 메서드는 자식 클래스의 메서드이다.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Car' object has no attribute 'need_a_push'
6.6 Get Help from Your Parent with super (부모에게 도움 받기: super)
* super() 메서드
- 자식 클래스 객체에서 오버라이드 하기 이전의 메서드(즉, 부모 클래스의 메서드)를 호출하기 위해 사용하는 메서드이다.
>>> class Person():
... def __init__(self, name):
... self.name = name
...
>>> class EmailPerson(Person):
... def __init__(self, name, email):
... super().__init__(name) # super() 메서드를 이용한 Code Reuse
... self.email = email
>>> bob = EmailPerson('Bob Frapples', 'bob@frapples.com')
>>> bob.name
'Bob Frapples'
>>> bob.email
'bob@frapples.com'
6.7 In self Defense (자신: self)
※ 모든 파이썬 Instance Method Definition에서의 첫 번째 Argument는 self이어야 한다.
* 두 가지 메서드 호출 방법
>>> class Car():
... def exclaim(self):
... print("I'm a Car!")
>>> car = Car()
>>> car.exclaim() # 일반적인, Pythonic한 메서드 호출 방법이다.
I'm a Car!
>>> Car.exclaim(car) # 메서드 정의에 맞춰서, 이와 같이 호출할 수도 있다.
I'm a Car!
6.8 Get and Set Attribute Values with Properties (get/set 속성값과 프로퍼티)
* Getter Method
- private 멤버를 리턴하는 메서드를 Getter라 부른다.
* Setter Method
- private 멤버에 입력값을 대입시키는 메서드를 Setter라 부른다.
* property(Getter, Setter)
- 파이썬 Built-In Function이다.
- private 멤버를 마치 public 멤버를 사용하듯이 Field Notation("object.member")을 사용할 수 있게하는 함수이다.
- 첫 번째 Argument로 해당 멤버의 Getter이 와야하고, 두 번째 Argument로 해당 멤버의 Setter가 와야한다.
>>> class Duck():
... def __init__(self, input_name):
... self.hidden_name = input_name
... def get_name(self):
... print('inside the getter')
... return self.hidden_name
... def set_name(self, input_name):
... print('inside the setter')
... self.hidden_name = input_name
... name = property(get_name, set_name)
>>> fowl = Duck('Howard')
>>> fowl.name # property() 덕분에 hidden_name 멤버를 public 멤버에 접근하듯이 접근할 수 있다.
inside the getter
'Howard'
>>> fowl.get_name() # 여전히 보통의 Getter를 사용하듯이 사용할 수도 있다.
inside the getter
'Howard'
>>> fowl.name = 'Daffy' # Setter를 이용할 때도, public 멤버를 수정하듯이 수정할 수 있다.
inside the setter
>>> fowl.name
inside the getter
'Daffy'
# 하지만, hidden_name이 구조적으로 private 멤버인 것은 아니다!
# getter, setter와 property를 사용하는 것은 프로그래머들 간의 약속이며, 강제사항이 아니다.
>>> fowl.hidden_name
'Howard'
* Decorator를 이용하여 property를 정의하는 방법
- Getter 메서드 앞에 @property 데커레이터를 쓴다.
- Seeter 메서드 앞에 @name.setter 데커레이터를 쓴다.
>>> class Duck():
... def __init__(self, input_name):
... self.hidden_name = input_name
... @property
... def name(self):
... print('inside the getter')
... return self.hidden_name
... @name.setter
... def name(self, input_name):
... print('inside the setter')
... self.hidden_name = input_name
... # Getter와 Setter를 정의하지 않고, Decorator를 이용해 더욱 Pythonic한 코드를 만들 수 있다.
# 물론, Getter, Setter를 정의하지 않았으니, Getter, Setter를 사용할 수는 없다.
>>> fowl = Duck('Howard')
>>> fowl.name
inside the getter
'Howard'
>>> fowl.name = 'Donald'
inside the setter
>>> fowl.name
inside the getter
'Donald'
* property를 통해 계산된 값에 접근하는 방법
- property가 계산된 값을 리턴하게 하면 된다.
>>> class Circle():
... def __init__(self, radius):
... self.radius = radius
... @property
... def diameter(self):
... return 2 * self.radius
...
>>> c = Circle(5)
>>> c.radius
5
>>> c.diameter
10
>>> c.radius = 7
>>> c.diameter
14
# 위와 같이, Setter를 정의하지 않은 상태에서 값을 수정하려 하면 에러가 발생된다.
# Getter는 read-only 이다.
>>> c.diameter = 20
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
6.9 Name Mangling for Privacy (private 네임 맹글링)
* Name Mangling(이름 바꾸기)
- 이름 앞에 두 개의 언더스코어(__)를 붙은 형태는 private 멤버이다.
- 파이썬은 위와 같은 Naming Convention(두 개의 언더스코어로 시작하는 네이밍 방법)을 보이는 멤버가 외부 코드에서 발견될 수 없도록 해당 private 멤버의 이름을 Mangling한다.
- Name Mangling은 해당 멤버의 속성을 근본적으로 private으로 변경시키는 것은 아니다.
해당 멤버의 직접적인 접근을 막는 방법 중 하나이다.
>>> class Duck():
... def __init__(self, input_name):
... self.__name = input_name
... @property
... def name(self):
... print('inside the getter')
... return self.__name
... @name.setter
... def name(self, input_name):
... print('inside the setter')
... self.__name = input_name
...
>>> fowl = Duck('Howard')
>>> fowl.name
inside the getter
'Howard'
>>> fowl.name = 'Donald'
inside the setter
>>> fowl.name
inside the getter
'Donald'
>>> fowl.__name // private 멤버에는 직접 접근할 수 없다.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Duck' object has no attribute '__name'
6.10 Method Types (메서드 타입)
* Instance Method (인스턴스 메서드)
- 첫 번째 인자가 self인 메서드를 의미한다.
- 한 객체에 하나의 인스턴스 메서드가 귀속되며, 인스턴스 메서드는 해당 객체를 관리하는 함수이다.
* Class Method (클래스 메서드)
- 인스턴스 메서드와 달리, 클래스 전체를 관리하는 함수를 의미한다.
- 클래스 정의 부분에 @classmethod 데커레이터를 통해 클래스 메서드를 정의할 수 있다.
- 첫 번째 인자는 클래스 자신이 위치해야 한다.
(따라서, 메서드를 호출하는 주체는 객체가 아닌 클래스이다.)
※ 파이썬에서는 관례상, 첫 번째 인자로 오는 클래스를 "cls"로 표현한다. (class는 예약어이기 때문에 사용하지 못한다.)
* 만들어진 객체의 개수를 헤아리는 클래스 메서드 kids(cls)
>>> class A():
... count = 0
... def __init__(self):
... A.count += 1
... def exclaim(self):
... print("I'm an A!")
... @classmethod
... def kids(cls):
... print("A has", cls.count, "little objects.")
...
>>>
>>> easy_a = A()
>>> breezy_a = A()
>>> wheezy_a = A()
>>> A.kids() # 메서드를 호출한 주체가 객체가 아닌, 클래스임에 유의하자.
A has 3 little objects.
* Static Method (정적 메서드)
- 클래스 메서드처럼, 호출하는 주체가 클래스인 메서드이다.
- 하지만, 다른 메서드들과 달리, 첫 번째 인자로 cls나 self를 요구하지 않는다.
(코딩 편의를 위한 메서드 타입이다.)
- 클래스 정의 부분에 @staticmethod 데커레이터를 통해 정적 메서드를 정의할 수 있다.
>>> class CoyoteWeapon():
... @staticmethod
... def commercial():
... print('This CoyoteWeapon has been brought to you by Acme')
...
>>>
>>> CoyoteWeapon.commercial()
This CoyoteWeapon has been brought to you by Acme
6.11 Duck Typing (덕 타이핑)
- 클래스 상속이나 인터페이스 구현으로 타입을 구분하는 대신,
덕 타이핑은 객체가 어떤 타입에 걸맞은 변수와 메소드를 지니면 객체를 해당 타입에 속하는 것으로 간주한다.
* Duck Typing이라는 용어는 아래의 Duck Test 방법에서 유래되었다.
"If it walks like a duck and quacks like a duck, it’s a duck."
(오리가 걷는 방식이나, 우는 소리를 정의하는 대신, 오리처럼 걷고 오리처럼 울면 그것을 오리라 간주하는 방식이다.)
* 파이썬에서의 덕 타이핑 활용 방법
- 메서드의 이름이 같은, 서로 다른 클래스의 메서드를 아우르는 방법은 아래와 같다.
>>> class Quote():
... def __init__(self, person, words):
... self.person = person
... self.words = words
... def who(self):
... return self.person
... def says(self):
... return self.words + '.'
...
>>> class QuestionQuote(Quote):
... def says(self):
... return self.words + '?'
...
>>> class ExclamationQuote(Quote):
... def says(self):
... return self.words + '!'
...
>>> hunter = Quote('Elmer Fudd', "I'm hunting wabbits")
>>> print(hunter.who(), 'says:', hunter.says())
Elmer Fudd says: I'm hunting wabbits.
>>> hunted1 = QuestionQuote('Bugs Bunny', "What's up, doc")
>>> print(hunted1.who(), 'says:', hunted1.says())
Bugs Bunny says: What's up, doc?
>>> hunted2 = ExclamationQuote('Daffy Duck', "It's rabbit season")
>>> print(hunted2.who(), 'says:', hunted2.says())
Daffy Duck says: It's rabbit season!
# 전혀 관계가 없는 클래스 정의
>>> class BabblingBrook():
... def who(self):
... return 'Brook'
... def says(self):
... return 'Babble'
...
>>> brook = BabblingBrook()
# Duck Typing (클래스가 다르더라도, 메서드가 같으면 who_sats() 함수를 사용할 수 있다.
>>> def who_says(obj):
... print(obj.who(), 'says', obj.says())
...
>>> who_says(hunter)
Elmer Fudd says I'm hunting wabbits.
>>> who_says(hunted1)
Bugs Bunny says What's up, doc?
>>> who_says(hunted2)
Daffy Duck says It's rabbit season!
>>> who_says(brook)
Brook says Babble
6.12 Special Methods (특수 메서드)
- 파이썬의 특수 메서드는 C++에서의 Operator Overloading Function에 해당된다.
- 즉, 산술/비교 연산자를 해당 클래스에 적절히 오버로딩하고자 할 때 정의하는 함수이다.
- 특수 메서드의 이름은 두 개의 언더스코어(__)가 이름의 앞, 뒤에 붙으며, 특수 메서드의 이름은 미리 예약되어 있다.
- 특수 메서드를 정의할 시, 미리 예약된 이름에 맞추어 함수의 이름을 정의하고, 해당 클래스에 부합하는 연산을 정의하면 된다.
(C++에서 이름이 정해져있는 연산자 오버로딩 함수를 정의한다고 생각하면 된다.)
- 파이썬의 문자열 객체에 Concatenation을 위해 + 연산자를 사용하고, Duplication을 위해 * 연산자를 사용 가능한 이유는
해당 연산자들이 문자열 클래스에 부합하는 특수 메서드로 Overloading되었기 때문이다.
* 특수 메서드 References (URL)
* 산술 연산을 위한 특수 메서드
Special Method | Description |
__add__(self, other) | self + other |
__sub__(self, other) | self - other |
__mul__(self, other) | self * other |
__floordiv__(self, other) | self || other |
__truediv__(self, other) | self | other |
__mod__(self, other) | self % other |
__pow__(self, other) | self ** other (\(self^{other}\)) |
* 비교 연산을 위한 특수 메서드
Special Method | Description |
__eq__(self, other) | self == other |
__ne__(self, other) | self != other |
__lt__(self, other) | self < other |
__gt__(self, other) | self > other |
__le__(self, other) | self <= other |
__ge__(self, other) | self >= other |
* 기타 특수 메서드
Special Method | Description |
__str__(self) | str(self) : 객체를 string으로 출력하는 메서드 |
__repr__(self) | repr(self) : 객체의 결과를 출력하는 메서드 |
__len__(self) | len(self) |
>>> class Word():
... def __init__(self, text):
... self.text = text
... def __eq__(self, word2):
... return self.text.lower() == word2.text.lower()
...
>>> first = Word('ha')
>>> second = Word('HA')
>>> third = Word('eh')
>>> first == second
True
>>> first == third
False
# __str__() 또는 __repr__()을 정의하지 않으면, 객체의 Default String을 출력한다.
>>> first
<__main__.Word object at 0x1006ba3d0>
>>> print(first)
<__main__.Word object at 0x1006ba3d0>
>>> class Word():
... def __init__(self, text):
... self.text = text
... def __eq__(self, word2):
... return self.text.lower() == word2.text.lower()
... def __str__(self):
... return self.text
... def __repr__(self):
... return 'Word("' self.text '")'
...
>>> first = Word('ha')
>>> first # uses __repr__
Word("ha")
>>> print(first) # uses __str__
ha
6.13 Composition (컴포지션) = Aggregation
- 파이썬에서 Has-A 관계를 구성하는 방식이다.
* X Is-a Y 관계
- X가 Y에 속하는 경우이다.
ex) 오리 Is-a 조류
* X Has-a Y 관계
- X는 Y를 갖고 있지만, Y가 X에 완전히 포함되지는 않는 경우이다.
ex) 오리 Has-a 부리
>>> class Bill(): # 부리 (bill)
... def __init__(self, description):
... self.description = description
...
>>> class Tail(): # 꼬리 (tail)
... def __init__(self, length):
... self.length = length
...
>>> class Duck(): # 오리 (duck)
... def __init__(self, bill, tail):
... self.bill = bill
... self.tail = tail
... def about(self):
... print('This duck has a', bill.description, 'bill and a', tail.length, 'tail')
...
>>> tail = Tail('long')
>>> bill = Bill('wide orange')
>>> duck = Duck(bill, tail)
>>> duck.about()
This duck has a wide orange bill and a long tail
6.14 When to Use Classes and Objects versus Modules (클래스와 객체, 그리고 모듈은 언제 사용할까?)
* 클래스 및 모듈의 사용 기준
- 비슷한 메서드가 필요하지만, 속성이 다른 개별 인스턴스가 필요한 경우엔 클래스를 이용한다.
- 클래스는 상속을 지원하지만, 모듈은 상속을 지원하지 않는다.
- 어떤 한 가지 일만 수행한다면 모듈이 적절하다.
- 여러 함수에 인자로 전달될 수 있는 여러 값을 포함한 여러 변수가 있다면, 클래스로 정의한다.
- 가장 간단한 방법을 사용한다. 딕셔너리, 리스트, 튜플은 모듈보다 작고, 간단하며, 빠르다. 그리고 일반적으로 모듈은 클래스보다 간단하다.
6.14.1 Named Tuples (네임드 튜플)
- 튜플의 Subclass(자식 클래스)이다.
- 이름(.name)과 위치([offset])으로 값에 접근할 수 있다.
- 네임드 튜플은 파이썬에 내장되어 있지 않으며, 사용을 위해서는 collections 모듈을 임포트해야 한다.
(collections 모듈내의 namedtuple 함수로 정의되어 있다.)
- Immutable한 객체라 생각할 수 있다.
- 객체보다 공간적/시간적 효율성이 좋다.
- 딕셔너리 형식의 대괄호 대신, 온점(.)을 통해 속성에 접근할 수 있다.
- 네임드 튜플은 딕셔너리의 Key로 활용할 수 있다.
>>> from collections import namedtuple
>>> Duck = namedtuple('Duck', 'bill tail')
>>> duck = Duck('wide orange', 'long')
>>> duck
Duck(bill='wide orange', tail='long')
>>> duck.bill
'wide orange'
>>> duck.tail
'long'
# 딕셔너리에 네임드 튜플을 만들 수 있다.
>>> parts = {'bill': 'wide orange', 'tail': 'long'}
>>> duck2 = Duck(**parts) # **parts: Keyword Argument
# duck2 = Duck(bill = 'wide orange', tail = 'long') 와 같다.
>>> duck2
Duck(bill='wide orange', tail='long')
# 네임드 튜플은 Immutable하지만, replace() 함수를 통해 필드를 바꿔서 또 다른 네임드 튜플을 리턴할 수 있다.
>>> duck3 = duck2._replace(tail='magnificent', bill='crushing')
>>> duck3
Duck(bill='crushing', tail='magnificent')
# 딕셔너리는 네임드 튜플의 기능을 사용할 수 없음에 유의하자.
>>> duck_dict = {'bill': 'wide orange', 'tail': 'long'}
>>> duck_dict
{'tail': 'long', 'bill': 'wide orange'}
>>> duck_dict['color'] = 'green'
>>> duck_dict
{'color': 'green', 'tail': 'long', 'bill': 'wide orange'}
# 딕셔너리는 네임드 튜플의 기능을 할 수 없다.
>>> duck.color = 'green'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'color'
※ Keyword Argument (**parts)
- parts 딕셔너리에서 Key와 Value를 추출하여 Duck()의 인자로 제공한다.
6.15 Things to Do (연습문제)
6.1 아무 내용도 없는 Thing 클래스를 만들어서 출력하라.
그리고 이 클래스의 example 객체를 생성해서 출력하라.
두 출력값은 같은가?
Sol 6.1
>>> class Thing():
... pass
...
>>> example = Thing()
>>> print(Thing)
<class '__main__.Thing'>
>>> print(example)
<__main__.Thing object at 0x000001813BE0E6D0>
6.2 Thing2 클래스를 만들고, 이 클래스의 letters 속성에 값 'abc'를 할당한 후 letters를 출력하라.
Sol 6.2
>>> class Thing2():
... letters = 'abc'
...
>>> print(Thing2.letters)
abc
6.3 Thing3 클래스를 만들어라.
이번에는 인스턴스(객체)의 letters 속성에 값 'xyz'를 할당한 후 letters를 출력하라.
letters를 출력하기 위해 객체를 생성해야 하는가?
Sol 6.3
>>> class Thing3():
... def __init__(self):
... self.letters = 'xyz'
...
>>> example = Thing3()
>>> print(example.letters)
xyz
>>> print(Thing3.letters)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Thing3' has no attribute 'letters'
6.4 name, symbol, number 인스턴스 속성을 가진 Element 클래스를 만들어라.
이 클래스로부터 'Hydrogen', 'H', 1값을 가진 객체를 생성하라.
Sol 6.4
>>> class Element():
... def __init__(self, name, symbol, number):
... self.name = name
... self.symbol = symbol
... self.number = number
...
>>> hydrogen = Element('Hydrogen', 'H', 1)
>>> print(hydrogen)
<__main__.Element object at 0x000001813BF48D90>
>>> print(hydrogen.name)
Hydrogen
>>> print(hydrogen.symbol)
H
>>> print(hydrogen.number)
1
6.5 'name': 'Hydrogen', 'symbol': 'H', 'number': 1과 같이 키와 값으로 이루어진 el_dict 딕셔너리를 만들어라.
그리고 el_dict 딕셔너리로부터 Element 클래스의 hydrogen 객체를 생성하라.
Sol 6.5
>>> el_dict = {
... 'name': 'Hydrogen',
... 'symbol': 'H',
... 'number': 1
... }
>>> hydrogen = Element(**el_dict)
>>> print(hydrogen)
<__main__.Element object at 0x000001813BF28580>
>>> print(hydrogen.name)
Hydrogen
>>> print(hydrogen.symbol)
H
>>> print(hydrogen.number)
1
# 혹은, hydrogen = Element(el_dict['name'], el_dict['symbol'], el_dict['number']) 와 같이 생성할 수도 있다.
6.6 Element 클래스에서 객체의 속성(name, symbol, number)값을 출력하는 dump() 메서드를 정의하라.
이 클래스의 hydrogen 객체를 생성하고, dump() 메서드로 이 속성을 출력하라.
Sol 6.6
class Element():
def __init__(self, name, symbol, number):
self.name = name
self.symbol = symbol
self.number = number
def dump(self):
print('name: ', self.name, ', symbol: ', self.symbol, ' number: ', self.number)
# 또는 print('name=%s, symbol=%s, number=%s' % (self.name, self.symbol, self.number))
hydrogen = Element('Hydrogen', 'H', 1)
hydrogen.dump()
>>> name: Hydrogen , symbol: H number: 1
6.7 print(hydrogen)을 호출하라.
Element 클래스의 정의에서 dump 메서드를 __str__메서드로 바꿔서 새로운 hydrogen 객체를 생성하라.
그리고 print(hydrogen)을 다시 호출해보라.
Sol 6.7
class Element():
def __init__(self, name, symbol, number):
self.name = name
self.symbol = symbol
self.number = number
def __str__(self):
return ('name = %s, symbol = %s, number = %s' % (self.name, self.symbol, self.number))
# __str__은 문자열을 "리턴"해야만 한다.
hydrogen = Element('Hydrogen', 'H', 1)
print(hydrogen)
>>> name = Hydrogen, symbol = H, number = 1
6.8 Element 클래스를 수정해서 name, symbol, number의 속성을 private으로 만들어라.
각 속성값을 반환하기 위해 getter 프로퍼티를 정의한다.
Sol 6.8
class Element():
def __init__(self, name, symbol, number):
# private 멤버로 만들고
self.__name = name
self.__symbol = symbol
self.__number = number
# Getter를 정의한다
@property
def name(self):
return self.__name
@property
def symbol(self):
return self.__symbol
@property
def number(self):
return self.__number
hydrogen = Element('Hydrogen', 'H', 1)
>>> print(hydrogen.name)
>>> print(hydrogen.symbol)
>>> print(hydrogen.number)
6.9 세 클래스 Bear, Rabbit, Octothorpe를 정의하라.
각 클래스에 eats() 메서드를 정의하라.
각 메서드는 'berries'(Bear), 'clover'(Rabbit), 또는 'campers'(Octothorpe)를 반환한다.
각 클래스의 객체를 생성하고, eats() 메서드의 반환값을 출력하라.
Sol 6.9
class Bear():
def eats(self):
return 'berries'
class Rabbit():
def eats(self):
return 'clover'
class Octothorpe():
def eats(self):
return 'campers'
bear = Bear()
rabbit = Rabbit()
octothorpe = Octothorpe()
print('bear: %s, rabbit: %s, octothorpe: %s' % (bear.eats(), rabbit.eats(), octothorpe.eats()))
>>> bear: berries, rabbit: clover, octothorpe: campers
6.10 Laser, Claw, SmartPhone 클래스를 정의하라.
각 클래스는 does() 메서드를 갖고 있다.
각 메서드는 'disintegrate' (Laser), 'crush' (Claw), 또는 'ring' (Smart Phone)을 반환한다.
그리고 각 인스턴스(객체)를 갖는 Robot 클래스를 정의하라.
Robot 클래스의 객체가 갖고 있는 내용을 출력하는 does() 메서드를 정의하라.
Sol 6.10
class Laser():
def does(self):
return 'disintegrate'
class Claw():
def does(self):
return 'crush'
class SmartPhone():
def does(self):
return 'ring'
class Robot():
laser = Laser()
claw = Claw()
smartphone = SmartPhone()
def does(self):
print('Robot has %s, %s and %s' % (self.laser.does(), self.claw.does(), self.smartphone.does()))
robot = Robot()
robot.does()
>>> Robot has disintegrate, crush and ring
Reference: Introducing Python(처음 시작하는 파이썬) (Bill Lubanovic 저, O'Reilly, 2015)