【问题标题】:Python how to pass class function from instance to another classPython如何将类函数从实例传递给另一个类
【发布时间】:2019-08-29 03:17:53
【问题描述】:

我有一个Player 类,它有许多属性来衡量它们的整体状态。我有第二类Character(类类型),它根据我的角色实例为我的玩家设置一些独特的配置。我遇到麻烦的地方是在玩家级别调用一个通用函数来衡量每个角色的独特里程碑目标。即检查每个玩家,看看他们是否已经达到了他们独特的里程碑 1。我最初尝试在初始化下使用一系列条件函数来做到这一点,但事实证明这在一个类中是不明智的,所以我把它移到了它的自己的单一功能。由于这样做,它显然会失败,因为函数正在检查的属性在父类 (Player) 中,而不是在定义函数的类 (Character) 中。

class Player:
    def __init__(self, player_num, name):
        self.character = Character(name)
        self.player_num = player_num
        self.name = name
        self.power = 0
        self.position = 1
        self.attributeLimit = 4
        self.attributes = []
        self.attachments = []
        self.collection = []
        self.visited = []
        self.setCharacterValues()
        self.ms1 = self.character.Milestone1 

        def setCharacterValues()
        #Loads Character instance data into the Player instance.

class Character:
    def __init__(self, name):
        self.attributes = []
        self.attachments = []
        self.collection = []
        self.visited = []
        self.name = name
        if name == 'char x':
            self.attributes = [1,2,3]
            #etc.
        #etc.

    def Milestone1(self):
        if self.name == 'char x':
            if self.power >= 20:
                return True
            else:
                return False
        if self.name == 'char y':
            if self.position >= 5:
                return True
            else:
                return False
        #etc

for i in players:
    if i.ms1():
        print('Passed')

现在我能想到的唯一解决方案是将函数从 Character 类移动到 Player 类。但这对我来说似乎与直觉相反,因为此功能正在衡量每个独特角色达到里程碑的能力。 感觉 将它留在字符下是合适的,我只是在某处遗漏了一个明显的步骤。有人可以帮忙吗?

【问题讨论】:

  • 为什么不使用继承呢?
  • 它是使用子类/继承解决的。谢谢!

标签: python class


【解决方案1】:

请发布回溯错误消息。我认为问题出在Milestone1() 你检查self.powerself.position 但self 指的是Character 的实例而不是Player,并且角色没有权力或职位属性。

以下是我能想到的 2 个修复:

  1. 继承:如果你让玩家成为角色的子类,那么玩家将拥有角色的所有属性,因此可以调用ms1()

    class Player(Character):
        def __init__(self, player_num, name):
            # self.character = Character(name)  <-- not needed
            # self.ms1 = self.character.Milestone1  <-- not needed
    
            # since Player is a subclass of Character,
            # use super to init & it already has name and Milestone1
            super().__init__(name)  # Py3 usage
            # super(Player, self).__init__(name)  # Py2 usage
    

    我在a simple example on repl.it 中对此进行了测试 它对我有用,按播放试试,输出是'n',然后是't'

    注意:in Python-2, the syntax for super is different than Python-3,您还必须提供子类Player 和实例self 作为参数。我在this sample repl.it using Python-2 中使用super(Player, self).__init__(name) 测试了继承,它也可以工作。

    另请注意:Python-2 classes should subclass object to create new-style classes

  2. 构图:修复Milestone1(),使其使用玩家作为参数,从而获得权力和位置

    class Character:
        # no change
    
        def Milestone1(self, player):
            if self.name == 'char x':
                if player.power >= 20:
                    return True
                else:
                    return False
    

    也更新Player,将播放器实例传递给Milestone1

    class Player:
        def __init__(self, player_num, name):
            self.character = Character(name)
    
            # self is the Player, lambda makes ms1 callable
            self.ms1 = lambda: self.character.Milestone1(self)
    

    虽然name 属性并没有真正使用,这似乎有点hacky,但我在this simple repl.it example 中测试过它也可以工作。

总的来说,我认为这是使用继承而不是组合的好机会。问问自己:

玩家是角色吗? (继承:#1)

玩家有角色吗? (组成:#2)

【讨论】:

  • 嗨,马克,我正在用我的手机回复,但我认为继承正是我期望解决这个问题的解决方案。今晚我会审查它。谢谢!
  • 这似乎在 Python3 上运行良好,但在 2.7 中运行我的脚本时,我不断收到此错误:(TypeError: must be type, not classobj) 从 line super().__init__(name)
  • 对不起Python-2, super is different,你得打电话给super(subclass, self).__init__(self, x, y, ...)
  • 但在 Python-2 中,您还应该将所有类子类化为 object,Python-3 解决了这个问题。我假设您使用的是 Python3,因为您没有在课程中使用 object例如 class Character(object): # do stuff
  • 请注意,上面对 Python-2 的 super 的评论中有错字。它应该说super(subclass, self).__init__(x, y, ...) __init__中没有self参数,只是在super中 - 哎呀!
【解决方案2】:

我建议在 Character 类中也初始化一个幂值,或者在 Character 类中创建一个泛型方法,然后在 Player 类中覆盖它。

【讨论】:

    【解决方案3】:

    您拥有的是一个容器类Player,它与Character 具有一对一的关系。您不想在游戏中发生任何事情之前复制角色的属性(例如 Player 中的 ms1,尤其是在 __init__ 期间。相反,只需在需要时从 Player 实例中访问该角色的属性检查他们:

    player = Player(player_num=42, name='Ivan')
    # do some stuff with `player` and `player.character` as the game progresses
    # then somewhere deep in the game...
    if player.character.ms1:
        print("Congratulations on achieving your first milestone!")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-25
      • 2016-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      相关资源
      最近更新 更多