Введение
В этом разделе рассматриваются несколько встроенных декораторов, которые используются в сочетании с определениями методов.
This tutorial is from open-source community. Access the source code
💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал
В этом разделе рассматриваются несколько встроенных декораторов, которые используются в сочетании с определениями методов.
Существуют предопределенные декораторы, которые используются для указания особых типов методов в определениях классов.
class Foo:
def bar(self,a):
...
@staticmethod
def spam(a):
...
@classmethod
def grok(cls,a):
...
@property
def name(self):
...
Рассмотрим их по порядку.
@staticmethod
используется для определения так называемых статических методов класса (из C++/Java). Статический метод - это функция, которая является частью класса, но которая не работает с экземплярами.
class Foo(object):
@staticmethod
def bar(x):
print('x =', x)
>>> Foo.bar(2) ## x=2
>>>
Статические методы иногда используются для реализации внутреннего вспомогательного кода для класса. Например, код для управления созданными экземплярами (управление памятью, системными ресурсами, сохранением данных, блокировками и т.д.). Они также используются в некоторых шаблонах проектирования (не рассматриваются здесь).
@classmethod
используется для определения методов класса. Метод класса - это метод, который получает объект класса в качестве первого параметра вместо экземпляра.
class Foo:
def bar(self):
print(self)
@classmethod
def spam(cls):
print(cls)
>>> f = Foo()
>>> f.bar()
<__main__.Foo object at 0x971690> ## Экземпляр `f`
>>> Foo.spam()
<class '__main__.Foo'> ## Класс `Foo`
>>>
Методы класса чаще всего используются в качестве инструмента для определения альтернативных конструкторов.
class Date:
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
@classmethod
def today(cls):
## Обратите внимание, как класс передается в качестве аргумента
tm = time.localtime()
## И используется для создания нового экземпляра
return cls(tm.tm_year, tm.tm_mon, tm.tm_mday)
d = Date.today()
Методы класса решают некоторые сложные проблемы с такими функциями, как наследование.
class Date:
...
@classmethod
def today(cls):
## Получает правильный класс (например, `NewDate`)
tm = time.localtime()
return cls(tm.tm_year, tm.tm_mon, tm.tm_mday)
class NewDate(Date):
...
d = NewDate.today()
В файлах report.py
и portfolio.py
создание объекта Portfolio
немного запутано. Например, в программе report.py
есть код такого вида:
def read_portfolio(filename, **opts):
'''
Считывает файл портфеля акций в список словарей с ключами
name, shares и 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
, чтобы использовать метод класса.
Поздравляем! Вы завершили лабораторную работу по Декорированным Методам. Вы можете практиковаться в более лабораторных работах в LabEx, чтобы улучшить свои навыки.