Python继承:从Base类转换为Derived类

时间:2015-04-14 06:22:23

标签: python inheritance

我仍然对Python很陌生,所以请耐心等待。这是我的问题:

我有一个基类,我们称之为体育游戏:

class Game:
    def __init__(self):
        self.home_team = None
        self.away_team = None

我为每项运动都有多个派生类,但我们以棒球为例:

class BaseballGame(Game):
    def __init__(self):
        self.home_pitcher = None
        self.away_pitcher = None

到目前为止一切都很好。但是我在一个单独的python模块中有另一个实用程序功能,它将生成并填充在该运动的给定日期内正在玩的所有游戏的列表。

def fetch_game_data:
    games = []
    games_found_online = code_that_fetches_online_games
    for online_game in games_found_online:
        new_game = Game()
        new_game.home_team = ...
        new_game.away_team = ...
        games.append(new_game)
    return games

使用BeautifulSoup进行大量解析显然要比这更复杂,但是你明白了。我的问题是这个函数返回一个Base类的列表,但我需要一个Derived类的列表。派生类将是调用此函数来填充列表并对其进行操作的类。我看到它的方式,我有两个选择:

  1. 我可以实现一个可怕的循环依赖,并让fetch_game_data函数了解所有派生类,并调用派生类构造函数而不是基类构造函数。派生类已经需要导入fetch_data模块,但是现在fetch_data模块必须导入所有派生类才能知道它们的构造函数。更糟糕的是,fetch_data模块不需要触及任何派生类字段 - 它只填充基类字段。循环依赖是JUST所以我可以创建对象。
    1. 我可以实现将基类游戏向下转换为派生类游戏(如BaseballGame)的代码。然后,当fetch_game_data函数返回所有游戏时,我可以将它们全部转换为Derived类对象并继续前进。不幸的是,我还没有看到如何实现这一点。我尝试更改变量,但随后代码会抱怨因为Derived类变量不存在。
  2. 我考虑的另一个选项,但很快就崩溃了,就是将现有的派生类对象列表发送到fetch_game_data函数中,而不是创建新的Game对象,它只会填充现有的对象。问题是我不知道我需要多少游戏对象。 fetch_game_data函数通过解析网页来确定需要多少游戏。我想我可以发送最大数量的游戏,但使用number_of_teams / 2,但如果棒球中有双头怎么办?这很快就崩溃了。我想我可以编写一个函数来获取游戏数据并返回当天的游戏数量。然后我可以填充一个Derived游戏列表,这些游戏的大小和发送量都会被填充。但我必须获取所有网页数据AGAIN并再解析它以填充列表。

    只有糟糕的选择!我希望到目前为止还有一个简单而优雅的解决方案。我愿意接受任何建议,包括重新设计,如果有意义的话。

    谢谢!

3 个答案:

答案 0 :(得分:0)

我正在从c ++移植现有代码,并且遇到了类似的问题。

我有一个通用类X并输入了特定于类的类,例如XInt,XStr等。这些类之间的区别不仅仅是值的类型。在c ++中,这很容易:我有virtual X::compare(X const& other)

在XInt中被覆盖。在覆盖方法中,我首先处理“ other”不是XInt的情况,然后执行static_cast<XInt const&>(other)

在python中显然是不可能的。所以这是我的解决方案。我添加了一个非虚拟的非公共函数来与XInt进行实际比较,并且没有注释参数的类型:

def _compare(self, other) -> int:
     <do-actual-comparison>

def compare(self, other: X) -> int:
     <handle cases where other is not XInt>
     return self._compare_worker(other)

还没有测试它,但是mypy并没有抱怨,而且由于鸭子在python中键入,它似乎可以工作。也许类似的东西会为您工作。

答案 1 :(得分:0)

您可以在实例类启动后对其进行转换,请参见以下示例:


class A:
    def __repr__(self):
        return "class A"
    def convert(self):
        'convert A to B class'
        self.__class__ = B
    def hello(self):
        print('hello from A')
        
        
class B(A):
    ""
    def __repr__(self):
        return "class B"
            
    def hello(self):
        print('hello from B')
        

a = A()

print(a)
a.hello()
a.convert()
print(a)
a.hello()

# output:
>>> "class A"
>>> "hello from A"
>>> "class B"
>>> "hello from B"

对于您而言,可以在创建实例后将类Game转换为所需的任何子类。

答案 2 :(得分:-1)

Python无法将对象转换为另一个类(甚至是子类)。

创建游戏对象时必须使用具体类。它可以用工厂方法(例如create_game)完成,如下所示:

def create_game(online_game):
    if online_game.type == 'baseball':
        return BaseballGame()
    else:
        return Game()

def fetch_game_data:
    games = []
    games_found_online = code_that_fetches_online_games
    for online_game in games_found_online:
        new_game = create_game(online_game)
        new_game.home_team = ...
        new_game.away_team = ...
        games.append(new_game)
    return games