클래스를 사용하여 새로운 객체 생성하기

Beginner

This tutorial is from open-source community. Access the source code

소개

이 섹션에서는 클래스 문 (class statement) 과 새로운 객체를 생성하는 아이디어를 소개합니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 중급 레벨의 실험이며 완료율은 73%입니다.학습자들로부터 100%의 긍정적인 리뷰율을 받았습니다.

객체 지향 프로그래밍 (Object Oriented (OO) programming)

코드가 객체들의 모음으로 구성되는 프로그래밍 기법입니다.

객체는 다음으로 구성됩니다:

  • 데이터. 속성 (Attributes)
  • 동작. 객체에 적용되는 함수인 메서드 (Methods)

이 과정에서 이미 일부 객체 지향 프로그래밍을 사용해 왔습니다.

예를 들어, 리스트를 조작하는 경우를 살펴보겠습니다.

>>> nums = [1, 2, 3]
>>> nums.append(4)      ## Method
>>> nums.insert(1,10)   ## Method
>>> nums
[1, 10, 2, 3, 4]        ## Data
>>>

nums는 리스트의 인스턴스입니다.

메서드 (append()insert()) 는 인스턴스 (nums) 에 연결됩니다.

class

새로운 객체를 정의하려면 class 문을 사용합니다.

class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.health = 100

    def move(self, dx, dy):
        self.x += dx
        self.y += dy

    def damage(self, pts):
        self.health -= pts

간단히 말해서, 클래스는 소위 인스턴스에 대해 다양한 연산을 수행하는 함수들의 집합입니다.

인스턴스 (Instances)

인스턴스는 프로그램에서 조작하는 실제 객체입니다.

클래스를 함수처럼 호출하여 생성됩니다.

>>> a = Player(2, 3)
>>> b = Player(10, 20)
>>>

abPlayer의 인스턴스입니다.

강조: class 문은 단지 정의일 뿐이며 (그 자체로는 아무것도 하지 않습니다). 함수 정의와 유사합니다.

인스턴스 데이터 (Instance Data)

각 인스턴스는 자체 로컬 데이터를 가지고 있습니다.

>>> a.x
2
>>> b.x
10

이 데이터는 __init__()에 의해 초기화됩니다.

class Player:
    def __init__(self, x, y):
        ## `self` 에 저장된 모든 값은 인스턴스 데이터입니다.
        self.x = x
        self.y = y
        self.health = 100

저장되는 속성의 총 개수나 유형에 대한 제한은 없습니다.

인스턴스 메서드 (Instance Methods)

인스턴스 메서드는 객체의 인스턴스에 적용되는 함수입니다.

class Player:
    ...
    ## `move` 는 메서드입니다.
    def move(self, dx, dy):
        self.x += dx
        self.y += dy

객체 자체는 항상 첫 번째 인수로 전달됩니다.

>>> a.move(1, 2)

## `a` 를 `self` 에 매칭
## `1` 을 `dx` 에 매칭
## `2` 를 `dy` 에 매칭
def move(self, dx, dy):

관례적으로, 인스턴스는 self라고 불립니다. 하지만 실제로 사용되는 이름은 중요하지 않습니다. 객체는 항상 첫 번째 인수로 전달됩니다. 이 인수를 self라고 부르는 것은 단지 파이썬 프로그래밍 스타일일 뿐입니다.

클래스 스코핑 (Class Scoping)

클래스는 이름의 스코프를 정의하지 않습니다.

class Player:
    ...
    def move(self, dx, dy):
        self.x += dx
        self.y += dy

    def left(self, amt):
        move(-amt, 0)       ## NO. 전역 `move` 함수를 호출합니다.
        self.move(-amt, 0)  ## YES. 위의 메서드 `move` 를 호출합니다.

인스턴스에 대해 작업을 수행하려면 항상 명시적으로 참조해야 합니다 (예: self).

이 일련의 연습부터 이전 섹션의 기존 코드에 일련의 변경 사항을 적용하기 시작합니다. 시작하려면 Exercise 3.18 의 작동하는 버전이 있는 것이 중요합니다. 그렇지 않은 경우, Solutions/3_18 디렉토리에서 찾을 수 있는 솔루션 코드를 사용하십시오. 복사해도 괜찮습니다.

연습 문제 4.1: 데이터를 구조체로 사용하기 (Objects as Data Structures)

2 절과 3 절에서 우리는 튜플과 딕셔너리로 표현된 데이터를 사용했습니다. 예를 들어, 주식 보유는 다음과 같은 튜플로 표현될 수 있습니다.

s = ('GOOG',100,490.10)

또는 다음과 같은 딕셔너리로 표현될 수 있습니다.

s = { 'name'   : 'GOOG',
      'shares' : 100,
      'price'  : 490.10
}

이러한 데이터를 조작하기 위한 함수를 작성할 수도 있습니다. 예를 들어:

def cost(s):
    return s['shares'] * s['price']

하지만 프로그램이 커지면 더 나은 조직감을 만들고 싶을 수 있습니다. 따라서 데이터를 표현하는 또 다른 방법은 클래스를 정의하는 것입니다. stock.py라는 파일을 만들고 단일 주식 보유를 나타내는 Stock 클래스를 정의합니다. Stock의 인스턴스가 name, shares, price 속성을 갖도록 합니다. 예를 들어:

>>> import stock
>>> a = stock.Stock('GOOG',100,490.10)
>>> a.name
'GOOG'
>>> a.shares
100
>>> a.price
490.1
>>>

몇 개의 Stock 객체를 더 만들고 조작합니다. 예를 들어:

>>> b = stock.Stock('AAPL', 50, 122.34)
>>> c = stock.Stock('IBM', 75, 91.75)
>>> b.shares * b.price
6117.0
>>> c.shares * c.price
6881.25
>>> stocks = [a, b, c]
>>> stocks
[<stock.Stock object at 0x37d0b0>, <stock.Stock object at 0x37d110>, <stock.Stock object at 0x37d050>]
>>> for s in stocks:
     print(f'{s.name:>10s} {s.shares:>10d} {s.price:>10.2f}')

... 출력을 확인하세요 ...
>>>

여기서 강조할 한 가지는 Stock 클래스가 객체의 인스턴스를 생성하는 팩토리처럼 작동한다는 것입니다. 기본적으로 함수처럼 호출하면 새로운 객체를 생성합니다. 또한 각 객체는 고유하다는 점을 강조해야 합니다. 즉, 각 객체는 생성된 다른 객체와 별개인 자체 데이터를 가지고 있습니다.

클래스에 의해 정의된 객체는 딕셔너리와 다소 유사합니다. 단지 약간 다른 구문을 사용합니다. 예를 들어, s['name'] 또는 s['price']를 쓰는 대신, 이제 s.names.price를 씁니다.

연습 문제 4.2: 메서드 추가하기 (Adding some Methods)

클래스를 사용하면 객체에 함수를 연결할 수 있습니다. 이것을 메서드라고 하며, 객체 내부에 저장된 데이터를 조작하는 함수입니다. Stock 객체에 cost()sell() 메서드를 추가합니다. 다음과 같이 작동해야 합니다.

>>> import stock
>>> s = stock.Stock('GOOG', 100, 490.10)
>>> s.cost()
49010.0
>>> s.shares
100
>>> s.sell(25)
>>> s.shares
75
>>> s.cost()
36757.5
>>>

연습 문제 4.3: 인스턴스 목록 만들기 (Creating a list of instances)

딕셔너리 목록에서 Stock 인스턴스 목록을 만들려면 다음 단계를 시도해 보세요. 그런 다음 총 비용을 계산합니다.

>>> import fileparse
>>> with open('portfolio.csv') as lines:
...     portdicts = fileparse.parse_csv(lines, select=['name','shares','price'], types=[str,int,float])
...
>>> portfolio = [ stock.Stock(d['name'], d['shares'], d['price']) for d in portdicts]
>>> portfolio
[<stock.Stock object at 0x10c9e2128>, <stock.Stock object at 0x10c9e2048>, <stock.Stock object at 0x10c9e2080>,
 <stock.Stock object at 0x10c9e25f8>, <stock.Stock object at 0x10c9e2630>, <stock.Stock object at 0x10ca6f748>,
 <stock.Stock object at 0x10ca6f7b8>]
>>> sum([s.cost() for s in portfolio])
44671.15
>>>

연습 문제 4.4: 클래스 사용하기 (Using your class)

report.py 프로그램의 read_portfolio() 함수를 수정하여 연습 문제 4.3 에서 보여준 것처럼 포트폴리오를 Stock 인스턴스 목록으로 읽도록 합니다. 그런 다음 report.pypcost.py의 모든 코드를 수정하여 딕셔너리 대신 Stock 인스턴스로 작동하도록 합니다.

힌트: 코드에 큰 변경을 할 필요는 없습니다. 주로 s['shares']와 같은 딕셔너리 접근을 s.shares로 변경하게 됩니다.

이전과 동일하게 함수를 실행할 수 있어야 합니다.

>>> import pcost
>>> pcost.portfolio_cost('portfolio.csv')
44671.15
>>> import report
>>> report.portfolio_report('portfolio.csv', 'prices.csv')
      Name     Shares      Price     Change
---------- ---------- ---------- ----------
        AA        100       9.22     -22.98
       IBM         50     106.28      15.18
       CAT        150      35.46     -47.98
      MSFT        200      20.89     -30.34
        GE         95      13.48     -26.89
      MSFT         50      20.89     -44.21
       IBM        100     106.28      35.84
>>>

요약 (Summary)

축하합니다! 클래스 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 기술을 향상시킬 수 있습니다.