【问题标题】:Create new class instance from class method从类方法创建新的类实例
【发布时间】:2012-10-26 23:14:09
【问题描述】:

我希望能够通过调用已实例化对象的方法来创建对象的新实例。比如我有对象:

organism = Organism()

我希望能够调用organism.reproduce() 并拥有两个有机体类型的对象。我此时的方法如下所示:

class Organism(object):
    def reproduce():
        organism = Organism()

而且我很确定它不起作用(我什至不确定如何测试它。我尝试了this post 中的 gc 方法)。那么如何让我的对象创建一个可访问的自身副本,就像我创建的第一个对象(使用organism = Organism())一样?

【问题讨论】:

  • 我想当你说reproduce时,你的意思是clone,对吧?如果是这种情况,那么告诉我们您的Organism 的定义特征/属性是什么将非常有帮助,以便正确处理。

标签: python object copy


【解决方案1】:
class Organism(object):
    def reproduce(self):
        #use self here to customize the new organism ...
        return Organism()

另一个选项——如果实例 (self) 没有在方法中使用:

class Organism(object):
    @classmethod
    def reproduce(cls):
        return cls()

这确保有机体产生更多有机体,并且(从有机体派生的假设博格产生更多博格)。

不需要使用self 的另一个好处是,除了可以从实例中调用之外,现在还可以直接从类中调用它:

new_organism0 = Organism.reproduce()  # Creates a new organism
new_organism1 = new_organism0.reproduce()  # Also creates a new organism

最后,如果在方法中同时使用了实例 (self) 和类(Organism 或从子类调用的子类):

class Organism(object):
    def reproduce(self):
        #use self here to customize the new organism ...
        return self.__class__()  # same as cls = type(self); return cls()

在每种情况下,您都可以将其用作:

organism = Organism()
new_organism = organism.reproduce()

【讨论】:

  • 我发现这个解释很有帮助,但是您能否详细说明“如果实例不重要”与“如果实例和类都重要”的意思? @classmethod 方法和 self.__class__() 方法都适用于我的情况:我有一个基类方法 get_copy 创建子类的新实例(?),然后我使用 __dict__ 来打开新的子类变成原件的“副本”。在这种情况下,一种方法是否比另一种更合适?
  • @isosceleswheel -- 我稍微更新了文本。基本上我是在讨论函数创建新实例所需的数据。换句话说,“如果实例无关紧要”与说“如果函数中没有使用self”是一样的。希望更新后的文字更清楚。
【解决方案2】:

为什么不简单地使用复制模块?

import copy
organism = Organism()
replica = copy.deepcopy(organism)

【讨论】:

    【解决方案3】:

    这样的事情怎么样:

    class Organism(object):
    
        population = []
    
        def __init__(self, name):
            self.name = name
            self.population.append(self)
        def have_one_child(self, name):
            return Organism(name)
        def reproduce(self, names):
            return [self.have_one_child(name) for name in names]
    

    结果:

    >>> a = Organism('a')
    >>> len(Organism.population)
    1
    >>> a.reproduce(['x', 'y', 'z']) # when one organism reproduces, children are added
                                     # to the total population
                                     # organism produces as many children as you state
    [<__main__.Organism object at 0x05F23190>, <__main__.Organism object at 0x05F230F0>, <__main__.Organism object at 0x05F23230>]
    >>> for ele in Organism.population:
    ...     print ele.name
    ... 
    a
    x
    y
    z
    >>> Organism.population[3].reproduce(['f', 'g'])
    [<__main__.Organism object at 0x05F231D0>, <__main__.Organism object at 0x05F23290>]
    >>> for ele in Organism.population:
    ...     print ele.name
    ... 
    a
    x
    y
    z
    f
    g
    

    【讨论】:

      【解决方案4】:

      和你最初做的一样,但是你必须用它做点什么!

      organism = Organism() 调用类Organism(名称后面的括号是“调用”操作)。这将创建并返回该类的一个新实例,然后将其绑定到名称 organism

      当您在解释器中执行该行时,您现在有一个变量 organism 引用您刚刚创建的新 Organism 实例。

      当你在函数内部写下那一行时(包括方法,因为方法和“从内部”的函数没有区别),它做同样的事情,但变量organism是一个局部变量。函数完成后局部变量会被丢弃,所以这个确实创建了一个新的Organism 实例,但它什么也没做,因为你永远无法访问它。

      您的函数应该返回任何它想与调用者交流的信息。任何你不返回的局部变量只有在你使用这些变量来创建你返回的东西时才有用。

      请注意,这与您在方法内创建实例的特定问题无关;这就是函数/方法的一般工作方式。在使用类和实例成功编写面向对象的程序之前,您需要了解函数是如何工作的;我强烈建议您完成一些教程。

      【讨论】:

        【解决方案5】:

        我相信你在问如何复制一个对象。 令人惊讶的是(也许),(几乎)没有标准的方法,这是设计使然。问题来自于复制概念的内在模糊性,即:当您复制对象属性时,您的意思是将其复制为引用(copy)还是值(deepcopy)?

        但是,在大多数情况下,您需要一致的行为(所有属性的深拷贝或复制),在这种情况下,您可以使用 copy 模块作为

        import copy
        new_obj = copy.copy(old_obj)
        

        new_obj = copy.deepcopy(old_obj)
        

        在一般情况下,您需要更自定义的行为,您可以使用相同的命令,但覆盖对象的 __copy____deepcopy__ 方法。

        有关详细信息和示例,请参阅更多答案,例如: How to override the copy/deepcopy operations for a Python object?

        【讨论】:

        • 很好的答案,但附加到错误的问题上。
        • 谢谢!但你为什么这么说?我知道这是当它说“那么我怎样才能让我的对象创建一个可以像第一个对象一样访问的自身副本时所问的内容。”(同样从第一个评论到问题,我不是唯一一个理解一样。
        • 您的解决方案是否显示“通过在已实例化的对象上调用方法”来制作副本?不,您是在自己制作副本,而不是通过定义然后在 old_obj 内的 / 上调用函数。
        • 对于通用副本,您可能会编写一个返回 copy.copy(self) 的方法(例如 old_obj.replicate()),但没有什么理由使用这种方法:您只需调用 copy.copy(old_obj)。我认为这是制作副本的标准方法,因为它甚至适用于覆盖对象的 __copy__ 方法的更多特定于对象的方法(例如,复制一些属性并引用其他属性)。
        【解决方案6】:
        from copy import copy                                                           
        
        class Organism(object):                                                         
        
            def __init__(self,name):                                                    
                self.name=name                                                          
        
            def setName(self,name):                                                     
                self.name=name                                                          
        
            def reproduce(self,childname):     
                #use deepcopy if necessary                                         
                cp = copy(self)                                                         
                cp.setName("descendant from " + self.name + " " + childname)            
                return cp                                                               
        
            def __str__(self):                                                          
                return self.name                                                        
        
        first = Organism("first")                                                       
        second = first.reproduce("second")                                              
        
        print first                                                                     
        print second 
        

        【讨论】:

          猜你喜欢
          • 2011-08-24
          • 2021-08-28
          • 1970-01-01
          • 2021-11-22
          • 2011-12-17
          • 2018-11-23
          • 2011-06-07
          相关资源
          最近更新 更多