Python ООП манипулируя двумя объектами в одном методе - PullRequest
1 голос
/ 06 июля 2019

Я новичок в Python, пытаюсь понять ООП.В моей программе я хочу, чтобы пользователь мог покупать и продавать акции, но я изо всех сил пытаюсь реализовать эту функцию.Извините, если проблема тривиальна.

Класс пользователя + один его объект

class User:
    def __init__(self, name, budget=None, stocks=None):
        self.name = name
        self.budget = budget or 1000 
        self.stocks = stocks or 0

    def sell_stock(self):
        if self.stocks != 0:
            self.stocks -= 1

    def buy_stock(self):
        self.stocks += 1


u1 = User("Karin", stocks=9)

Класс запасов + один его объект

class Stock:
    def __init__(self, price, name, availability=None):
        self.price = price
        self.name = name
        self.availability = availability or 1


s1 = Stock("200", "Netflix")

Я хочу написать метод с именем buy_stock (), который будет выполнять следующее:

  • u1.budget - s1.price
  • u1.stocks + = 1
  • s1.availability - = 1
  • покажет цену и название акции, которую купил пользователь, поэтому я увижу сообщение f "{Karin}купил {Netflix} акции за {200} долларов. "

Ответы [ 6 ]

2 голосов
/ 06 июля 2019
class Stock:
    def __init__(self, price, name, availability=1):
        self.price = price
        self.name = name
        self.availability = availability

class User:
    def __init__(self, name, budget=1000,):
        self.name = name
        self.budget = budget 
        self.stocks = []

    def sell_stock(self, stock):
        try:
            self.stocks.remove(stock)
            stock.availability += 1
            self.budget += stock.price
            print('{} has sold {} stock for {} dollars'.format(self.name, stock.name, stock.price))

        except:
          pass

    def buy_stock(self, stock):
        if self.budget - stock.price >= 0 and stock.availability >= 1:
            self.stocks.append(stock)
            stock.availability -= 1
            self.budget -= stock.price
            print('{} has bought {} stock for {} dollars'.format(self.name, stock.name, stock.price))

s1 = Stock(200, "Netflix")
s2 = Stock(300, "SomeStock", availability=2)

u1 = User("Karin", budget=10000)
u1.buy_stock(s2)
u1.sell_stock(s2)

u2 = User("Sam")
u2.buy_stock(s2)
u2.buy_stock(s1) 

вывод:

Karin has bought SomeStock stock for 300 dollars
Karin has sold SomeStock stock for 300 dollars
Sam has bought SomeStock stock for 300 dollars
Sam has bought Netflix stock for 200 dollars

Когда вы покупаете предмет, вы должны убедиться, что он доступен, и у вас есть бюджет для него. Я удалил стандартный конструктор из конструктора, чтобы избежать репарации и иметь только один источник логики buy_stock. И последнее замечание: вам не нужен ключ or, так как вы можете установить значения по умолчанию в конструкторе.

1 голос
/ 06 июля 2019

Может быть, что-то вроде этого (я действительно не возился с переменной экземпляра «stocks» в классе «User». Я бы, возможно, отказался от этого и поддержал бы список объектов Stock вместо этого (ваш счет акций был бы просто длина этого списка)):

class User:

    def __init__(self, name, budget=1000, stocks=0):
        self.name = name
        self.budget = budget
        self.stocks = stocks

    def sell_stock(self):
        if self.stocks:
            self.stocks -= 1

    def buy_stock(self, stock, quantity=1):
        try:
            price = stock.request(quantity)
        except RuntimeError as error:
            raise error
        else:
            self.budget -= price
            self.stocks += quantity
            print(f"{self.name} bought ${price} worth of {stock.name} stocks")

class Stock:

    def __init__(self, name, price, quantity_available=1):
        self.name = name
        self.price = price
        self.quantity_available = quantity_available

    def isAvailable(self):
        return self.quantity_available > 0

    def request(self, quantity_requested):
        if not self.isAvailable():
            raise RuntimeError(f"No more {self.name} stocks available")
        elif self.quantity_available < quantity_requested:
            raise RuntimeError(f"Requested too many {self.name} stocks")
        else:
            self.quantity_available -= quantity_requested
            return self.price * quantity_requested

def main():

    user = User("Karin")

    stock = Stock("Netflix", 200, quantity_available=6)

    user.buy_stock(stock, quantity=3)
    user.buy_stock(stock, quantity=2)
    user.buy_stock(stock, quantity=1)

    user.buy_stock(stock, quantity=1)

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

Выход:

Karin bought $600 worth of Netflix stocks
Karin bought $400 worth of Netflix stocks
Karin bought $200 worth of Netflix stocks
RuntimeError: No more Netflix stocks available
1 голос
/ 06 июля 2019

Вам нужно 2 типа объектов: Portfolio и Stock.
A User может иметь несколько Portfolio, и в примере представлено только его именем.

Для более сложной модели вы также можете смоделировать Transactions как объекты; Вам также нужно будет обрабатывать колебания цен акций, комиссий и других расходов.

Вот упрощенный пример, который демонстрирует, как объекты взаимодействуют друг с другом:

class Stock:

    def __init__(self, ticker, price):
        assert price > 0
        self.ticker = ticker
        self.price = price

    def __hash__(self):
        return hash(self.ticker)

    def __str__(self):
        return self.ticker + ', $' + str(self.price) + ':'


class Portfolio:

    def __init__(self, owner):
        self.owner = owner
        self.cash = 0
        self.stocks = {}   # a mapping of Stock --> quantity

    def buy(self, stock, quantity):
        if self.cash < stock.price * quantity:
            print('Not enough cash to purchase ', quantity, stock)
        else:
            self.cash -= stock.price * quantity
            try:
                self.stocks[stock] += quantity
            except KeyError:
                self.stocks[stock] = quantity

    def sell(self, stock, quantity):
        assert quantity > 0
        try:
            if self.stocks[stock] < quantity:
                print('Not enough', stock.ticker, 'inventory to sell', str(quantity), stock)
                return
            self.stocks[stock] -= quantity * stock.price
            self.cash += quantity * stock.price
        except KeyError:
            print('No', stock.ticker, 'inventory to sell')

    def __str__(self):
        res = [self.owner, "'s Portfolio:\n"]
        for stock, quantity in self.stocks.items():
            res += [str(stock), ' ', str(quantity), ' -> ', '$', str(quantity*stock.price), '\n']
        res += ['cash: ', '$', str(self.cash), '\n']
        return ''.join(res)

goog = Stock('GOOG', 325)
alibaba = Stock('ALI', 12)
apple = Stock('AAPL', 42)

pfl = Portfolio('Karin')
pfl.cash = 10000

pfl.buy(goog, 10)
pfl.buy(alibaba, 100)
pfl.sell(apple, 100)
pfl.buy(apple, 10000)
pfl.sell(goog, 10000)

print()
print(pfl)

выход:

No AAPL inventory to sell
Not enough cash to purchase  10000 AAPL, $42:
Not enough GOOG inventory to sell 10000 GOOG, $325:

Karin's Portfolio:
GOOG, $325: 10 -> $3250
ALI, $12: 100 -> $1200
cash: $5550
1 голос
/ 06 июля 2019

Я думаю, что это должно сделать это. Кроме того, измените тип данных вашей цены акций со строки на int (или выполните приведение типа позже)

class User:
    def __init__(self, name, budget=None, stocks=None):
        self.name = name
        self.budget = budget or 1000 
        self.stocks = stocks or 0

    def sell_stock(self):
        if self.stocks != 0:
            self.stocks -= 1

    def buy_stock(self, stock):
        self.budget - stock.price
        stock.availability -= 1
        self.stocks += 1
        print("{} has bought {} stock for {} dollars".format(self.name,stock.name,stock.price))

class Stock:
    def __init__(self, price, name, availability=None):
        self.price = price
        self.name = name
        self.availability = availability or 1


s1 = Stock(200, "Netflix")

u1 = User("Karin", stocks=9)

u1.buy_stock(s1)
1 голос
/ 06 июля 2019

Добро пожаловать в мир ООП:)

То, что вы пытаетесь сделать, довольно просто.Поскольку вы пытаетесь работать с двумя классами одновременно, это сигнал о том, что один из этих классов должен использоваться в качестве аргумента в функции.Т.е.

class Stock:
     # .... basic init function

     # we need a function to return the value
     # of this stock, and maybe take an argument
     # for how many shares we want to value
     # so let’s write a function to do that for us

     def get_value(self, number_of_shares=1):
         return (self.value * number_of_shares)

class User:
     #.... basic init function

     def buy_stock(self, stock, amount=1):
          total_value = stock.get_value(amount)
          self.budget = self.budget - total_value
          self.stocks = self.stocks + amount

          #display what happened
          print(“{} bought {} shares of {} for {}”.format(self.name, amount, stock.name, total_value))

Тогда на практике вы можете написать

Ввод:

# assuming Andrew is a user
# and my_stock is a stock worth $20 a share
Andrew.buy_stock(my_stock, 10)

Вывод:

Andrew bought 10 shares of my_stock for $200

Но в основном ответ наВаш вопрос состоит в том, чтобы передать аргумент, который вы ожидаете, что это класс, с которым вы хотите работать.Таким образом, вы можете манипулировать как объектом User, вызывающим метод, так и объектом Stock, передаваемым в метод.

1 голос
/ 06 июля 2019

Если подумать об этом в более реальном сценарии, у вас будет объект Marketplace, который содержит все акции, у которых другие пользователи могут покупать акции.
Таким образом, он будет довольно читабельным и масштабируемые в будущем для дальнейшего развития.

Marketplace может быть отдельным классом, словарем, содержащим другие стандартные объекты (как в примере ниже), или классом, который является соединителем с вашей базой данных (например, mongodb).
Какойодин из них зависит от проекта.

Для этого примера словарь - хорошее и элегантное решение, которое поможет вам:

class User:
    def __init__(self, name, budget=None, stocks=None):
        self.name = name
        self.budget = budget or 1000
        self.stocks = stocks or 0

    def __repr__(self):
        # returns a represantion of the object
        # so it's more informative of the state
        # of this object
        return "{} balance: {}".format(
            self.name,
            self.budget
        )

    def sells(self, stock_name, amount):
        # Increase my budget by the amount of stocks I'm selling 
        # multiplied by its price.
        self.budget += marketplace[stock_name].price * amount

        # Send the stocks back into the market and remove them
        # from my ownership
        marketplace[stock_name].availability += amount
        self.stocks -= amount


    def buys(self, stock, amount):
        # Lower my budget by the stock price 
        # multiplied by the amount of stock I'm buying

        marketplace[stock].availability -= amount
        self.budget -= marketplace[stock].price * amount

        # Print out the transaction
        print("{} has bought {} stock for {} dollars".format(
            self.name,
            stock,
            marketplace[stock].price * amount
        ))


class Stock:
    def __init__(self, price, name, availability=None):
        self.price = price
        self.name = name
        self.availability = availability or 1

# In production like environmnet, you would not do this but would keep in
# mongodb or some other sql/nosql database
# For this example, a kind of javascript dict logic would be alright to use
marketplace = {
    "Netflix": Stock(200, "Netflix", 100)
}

u1 = User("Karin", budget=1000, stocks=0)

u1.buys("Netflix", 10)
u1.sells("Netflix", 5)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...