每次使用对象组合时实例化唯一对象?

时间:2011-10-21 01:50:06

标签: python object singleton composition

作为一个例子,只有几个虚拟对象将一起使用。 FWIW这是使用Python 2.7.2。

class Student(object):
    def __init__(self, tool):
        self.tool = tool

    def draw(self):
        if self.tool.broken != True:
            print "I used my tool. Sweet."
        else:
            print "My tool is broken. Wah."

class Tool(object):
    def __init__(self, name):
        self.name = name
        self.broken = False

    def break(self):
        print "The %s busted." % self.name
        self.broken = True

Hammer = Tool(hammer)
Billy = Student(Hammer)
Tommy = Student(Hammer)

这可能是足够的代码,你知道我要去哪里。如果我调用Hammer.break(),我在对象的同一个实例上调用它;如果比利的锤子被打破了,那么汤米也是如此(毕竟它与锤子完全相同)。

现在很明显,如果该程序仅限于Billy和Tommy作为学生的实例,那么修复将是显而易见的 - 实例化更多的Hammers。但显然我在问,因为不是那么简单,呵呵。我想知道是否有可能创建对象,这些对象在每次被调用时都会显示为自己的唯一实例。

编辑:我得到的答案让我相信我对实例化的理解有一个漏洞。如果我有这样的事情:

class Foo(object):
    pass

class Moo(Foo):
    pass

class Guy(object):
    def __init__(self, thing):
        self.thing = thing

Bill = Guy(Moo())
Steve = Guy(Moo())

每次我使用Moo()时,是一个单独的实例,还是它们都引用同一个对象?如果他们分开,那么我的整个问题都可以撤回,因为它会让我的思绪变得松散。

6 个答案:

答案 0 :(得分:3)

您必须为每个学生创建工具的新实例。

class Student(object):
    def __init__(self, tool):
        self.tool = tool

    def draw(self):
        if self.tool.broken != True:
            print "I used my tool. Sweet."
        else:
            print "My tool is broken. Wah."

class Tool(object):
    def __init__(self, name):
        self.name = name
        self.broken = False

    def break(self):
        print "The %s busted." % self.name
        self.broken = True

# Instead of instance, make it a callable that returns a new one
def Hammer():
    return Tool('hammer')

# Pass a new object, instead of the type
Billy = Student(Hammer())
Tommy = Student(Hammer())

答案 1 :(得分:2)

  

我会尽量简短。嗯..我总是试着简短,但我的成功水平几乎是random.randint(0,从不)。所以是的。

洛尔。你甚至没有简短地宣布你会试着简短。

首先,我们需要明确“召唤成为”的含义。据推测,每次发生self.tool = object时你都需要一把新锤子。您不希望每次都有新的实例,例如,您访问工具属性,或者每次检查self.tool.broken时,您总是会得到一个新的,可能是完整的锤子。

一对夫妇。

一,给Tool一个复制方法,该方法产生一个新对象,该对象应该等于原始对象,但是是一个不同的实例。例如:

class Tool:

    def __init__(self, kind):
        self.kind = kind
        self.broken = False

    def copy(self):
        result = Tool(self.kind)
        result.broken = self.broken
        return result

然后在学生的初学者中你说

    self.tool = tool.copy()

选项二,使用工厂功能。

def makehammer():
    return Tool(hammer)

class Student:
    def __init__(self, factory):
        self.tool = factory()

Billy = Student(makehammer)

我无法在Python中认为你可以编写行self.tool = object并让对象自动复制,我认为你不想这样做。我喜欢Python的一件事是WYSIWYG。如果你想要魔法使用C ++。我认为,当你不仅无法分辨出一行代码在做什么时,你甚至不能告诉它正在做任何特殊的代码,这使得代码难以理解。

请注意,您可以使用工厂对象获得更好的体验。例如:

class RealisticFactory:
    def __init__(self, kind, failurerate):
        self.kind = kind
        self.failurerate = failurerate

    def make(self):
        result = Tool(self.kind)
        if random.random() < self.failurerate:
            result.broken = True
        if (self.failurerate < 0.01):
            self.failurerate += 0.0001
        return result

factory = RealisticFactory(hammer, 0.0007)
Billy = Student(factory.make)
Tommy = Student(factory.make) # Tommy's tool is slightly more likely to be broken

答案 2 :(得分:1)

您可以像这样更改行:

Billy = Student(Tool('hammer'))
Tommy = Student(Tool('hammer'))

这将为Student类的每个实例生成一个独特的Tool类实例。您发布的示例代码的问题在于您没有多次“调用工具”(使用您的单词)。

答案 3 :(得分:1)

每次要创建新工具时,只需调用工具('锤子')。

h1 = Tool('hammer')
h2 = Tool('hammer')
Billy = Student(h1)
Tommy = Student(h2)

答案 4 :(得分:0)

哦等等,我忘记了,Python确实有魔力。

class Student:
    def __setattr__(self, attr, value):
        if attr == 'tool':
            self.__dict__[attr] = value.copy()
        else:
            self.__dict__[attr] = value

但我仍然说你应该谨慎使用魔法。

答案 5 :(得分:0)

在看到这里的答案并记住Python的禅之后,我将回答我自己的问题时说:“我可能应该更加努力地思考它。”

我将重申我自己的问题作为答案。假设我有这个小程序:

class Item(object):
    def __init__(self):
        self.broken = False

    def smash(self):
        print "This object broke."
        self.broken = True

class Person(object):
    def __init__(self, holding):
        self.holding = holding

    def using(self):
        if self.holding.broken != True:
            print "Pass."
        else:
            print "Fail."

Foo = Person(Item())
Bar = Person(Item())

Foo.holding.smash()
Foo.using()
Bar.using()

程序将为Foo.using()返回“Fail”,为Bar.using()返回“Pass”。在实际上在考虑我正在做什么时,“Foo.holding = Item()”和“Bar.holding = Item()”显然是不同的实例。我甚至运行这个愚蠢的程序来证明它是有效的,因为我推测它确实有效,并且对你们没有惊喜,它确实如此。所以我撤回了我的问题,因为当我提出时,实际上并没有使用我的大脑。有趣的是,通过我一直在研究的程序,我已经这样做了,但假设这是错误的方法。所以,谢谢你的幽默。