Концепции объектно-ориентированного проектирования Python

Я просто возвращаюсь к программированию после 20-летнего перерыва. Я думал, что Python выглядит довольно простым и мощным, поэтому я прошел онлайн-курс и немного почитал.

Сейчас я смотрю на несколько простых проектов, чтобы познакомиться с языком. Одной из проблем является понимание объектно-ориентированного программирования, которого не было, когда я в последний раз писал программу.

Мой первый проект состоял в том, чтобы прочитать файл данных, содержащий информацию о портфеле акций, выполнить некоторые расчеты по каждому из них и распечатать отчет. У меня это работает.

Так что теперь я смотрю на что-то более продвинутое, считываю данные и сохраняю их, а затем использую данные для предоставления ответов на интерактивные вопросы. Мой вопрос заключается в том, как хранить данные, чтобы к ним можно было легко получить доступ.

Моей первой мыслью было составить список списков, например,

companies = [ ['AMP', 1000, 2.50], ['ANZ', 2000, 17.00], ['BHP', 500, 54.30] ]

К этому можно легко получить доступ в циклах, но методы доступа не совсем дружелюбны - числа в качестве индексов вместо имен:

companyqty = companies[1][1]

Или для циклов:

for company in companies:
    if company[0] == 'BHP':
        companyqty = company[1]

Затем я подумал о словаре со значением в виде списка:

companies = {'AMP':[1000, 2.50], 'ANZ':[2000, 17.00], 'BHP':[500, 54.30] }
companyqty = companies['BHP'][0]

Это обеспечивает немедленный доступ к любой данной компании, но по-прежнему привязан к числовым индексам.

Поэтому мне интересно, как структурировать это объектно-ориентированным образом, чтобы иметь возможность хранить список компаний и все связанные данные и иметь удобный доступ к значениям. Все мои идеи до сих пор выглядят как списки или словари, как указано выше.

Или такая проблема не подходит для объектно-ориентированного подхода?

Спасибо


person David M    schedule 17.08.2013    source источник


Ответы (4)


Это прекрасная проблема для подхода ООП. Например, вы можете создать класс для определенного портфеля акций, который имеет атрибуты для названия компании, количества акций и цены акции. Вы можете дать ему полезные функции, такие как getValue. Вот пример реализации:

class Holding:
    def __init__(self, companyName, numShares, sharePrice):
        self.companyName = companyName
        self.numShares = numShares
        self.sharePrice = sharePrice
    def getValue(self):
        return self.numShares * self.sharePrice

portfolio = {'AMP':Holding('AMP', 1000, 2.5), 'ANZ':Holding('ANZ', 2000, 17.0), 'BHP':Holding('BHP', 500, 54.30)}

print portfolio['BHP'].sharePrice
# 54.3
print portfolio['AMP'].getValue()
# 2500.0

Вы можете получить доступ к атрибутам своих холдингов по имени атрибута. Вы можете перейти на следующий уровень и написать класс для портфеля, который может иметь такие атрибуты, как «holdingList» и «имя брокера», и функции, такие как «getTotalValue» и так далее.

person Brionius    schedule 17.08.2013

Следующим шагом может быть использование класса, созданного с помощью collections.namedtuple() factory:

from collections import namedtuple

Company = namedtuple('Company', 'quantity price')

companies = {'AMP': Company(1000, 2.50), 'ANZ': Company(2000, 17.00), 'BHP': Company(500, 54.30)}

companies['AMP'].quantity

Обратите внимание, что, как и объекты tuple, объекты, производные от namedtuple, неизменяемы. Вы не можете назначать атрибуты, вместо этого вы создаете новый объект.

Вам нужно будет переключиться на пользовательские классы только в том случае, если вам нужно добавить функциональность к вашим объектам; добавить методы, которые воздействуют на данные, связанные с объектом:

class Company(object):
    def __init__(self, quantity, price):
        self.quantity = quantity
        self.price = price

    def profit(self, newprice):
        return self.quantity * (newprice - self.price)
person Martijn Pieters    schedule 17.08.2013

вы также можете использовать вложенные словари:

companies =
   {
      'AMP': {'quantity':1000, 'price': 2.50},
      'ANZ': {'quantity':2000, 'price': 17.00},
      'BHP': {'quantity':500, 'price': 54.30}
   }

и получить к нему доступ, как:

companyqty = companies['BHP']['quantity']

вы даже можете определить дополнительные «свойства» для компании:

companies =
   {
      'AMP': {'quantity':1000, 'price': 2.50, 'foundation_date': '2013-01-01'},
      'ANZ': {'quantity':2000, 'price': 17.00},
      'BHP': {'quantity':500, 'price': 54.30, 'head': 'Jeffrey'}
   }
person Roman Pekar    schedule 17.08.2013

Несмотря на то, что в Python есть один и только один способ делать что-то, ответ на этот вопрос действительно зависит от того, что «можно легко получить».

Означает ли это, что программисту легко получить доступ к объекту и его атрибуту? Тогда лучший способ сделать Company экземпляром класса и предоставить атрибуты для цены, количества и т. д. Возможно, создание класса с именем Portfolio будет излишним, если только у вас не будет нетривиальной логики, кроме логики list или dict. Также можно сделать класс на основе словаря, тогда будет возможен доступ как по ключам, так и по атрибутам. Это то, что я бы назвал легко доступным. Взгляните на класс Storage инфраструктуры webpy: https://github.com/webpy/webpy/blob/master/web/utils.py#L52 в качестве примера.

Если «легкий доступ» означает, что некоторая сериализация или другая обработка данных будет выполняться сторонней библиотекой, то самый простой способ — использовать структуры данных, ожидаемые библиотекой. Например, формат JSON очень хорошо сопоставляется со списками и словарями Python (см. ответ Романа Пекара).

person Roman Susi    schedule 17.08.2013
comment
Я предполагаю, что на самом деле я имею в виду доступ таким образом, который сводит к минимуму возможность ошибок, в частности, используя числа для ссылки на поля (например, Компании [1] [1]). В моем первом упражнении я сделал это несколько раз. Я думаю, что все еще думаю о таких индексах, начинающихся с 1, а не с 0. Используя имена, я избегаю этой ситуации. - person David M; 18.08.2013
comment
Да, я даже не думал об использовании цифровых клавиш, потому что использование ключей или атрибутов заставляет формат нести свой контекст. Если по какой-то внешней причине нужно использовать позиции в списках или кортежах, то для позиций можно определить имена, например. компании[0][COMPANY_PRICE]. Именованные кортежи также упоминаются в одном из ответов. - person Roman Susi; 18.08.2013