【问题标题】:When is it best to use a class in Python?什么时候最好在 Python 中使用类?
【发布时间】:2012-05-24 12:41:31
【问题描述】:

我是 python 和一般编程的新手,所以非常感谢任何关于这一点的澄清。

例如在下面的代码中:

    #Using a class
class Monster(object): 
    def __init__(self, level, damage, duration): 
        print self
        self.level = level
        self.damage = damage
        self.duration = duration

    def fight(self):
        print self 
        print "The monster's level is ", self.level
        print "The monster's damage is ", self.damage
        print "The attack duration is ", self.duration

    def sleep(self): 
        print "The monster is tired and decides to rest."

x = Monster(1, 2, 3)
y = Monster(2, 3, 4)
x.fight()
y.fight()
    y.sleep() 

   #just using a function
def fight_func(level, damage, duration):
    print "The monster's level is ", level
    print "The monster's damage is ", damage
    print "The attack duration is ", duration

fight_func(1, 2, 3)
fight_func(5,3,4)

纯函数版本看起来更干净,结果也一样。

是您可以在对象上创建和调用许多方法的类的主要值,例如打架还是睡觉?

【问题讨论】:

标签: python oop class function


【解决方案1】:

你的例子相当简单。

在一个更完整的示例中,战斗不仅会显示当前状态 - 它还会修改该状态。你的怪物可能会受伤,这会改变它的生命值和士气。这个状态必须存储在某个地方。如果你使用一个类,添加实例变量来存储这个状态是很自然的。

仅使用函数会更难找到存储状态的好地方。

【讨论】:

  • 阅读本文以获得更多见解:mitpress.mit.edu/sicp/full-text/book/book.html
  • @Yoel:虽然我建议任何对计算感兴趣的人阅读 SICP,但在这种情况下我几乎看不到它的价值。它教授的是函数式编程风格,而不是 OOP。
  • Mark 建议如果fight_func 需要跟踪战斗状态,那么创建一个在内部保持战斗状态的战斗管理器类将是一个好主意。另一方面,如果唯一的状态是对怪物造成的伤害,那么你真的不需要它。
  • 是的,但它确实解决了 @MarkByers 和 OP 遇到的问题,即状态在编程、函数式和 oop 中的工作方式
  • @Yoel Python 有一些用于函数式使用的设施,但称其为函数式语言有点牵强。
【解决方案2】:

你的例子不是特别有趣——它只是打印了三个数字。你不需要类,甚至不需要一个函数(真的)来做到这一点。

但是,如果您需要编写一个程序来同时跟踪两个不同的怪物、了解它们的健康状况、区分它们的战斗能力等等,那么您可以看到将每个怪物封装在一个单独的怪物实例。

【讨论】:

  • 我想我必须稍后再举一个更好的例子。谢谢你的解释——现在我开始明白了。 :)
【解决方案3】:

我的怪物呢?他可以与另一个怪物战斗!大概你的功能怪物无法做到这一点;-)

class Monster(object): 
    def __init__(self, level, damage, duration): 
        self.level    = level
        self.damage   = damage
        self.duration = duration
    def fight(self, enemy):
        if not isinstance(enemy, Monster) :
            print "The enemy is not a monster, so I can't fight it."
            return None
        else :
            print "Starting fighting"
        print "My monster's level is ", self.level
        print "My monster's damage is ", self.damage
        print "My monster's attack duration is ", self.duration
        print "The enemy's level is ", enemy.level
        print "The enemy's damage is ", enemy.damage
        print "The enemy's attack duration is ", enemy.duration

        result_of_fight = 3.*(self.level    - enemy.level)  + \
                          2.*(self.damage   - enemy.damage) + \
                          1.*(self.duration - enemy.duration)
        if result_of_fight > 0 :
            print "My monster wins the brutal battle"
        elif result_of_fight < 0 :
            print "My monster is defeated by the enemy"
        else :
            print "The two monsters both retreat for a draw"
        return result_of_fight
    def sleep(self, days): 
        print "The monster is tired and decides to rest for %3d days" % days
        self.level    += 3.0 * days
        self.damage   += 2.0 * days
        self.duration += 2.0 * days
x = Monster(1, 2, 3)
y = Monster(2, 3, 4)
x.fight(y)
x.sleep(10) 

所以:

Starting fighting
My monster's level is  1
My monster's damage is  2
My monster's attack duration is  3
The enemy's level is  2
The enemy's damage is  3
The enemy's attack duration is  4
My monster is defeated by the enemy
The monster is tired and decides to rest for  10 days

【讨论】:

  • 哇,非常感谢分享一个更充实的例子。超级有助于通读。我不熟悉 %3d 格式。你为什么使用它而不仅仅是 %d?
  • %3d 有点细微差别,它只强加了 3 位数的最小字段宽度,因此 days 的多个输出低于 1000 将被对齐。
  • 嗯,好的。谢谢你。还有一个问题,如果你愿意的话:你为什么决定在这个代码块中乘以减法运算的结果? result_of_fight = 3.*(self.level - enemy.level) + \ 2.*(self.damage - enemy.damage) + \ 1.*(self.duration - enemy.duration)
  • 啊,那也很麻烦,也很随意。我想逐步增加持续时间、伤害和等级的权重,以确定战斗结果。
  • 有道理。再次感谢你。 :)
【解决方案4】:

这是一个比您的代码更通用的答案,但是当您需要时,类很有用:

  • 在特定功能之间安全地共享状态

    类提供封装以避免污染全局命名空间 只需要在几个函数之间共享的变量。您不希望有人使用您的代码来覆盖您的所有函数都在使用的变量 - 您总是希望能够尽可能地控制访问。

    类可以被实例化,并且具有相同变量的多个独立副本,它们根本不共享,同时只需要很少的代码使用。

    当您需要对一个函数和变量集合与另一个函数和变量集合之间的交互进行建模时,即当您需要对对象建模时,它们是合适的。为没有状态的单个函数定义一个类坦率地说是浪费代码。

  • 提供运算符重载或为某些类型定义特定特征

    是什么使intstringtuples 可散列(可用作字典中的键或插入set),而lists 和dicts 不是?

    答案:这些原始类型的基类实现了magic method__hash__,这使得Python 编译器能够在运行时动态计算哈希值。

    什么允许+ 运算符重载,以便5 + 2 = 7 用于ints 而's' + 'a' = 'sa' 用于字符串?

    答案:这些类型的基类定义了它们自己的__add__ 方法,让您可以准确定义类的两个成员之间的加法是如何进行的。

    所有用户定义的类都可以实现这些方法。它们有很好的用例:更大的数学库——numpy、scipy 和 pandas——通过定义这些神奇的方法来大量使用运算符重载,为您提供有用的对象来处理数据。类是在 Python 中实现这些特征和属性的唯一方法。

不满足上述条件时,类不优于函数。

使用类以合理的方式组合有意义的函数和变量,或赋予对象特殊属性。其他的都是多余的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多