【问题标题】:How do I properly use a function under a class?如何正确使用类下的函数?
【发布时间】:2019-10-25 19:24:34
【问题描述】:

我目前正在学习 Python。由于我是 OO(面向对象)编程的忠实粉丝,显然在 Python 中应用它并不难。但是当我尝试它时,它似乎与 C# 非常不同。

正如您在下面看到的,我正在尝试创建一个具有三个属性 Id、Hp 和 Mana 的角色类。分数是通过将 Hp 和 Mana 相加然后乘以 10 来计算的。

如您所见,在将 MyChar 定义为 id=10 hp=100 mana=100 之后,我期待 MyChar.Score 为 (100+100)*10,即 2000,但奇怪的是,它说:

bound method Character.Score of <__main__.Character object at 0x0000021B17DD1F60> 作为print(MyChar.Score) 的结果。

我该如何解决这个问题?

这是我的代码:

class Character:

    def __init__(self, Id, Hp, Mana):
        self.Id = Id;
        self.Hp = Hp;
        self.Mana = Mana;


    def Score(self):
        return (self.Hp + self.Mana)*10;

MyChar = Character(10, 100, 100);

print(MyChar.Score)

【问题讨论】:

  • 分数不是一个属性而是一个成员函数,像 print(MyChar.Score()) 一样调用它
  • @Kunal 它可能不过。这在将函数/方法传递给高阶函数(如 map/filter)时特别有用。 :)
  • 我发誓这种函数也称为方法,在 C# 中使用() 调用。
  • @KunalMukherjee 是的 - MyChar.Score() 表达式 first 解析 MyChar 对象上的 "Score" 属性(产生一个方法对象),then 在其上应用调用运算符(括号)。
  • @Goyo 您可能想了解一下 Python “方法”到底是什么:wiki.python.org/moin/FromFunctionToMethod - 作为一般规则,Python 的对象模型与 C# 的对象模型大不相同,所以虽然您会发现类、实例、属性、方法等相同的基本概念,您将不会与 C# 实现这些概念的方式进行 1:1 映射。

标签: python python-3.x


【解决方案1】:

如果你想像 C# 中的属性一样使用它,请使用@property 装饰函数,如下所示:

class Character:

    def __init__(self,Id,Hp,Mana):
        self.Id=Id;
        self.Hp=Hp;
        self.Mana=Mana;

    @property
    def Score(self):
        return (self.Hp+self.Mana)*10;

MyChar=Character(10,100,100);

print(MyChar.Score)

所以你不必像函数一样调用它。

有关属性的更高级用法(例如,还有一个 setter 函数),请参阅官方文档:https://docs.python.org/3/library/functions.html#property

【讨论】:

  • 虽然这是一个不错的建议,但它并不能真正回答 OP 的问题。
  • @brunodesthuilliers 我不明白。这在 OP 的示例中添加了一行(装饰器)并解决了问题。这怎么不回答问题?
  • @Teepeemm OP 询问为什么表达式 MyChar.Score 没有评估 Score 方法的返回值,而不是如何使其成为计算属性而不是方法。
  • 虽然标题确实询问了如何使用该功能,但正文只是询问“我该如何解决这个问题?”似乎MyChar.Score()@property def Score 会导致 print 语句按照 OP 的要求工作,这种方法的优点是可以将更多逻辑封装到类定义中。
【解决方案2】:

tl;dr

通过调用它像任何其他函数一样使用它:print(MyChar.Score())(注意额外的一对括号)。


正如你所说的,MyChar.Score 是一个“类下的函数”(又名method)。因此,只需通过调用它来像任何其他函数一样使用它:用一对括号作为后缀。

print(MyChar.Score())
#                 ^^

没有调用,只需执行print(MyChar.Score) 打印<bound method blah blah>,即方法的非正式字符串表示。 print 函数在内部调用 __str__() 魔术方法(或 __repr__(),如果前者未定义)。因此,以下打印等效行:

print(MyChar.Score.__str__())
print(str(MyChar.Score))
print(MyChar.Score.__repr__())
print(repr(MyChar.Score))

在 Python 中,函数是 first-class citizens,因此它们是对象并具有 __str__()__repr__() 方法。

【讨论】:

  • 没有括号,你就没有调用这个函数。相反,您打印的是函数本身的表示,它是称为“Score”的字符类的一个方法。
【解决方案3】:

在 Python 中,一切都是对象,包括类、函数和方法,因此 MyChar.Score(不带括号)仅解析 MyChar 对象上的 Score 属性。这会产生一个method 对象,它恰好是一个可调用对象(一个实现__call__ 特殊方法的对象)。然后,您必须应用调用运算符(括号)来实际调用它。

您可能需要在Python's object model 上查看官方文档以了解更多信息。

【讨论】:

    【解决方案4】:
    class Character(object):
        def __init__(self):
            print ('Starting')
    
        def method(self):
            print ('This is a method()')
    ch = Character()
    
    '''When we don't add the bracket after the method call, it would lead to a method bound error as in your case'''
    print (ch.method)
    '''This can be solved by doing the following line'''
    ch.method()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-19
      • 1970-01-01
      • 1970-01-01
      • 2014-04-22
      • 2021-02-03
      • 2011-12-22
      相关资源
      最近更新 更多