多类继承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,amount,buy_price):
        super().__init__(name,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,amount):
        super().__init__(name,amount)
        print("crypto")


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

每次运行它,我都会得到以下信息:

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

我在做什么错了?

我的目标是要拥有一个既继承自Crypto又继承自Usd_asset的类。 两者都继承自Asset。

解决方法

在Python 3.8.6中,我无法重现该错误,但又出现了其他奇怪的行为:

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')

输出:

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 'object'>)
init Usd_asset        ## <<<--- strange
init Asset
done Usd_asset
done Crypto
done Crypto_Usd

问题是在Usd_asset.__init__()方法内调用Crypto.__init__()__mro__表明Asset是唯一的超类。

使用完整的代码,我在Crypto.__init__()中得到了异常

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

它尝试呼叫Usd_asset.__init__()

解决方案

请勿在用于多重继承的类中使用super()。或者也许永远不要使用super(),因为您不知道该类是否将用于多重继承。

总是写Class.method(self,arguments)

class Usd_asset(Asset):
    def __init__(self,name,ticker,amount,buy_price):
        Asset.__init__(self,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,amount):
        Asset.__init__(self,amount)
        print("crypto")

修改

super()中的Crypto.__init__()选择Usd_asset.__init__()的原因是因为super()super(Crypto,self)使用self.__class__.__mro__来找到{{ 1}}类。

如果Cryptoself的实例

Crypto

self.__class__.__mro__ (<class '__main__.Crypto'>,<class 'object'>) 将被选择。

如果Assetself的实例

Crypto_Usd

self.__class__.__mro__ (<class '__main__.Crypto_Usd'>,<class '__main__.Crypto'>,<class '__main__.Usd_asset'>,<class 'object'>) 将被选择。

Usd_asset

class Crypto(Asset): def __init__(self,Crypto.__mro__) print("self.__class__.__mro__",self.__class__.__mro__) super().__init__(name) print("done Crypto") 元组不显示多重继承,因此会产生这种奇怪的行为。

,

因为当您使用super()时您的实例是 Crypto_Usd ,您没有像预期的那样获得 Asset 类=>替换了调用{{1} }由super().__init(...)

,
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,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,buy_price):
        super().__init__(name,amount):
        super().__init__(name,amount)
        print("crypto")


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