【问题标题】:Python OOP manipulating two objects in one methodPython OOP 在一种方法中操作两个对象
【发布时间】:2019-07-07 00:28:36
【问题描述】:

我是 Python 新手,想了解 OOP。在我的程序中,我希望用户能够买卖股票,但我正在努力实现此功能。对不起,如果问题是微不足道的。

用户类+它的一个对象

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} 美元的股票。”

【问题讨论】:

  • 我认为用户拥有portfolio 的股票,而不仅仅是一个数字。您可能需要使用集合(如dictlist)来存储每种不同的类型(使用股票的name 作为唯一标识键)和用户拥有的数量。
  • 同意凯西。您可以对此模型进行改进,库存对象字典是个好主意。

标签: python oop


【解决方案1】:
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

当您购买商品时,您必须确保它是可用的并且您有预算。我从构造函数中删除了 stock 参数以避免重复,并且只有一个逻辑源 buy_stock。最后一点:您不需要 or 密钥,因为您可以在构造函数中设置默认值。

【讨论】:

    【解决方案2】:

    欢迎来到 OOP 的世界 :)

    您要做的事情相当简单。由于您尝试同时使用两个类,这表明其中一个类应该用作函数中的参数。即

    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
    

    但基本上,您的问题的答案是传递一个您希望成为您想要使用的类的参数。因此,您既可以操作调用该方法的用户对象,也可以操作传递给该方法的库存对象。

    【讨论】:

      【解决方案3】:

      我认为应该这样做。另外,将股票价格的数据类型从字符串更改为 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)
      

      【讨论】:

        【解决方案4】:

        要在更真实的场景中考虑它,您将拥有一个 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)
        

        【讨论】:

        • 感谢您的解决方案。这非常符合我最初的逻辑。我想创建将从 User 和 Stock 继承的 Market 类,以便我可以操纵所有局部变量,但我不确定这是否是创建另一个类的明智之举
        【解决方案5】:

        可能是这样的(我并没有真正弄乱“用户”类中的“股票”实例变量。我可能会放弃它并改为维护一个股票对象列表(您的股票数量只是该列表的长度)):

        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
        

        【讨论】:

          【解决方案6】:

          您需要两种类型的对象:PortfolioStock
          一个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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-06-18
            • 1970-01-01
            • 2021-04-28
            • 2022-12-14
            相关资源
            最近更新 更多