【问题标题】:instantiate python object immediately after its class definition在类定义之后立即实例化 python 对象
【发布时间】:2013-07-19 04:04:16
【问题描述】:

在一个大型python项目(openerp)中我多次遇到以下模式:

在一个模块中,定义了一个类及其方法。然后,在同一个模块中,在类定义之后立即实例化该类的一个实例,然后从其他模块调用该实例。

# in module_A.py:
class ClassA(object):

    def __init__(self, default="Hello world!"):
        self.default = default 

    def my_method(self, data):
        print self.default
        print data

object_a = ClassA()

在我看来,将方法定义为模块函数看起来更简单,没有类查找重载:

# in module_B.py:

default = "Hello world!"

def my_method(data):
    print default
    print data

从其他模块看,用法很相似:

from module_a import object_a as prefix
prefix.my_method("I'm so objective!")

对比:

import module_b as prefix
prefix.my_method("I'm so modular!")

是否有任何理由更喜欢模式 A 而不是模式 B?还是模式 B 更 Pythonic?

【问题讨论】:

  • youtube.com/… 没有回答您的问题,但这可能会让您感兴趣。
  • 正如你提到的 OpenERP,这是为不是 OpenERP 模型的类找到的,但对 OpenERP 模型不这样做。在 OpenERP

标签: python openerp instantiation python-module


【解决方案1】:

有时,您希望不同的客户端能够以不同的设置使用您的模块,这样它们就不会相互冲突。例如,Python 的random 模块提供了一堆随机数生成函数,这些函数实际上是隐藏的Random 实例的绑定方法。大多数用户不太关心什么算法生成他们的随机数,或者其他模块是否会要求随机数会改变序列。但是,关心的用户可以获取自己的Random 对象并生成随机数序列,而不会受到其他模块要求随机数的影响。

有时,现在全球性的东西可能并不总是全球性的。例如,如果您正在开发行星规模的 RTS,您可能有一个带有一个实例的 Planet 类,因为战斗只发生在一个行星上。然而,你不想排除建造类似行星湮灭的可能性,战斗跨越整个太阳系,并将灭绝事件的小行星作为超级武器投放。如果你摆脱了Planet 类并将其方法和属性设置为模块级,那么以后再返回并添加更多行星将会更加困难。

有时,让对象而不是模块来做事更具可读性。例如,假设模块joebob 定义了两个对象evil_overlord_bobgood_guy_joe

class Bob(object):
    def slaughter_everything(self):
        print "Muahahaha! Die for my amusement!"
class Joe(object):
    def stop_bob(self):
        print "I won't let you hurt those innocents!"
evil_overlord_bob = Bob()
good_guy_joe = Joe()

假设 Bob 和 Joe 是非常独特的人。您想创建另一个对象,例如 Bob 或 Joe,这是不可想象的。在这种情况下,您可以将 slaughter_everythingstop_bob 移动到模块级别,并完全摆脱 Bob 和 Joe 类和对象。但是,那你会写

joebob.slaughter_everything()
joebob.stop_bob()

如果你能说出来,事情就更清楚了

evil_overlord_bob.slaughter_everything()
good_guy_joe.stop_bob()

即使你永远不需要实例化 Bob 的同样邪恶的孪生兄弟 greg_the_fleshripper

【讨论】:

  • 所以你的主要论点是类比模块更可重用。另一方面,Josay 链接的视频(对问题的评论)反对这是过早实施的一种形式。
  • goodguy/badguy 示例可以很容易地以模式 B 风格编写为两个独立的模块。
  • @QuantMetropolis:我不知道在你的情况下这些课程是否是个好主意。我不知道您正在查看的代码或系统的设计。我只是给出了一些例子,你可能会合理地更喜欢具有单个实例的类而不是模块级函数和状态。
  • 虽然您可以将 Bob 和 Joe 实现为两个模块,但它们在逻辑上非常紧密地组合在一起。将它们放在单独的模块中将需要两个导入,因为作为一个依赖项更有意义,并且将 Bob 用<module 'bob' from '/path/to/bob'> 表示比用<joebob.Bob object at 0xabcdefab> 表示仍然不太容易理解。此外,您可能会在 bobjoe 模块中进行循环导入,而没有人想要这样。
【解决方案2】:

除了其他好处之外,使用类还允许您对实例使用自省,而这是函数无法做到的。

以更一般的方式,这两种方法都是“pythonic”。使用其中一个真的取决于项目的类型(小/大,带/不带 GUI,...)

【讨论】:

  • 嗯,你可以对模块进行自省,这相当于模式 B 中的对象自省。
猜你喜欢
  • 1970-01-01
  • 2013-01-28
  • 1970-01-01
  • 2013-12-12
  • 1970-01-01
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
  • 2016-01-22
相关资源
最近更新 更多