내장 메서드 데코레이터 소개

Beginner

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

소개

이 섹션에서는 메서드 정의와 함께 사용되는 몇 가지 내장 데코레이터 (decorator) 에 대해 설명합니다.

사전 정의된 데코레이터 (Predefined Decorators)

클래스 정의에서 특별한 종류의 메서드를 지정하는 데 사용되는 사전 정의된 데코레이터가 있습니다.

class Foo:
    def bar(self,a):
        ...

    @staticmethod
    def spam(a):
        ...

    @classmethod
    def grok(cls,a):
        ...

    @property
    def name(self):
        ...

하나씩 살펴보겠습니다.

정적 메서드 (Static Methods)

@staticmethod는 소위 정적 클래스 메서드 (C++/Java 에서) 를 정의하는 데 사용됩니다. 정적 메서드는 클래스의 일부이지만 인스턴스에 대해 작동하지 않는 함수입니다.

class Foo(object):
    @staticmethod
    def bar(x):
        print('x =', x)

>>> Foo.bar(2) ## x=2
>>>

정적 메서드는 때때로 클래스에 대한 내부 지원 코드를 구현하는 데 사용됩니다. 예를 들어, 생성된 인스턴스 (메모리 관리, 시스템 리소스, 지속성, 잠금 등) 를 관리하는 데 도움이 되는 코드입니다. 특정 디자인 패턴 (여기서는 논의하지 않음) 에서도 사용됩니다.

클래스 메서드 (Class Methods)

@classmethod는 클래스 메서드를 정의하는 데 사용됩니다. 클래스 메서드는 인스턴스 대신 클래스 객체를 첫 번째 매개변수로 받습니다.

class Foo:
    def bar(self):
        print(self)
    @classmethod
    def spam(cls):
        print(cls)

>>> f = Foo()
>>> f.bar()
<__main__.Foo object at 0x971690>   ## The instance `f`
>>> Foo.spam()
<class '__main__.Foo'>              ## The class `Foo`
>>>

클래스 메서드는 대체 생성자를 정의하는 도구로 가장 자주 사용됩니다.

class Date:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
    @classmethod
    def today(cls):
        ## Notice how the class is passed as an argument
        tm = time.localtime()
        ## And used to create a new instance
        return cls(tm.tm_year, tm.tm_mon, tm.tm_mday)

d = Date.today()

클래스 메서드는 상속과 같은 기능으로 몇 가지 까다로운 문제를 해결합니다.

class Date:
    ...
    @classmethod
    def today(cls):
        ## Gets the correct class (e.g. `NewDate`)
        tm = time.localtime()
        return cls(tm.tm_year, tm.tm_mon, tm.tm_mday)

class NewDate(Date):
    ...

d = NewDate.today()

연습 문제 7.11: 실전에서의 클래스 메서드

report.pyportfolio.py 파일에서 Portfolio 객체의 생성은 약간 혼란스럽습니다. 예를 들어, report.py 프로그램에는 다음과 같은 코드가 있습니다.

def read_portfolio(filename, **opts):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and price.
    '''
    with open(filename) as lines:
        portdicts = fileparse.parse_csv(lines,
                                        select=['name','shares','price'],
                                        types=[str,int,float],
                                        **opts)

    portfolio = [ Stock(**d) for d in portdicts ]
    return Portfolio(portfolio)

그리고 portfolio.py 파일은 다음과 같이 이상한 초기자를 사용하여 Portfolio()를 정의합니다.

class Portfolio:
    def __init__(self, holdings):
        self._holdings = holdings
    ...

솔직히 말해서, 코드 분산 때문에 책임의 연쇄가 다소 혼란스럽습니다. Portfolio 클래스가 Stock 인스턴스 목록을 포함해야 한다면, 클래스를 좀 더 명확하게 변경해야 할 수 있습니다. 다음과 같이:

## portfolio.py

import stock

class Portfolio:
    def __init__(self):
        self._holdings = []

    def append(self, holding):
        if not isinstance(holding, stock.Stock):
            raise TypeError('Expected a Stock instance')
        self._holdings.append(holding)
    ...

CSV 파일에서 포트폴리오를 읽으려면 클래스 메서드를 만들 수 있습니다.

## portfolio.py

import fileparse
import stock

class Portfolio:
    def __init__(self):
        self._holdings = []

    def append(self, holding):
        if not isinstance(holding, stock.Stock):
            raise TypeError('Expected a Stock instance')
        self._holdings.append(holding)

    @classmethod
    def from_csv(cls, lines, **opts):
        self = cls()
        portdicts = fileparse.parse_csv(lines,
                                        select=['name','shares','price'],
                                        types=[str,int,float],
                                        **opts)

        for d in portdicts:
            self.append(stock.Stock(**d))

        return self

이 새로운 Portfolio 클래스를 사용하려면 다음과 같은 코드를 작성할 수 있습니다.

>>> from portfolio import Portfolio
>>> with open('portfolio.csv') as lines:
...     port = Portfolio.from_csv(lines)
...
>>>

Portfolio 클래스에 이러한 변경 사항을 적용하고 클래스 메서드를 사용하도록 report.py 코드를 수정하십시오.

요약

축하합니다! 데코레이터 메서드 (Decorated Methods) 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 실력을 향상시킬 수 있습니다.