简体   繁体   中英

Error with multiple class inheritance Python

import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objects as go # run "pip install plotly==4.9.0" in your terminal to install plotly
import yfinance as yf
import numpy as np
import ast

eurusd = yf.Ticker("EURUSD=X")
usd_to_eur = 1 / (eurusd.info["ask"])
eur_to_usd = 1 * eurusd.info["ask"]

class Asset:
    def __init__(self,name, ticker, amount):
        self.amount = amount
        self.name = name
        self.ticker = ticker
        self.price = yf.Ticker(self.ticker).info["regularMarketPrice"]

class Usd_asset(Asset):
    def __init__(self, name, ticker, amount, buy_price):
        super().__init__(name, ticker, amount)
        self.buy_price = buy_price
        self.buy_price_eur = [x * usd_to_eur for x in self.buy_price]
        self.price_usd = yf.Ticker(self.ticker).info["regularMarketPrice"]
        self.price_eur = self.price_usd * usd_to_eur

class Crypto(Asset):
    def __init__(self, name, ticker, amount):
        super().__init__(name, ticker, amount)
        print("crypto")


class Crypto_Usd(Crypto, Usd_asset):
    def __init__(self, name, ticker, amount, buy_price):
        Usd_asset.__init__(self, name = name, ticker = ticker, amount = amount, buy_price = buy_price)
        Crypto.__init__(self, name = name, ticker = ticker, amount = amount)
        print("crypto usd")

Whenever I run it, I get the following:

Attribute Error: Type object 'Usd_asset' has no attribute '_Crypto_Usd__init'

What am I doing wrong here?

My goal is to have a class which inherits both from Crypto and from Usd_asset. which in their turn both inherit from Asset.

In Python 3.8.6 I can't reproduce the error but I get an other strange behavior:

class Asset:
  def __init__(self, name):
    print("init Asset")
    self.name = name
class Usd_asset(Asset):
  def __init__(self, name):
    print("init Usd_asset")
    super().__init__(name)
    print("done Usd_asset")
class Crypto(Asset):
  def __init__(self, name):
    print("init Crypto", Crypto.__mro__)
    super().__init__(name)
    print("done Crypto")
class Crypto_Usd(Crypto, Usd_asset):
  def __init__(self, name):
    print("init Crypto_Usd")
    Usd_asset.__init__(self, name = name)
    Crypto.__init__(self, name = name)
    print("done Crypto_Usd")

print("\nCrypto('bar')")
x = Crypto('bar')
print("\nCrypto_Usd('foo')")
a = Crypto_Usd('foo')

The output:

Crypto('bar')
init Crypto (<class '__main__.Crypto'>, <class '__main__.Asset'>, <class 'object'>)
init Asset
done Crypto

Crypto_Usd('foo')
init Crypto_Usd
init Usd_asset
init Asset
done Usd_asset
init Crypto (<class '__main__.Crypto'>, <class '__main__.Asset'>, <class 'object'>)
init Usd_asset        ## <<<--- strange
init Asset
done Usd_asset
done Crypto
done Crypto_Usd

The problem is the calling of Usd_asset.__init__() inside the Crypto.__init__() method. The __mro__ shows that Asset is the only super class.

With the full code I get an Exception in Crypto.__init__()

__init__() missing 1 required positional argument: 'buy_price'

It tries to call Usd_asset.__init__()

Solution

Don't use super() in classes that are used in multiple inheritance. Or maybe never use super() because you don't know if the class will be used in multiple inheritance.

Always write the Class.method(self, arguments)

class Usd_asset(Asset):
    def __init__(self, name, ticker, amount, buy_price):
        Asset.__init__(self, name, ticker, amount)
        self.buy_price = buy_price
        self.buy_price_eur = [x * usd_to_eur for x in self.buy_price]
        self.price_usd = yf.Ticker(self.ticker).info["regularMarketPrice"]
        self.price_eur = self.price_usd * usd_to_eur

class Crypto(Asset):
    def __init__(self, name, ticker, amount):
        Asset.__init__(self, name, ticker, amount)
        print("crypto")

Edit

The reason super() in Crypto.__init__() chooses Usd_asset.__init__() is because super() or super(Crypto, self) uses self.__class__.__mro__ to find the first parent class of Crypto class.

In case self is instance of Crypto

self.__class__.__mro__ (<class '__main__.Crypto'>, <class '__main__.Asset'>, <class 'object'>)

Asset will be chosen.

In case self is instance of Crypto_Usd

self.__class__.__mro__ (<class '__main__.Crypto_Usd'>, <class '__main__.Crypto'>, <class '__main__.Usd_asset'>, <class '__main__.Asset'>, <class 'object'>)

Usd_asset will be chosen.

class Crypto(Asset):
  def __init__(self, name):
    print("init Crypto", Crypto.__mro__)
    print("self.__class__.__mro__", self.__class__.__mro__)
    super().__init__(name)
    print("done Crypto")

The __mro__ tuple does not show the multiple inheritance and thus creates this strange behavior.

因为当您使用super()时,您的实例是Crypto_Usd ,所以您没有按预期获得类Asset => 将调用super().__init(...)替换为Asset.__init__(self, ...)

import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objects as go # run "pip install plotly==4.9.0" in your terminal to install plotly
import yfinance as yf
import numpy as np
import ast

eurusd = yf.Ticker("EURUSD=X")
usd_to_eur = 1 / (eurusd.info["ask"])
eur_to_usd = 1 * eurusd.info["ask"]

class Asset:
    def __init__(self,name, ticker, amount):
        self.amount = amount
        self.name = name
        self.ticker = ticker
        self.price = yf.Ticker(self.ticker).info["regularMarketPrice"]

class Usd_asset(Asset):
    def __init__(self, name, ticker, amount, buy_price):
        super().__init__(name, ticker, amount)
        self.buy_price = buy_price
        self.buy_price_eur = [x * usd_to_eur for x in self.buy_price]
        self.price_usd = yf.Ticker(self.ticker).info["regularMarketPrice"]
        self.price_eur = self.price_usd * usd_to_eur

class Crypto(Asset):
    def __init__(self, name, ticker, amount):
        super().__init__(name, ticker, amount)
        print("crypto")


class Crypto_Usd(Crypto, Usd_asset):
    def __init__(self, name, ticker, amount, buy_price):
        Usd_asset.__init__(self, name = name, ticker = ticker, amount = amount, buy_price = buy_price)
        Crypto.__init__(self, name = name, ticker = ticker, amount = amount)
        print("crypto usd")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM