如何在python中覆盖类定义?

时间:2015-08-26 00:18:52

标签: python

我有一个嵌套的类结构,当我实例化顶级类时,它将一堆其他类的对象实例化为属性,并将那些其他类实例化为它们自己的属性。

在我开发代码时,我希望在新模块中覆盖类定义(这对我来说是一种很好的方法,可以避免在添加新功能时破坏其他脚本中的现有功能)。

作为一个玩具示例,有一个模块,我定义了两个类,其中一个有另一个列表,Deck和Card。当我实例化一个Deck对象时,它会实例化一个Card对象列表。

module_1.py

class Card(object):
    def __init__(self, suit, number):
        self.suit = suit
        self.number = number

class Deck(object):
    def __init__(self):
        suit_list = ['heart', 'diamond', 'club', 'spade']
        self.cards = []
        for suit in suit_list:
            for number in range(14):
                self.cards.append(Card(suit, number))

我有另一种类型的卡,我想制作那些卡片,所以我将Deck导入新模块并在新模块中定义一个新的Card类,但是当我实例化Deck时,它有来自module_1的卡片。吡啶

module_2.py

from module_1 import Deck

class Card(object):
    def __init__(self, suit, number):
        self.suit = suit
        self.number = number
        self.index = [suit, number]

if __name__ == '__main__':
    new_deck = Deck()
    print new_deck.cards[0]

输出:

>python module_2.py
<module_1.Card object at 0x000001>

我是否可以通过某种方式从module_1.py中使用我的Deck类,但让它使用我的新Card类?

传递类定义很麻烦,因为实际情况是深层嵌套的,我可能还想开发顶级对象中包含的其他类。

另外,我希望这与面向对象的范例一致。是吗?

3 个答案:

答案 0 :(得分:4)

使Card类成为Deck实例初始化程序的可选参数,默认为初始Card类,并在初始化新卡片组时通过传递第二个Card类的第二个参数来覆盖它。

编辑根据cyphase的建议,使名称更加Pythonic并使索引成为元组。

class Card(object):
    def __init__(self, suit, number):
        self.suit = suit
        self.number = number

class Deck(object):
    def __init__(self, card_type=Card):
        suit_list = ['heart', 'diamond', 'club', 'spade']
        self.cards = []
        for suit in suit_list:
            for number in range(14):
                self.cards.append(card_type(suit, number))

您的第二个模块会将其Card类传递到Deck:

from module_1 import Deck

class FancyCard(object):
    def __init__(self, suit, number):
        self.suit = suit
        self.number = number
        self.index = suit, number

if __name__ == '__main__':
    new_deck = Deck(FancyCard)
    print new_deck.cards[0]

答案 1 :(得分:0)

帕特里克的答案是推荐的方式。但是,回答你的具体问题,实际上是可能的。

import module_1

class Card(object):
    def __init__(self, suit, number):
        self.suit = suit
        self.number = number
        self.index = [suit, number]

if __name__ == '__main__':
    # Keep reference to the original Card class.
    original_card = module_1.Card
    # Replace with my custom Card class.
    module_1.Card = Card  
    new_deck = module_1.Deck()
    print new_deck.cards[0]
    # Restore.
    module_1.Card = original_card

答案 2 :(得分:0)

为了使相互关联的类的集合可以自定义,我不会硬编码类的代码中的类选择。相反,我会使用类变量来选择替代类。

# module 1

class Card(object):
    def __init__(self, suit, number):
        self.suit = suit
        self.number = number

class Deck(object):

    CardCls = None

    def __init__(self, card_type=Card):
        suit_list = ['heart', 'diamond', 'club', 'spade']
        self.cards = []
        CardCls = self.CardCls or Card
        for suit in suit_list:
            for number in range(14):
                self.cards.append(CardCls(suit, number))

# module 2
from module_1 import Deck

class NewCard(object):
    def __init__(self, suit, number):
        self.suit = suit
        self.number = number
        self.index = [suit, number]

class NewDeck(Deck):
    CardCls = NewCard

或者,您最初可以代之以Deck代码:

class Deck(object):

    CardCls = Card

    def __init__(self, card_type=Card):
        suit_list = ['heart', 'diamond', 'club', 'spade']
        self.cards = []
        for suit in suit_list:
            for number in range(14):
                self.cards.append(self.CardCls(suit, number))

但是这需要在原始模块中Card之前定义Deck,或者稍后将其连接到类中:

Deck.CardCls = Card

因此,我发现使用类似的模式更灵活:

CardCls = self.CardCls or Card

这样,模块中类定义的顺序无关紧要。如果所讨论的Deck子类的实例具有变量self.CardCls设置(“truthy”值 - 如果将其设置为子类中的类级变量,它将使用它)将使用那。如果没有,它将使用与Card基类相同的模块中定义的Deck类。