2015-08-26 91 views
1

我有一个嵌套的类结构,当我实例化顶级类时,它将其他类的一些对象实例化为属性,并将那些其他类实例化为他们自己的属性。如何覆盖python中的类定义?

正如我发展我的代码,我想重写一个新的模块定义一个类(这将是对我来说,以避免破坏现有的功能在其他脚本中同时增加新功能的好方法)。

作为玩具例如,存在如下情况:我定义两个类,其中一个的另一,甲板和卡的列表的模块。当我实例化一个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)) 

我有另一种类型的卡,我想创建它们的甲板,于是我进口甲板到一个新的模块和新模块中定义一个新的卡类,但是当我实例露天平台,它已经从module_1.py卡

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但它用我的新卡班?

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

此外,我预计这是符合面向对象的范例。是吗?

回答

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 
+0

这是如何回答“具体问题”比帕特里克的答案或我删除的答案更?我想如果你认为OP不想修改'Deck'的代码。 – Cyphase

+0

@Cyphase好了,问题是“我怎样才能重写python中的类定义?”。这是你如何做到的。 – cdonts

+0

确实,这将覆盖Card类定义而不是修改Deck类,但是您应该提及它会使原始Card定义无法访问... –

4

制作卡片类的可选参数的甲板实例初始化默认为您最初的卡类,并通过传递你的第二个卡类的第二个参数,当你初始化你的新扑克牌覆盖它。

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

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

你的第二个模块将通过其卡类到甲板:

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] 
+0

另外,'self.index'应该是'tuple';)。 – Cyphase

+0

谢谢。这对于玩具问题是一个很好的解决方案。不幸的是我有一个更复杂的数据结构,所以命名空间体操更可取。对于这个实现,如果我要在底部替换一个类,我需要在每个级别中引用类定义。 –

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

这需要CardDeck之前,始发模块中的定义以后可以连接到课程中:

Deck.CardCls = Card 

所以,我觉得它更灵活的使用模式,如:

CardCls = self.CardCls or Card 

这样,类定义的模块中的顺序并不重要。如果Deck子类的实例有一个变量self.CardCls set(“truthy”值 - 如果将它设置为子类中的类级别变量,那么它将使用该值)。如果没有,它将使用与Deck基类在同一模块中定义的Card类。

+0

谢谢马特。我想重写类定义而不是传递类的原因是我想修改的列表在类结构中很深,所以我需要在开发时传递一堆类定义。我将编辑我的问题以添加该信息。 –

+0

@ S.Somomberg如果我明白你在问什么,你不能这样做。在模块中定义的类和函数使用该模块作为它们的名称空间。将类导入另一个模块并不意味着导入的类可以在第二个模块的名称空间中看到任何内容。如果你想覆盖查找,你必须用一个钩子来构造你的类,以便你可以告诉它使用一个替代对象(类,函数,无论),然后使用钩子。唯一的选择就是改变原来的命名空间,正如cdonts所暗示的那样。 –