我认为Python中的所有函数和方法参数都是通过引用传递的,这使我相信以下代码可以工作:
class Insect:
def status(self):
print "i am a %s" % self
class Caterpillar(Insect):
def grow_up(self):
self = Butterfly() # replace myself with a new object
return
class Butterfly(Insect):
pass
my_obj = Caterpillar()
my_obj.status() # i am a <__main__.Caterpillar instance at 0x100494710>
# ok, time to grow up:
my_obj.grow_up()
my_obj.status() # want new Butterfly object, but it is still Caterpillar! :(
如何在方法调用中更改对象本身?
- 编辑:
到目前为止,回复是:
1)更改self .__ class__以更改与当前对象关联的类 2)“不要那样抱。”
最初的问题:如何在旧类中定义的方法调用中创建一个取代旧的 new 对象?
我认为答案可能实际上是“你做不到。”
- EDIT2:
为什么每个人都害怕说“这是不可能的”?
答案 0 :(得分:3)
当你说self = Butterfly()
时,你正在做的就是改变变量self
指向的内容;你不会改变自我,只不过:
x = 1
x = 2
...将数字1更改为2。
一般来说,当人们需要这个时候,不是改变对象的类型(许多语言都是禁止的),人们会使用合成策略:
class Lepidoptera(Insect):
def __init__(self):
self.stage = Caterpillar()
def status(self):
print 'I am a %s' % self.stage
def grow_up(self):
if self.stage.adult:
raise TypeError('Already an adult')
self.stage = Butterfly()
答案 1 :(得分:2)
self.__class__ = Butterfly
可能会有效,因为它会重新绑定一个合格的名称(与重新绑定裸名称相比,完全不同)。
重新绑定一个裸名称对以前绑定到它的任何对象都不会有任何效果(除非该裸名称是对该“前一个对象”的唯一引用,在这种情况下后者可能会被销毁 - 但这显然不是这种情况,因为self
是对my_obj
相同对象的引用,因此self
不能是仅对它的引用)。
修改强>:
你指的是需要初始化新重新分类的对象 - 这很容易:
self.__dict__.clear()
self.__class__ = Butterfly
self.__init__(whatever, you, want)
但是在评论中你提到需要“备份属性” - 我不知道你究竟是什么意思,或者为什么这与你直接分配到{{1的“梦想案例”完全不同(这当然也会破坏属性)。也许这个想法是self
的(有些)参数需要是__init__
的属性?然后,例如,您可以将其编码为:
self
答案 2 :(得分:1)
请记住,Python中的变量是绑定到对象的名称。阅读section 4.1 of the Language Reference了解更多详情。它的要点是方法参数是绑定到调用中传递的对象的名称。
当您为变量“分配新值”时,您只需将本地名称绑定到新对象即可。它最初提到的对象没有改变。
当您对变量调用变异方法时,该方法可以使用限定名称来更改对象的内部状态,例如self.var
Alex is referring to in his answer 。如果重新绑定self
,则不会修改对象。
这是Python的一个更有趣的功能。它与大多数其他语言略有不同,因为您实际上无法访问方法中的原始对象指针(例如this
)。您唯一可以访问的是实例的绑定名称。
编辑:我不知道我是如何忘记回答您的实际问题的,但答案肯定是您无法在方法调用中更改基础对象。我的漫无边际是为什么部分而没有真正提供答案。
答案 3 :(得分:1)
您的设计存在根本缺陷。毛虫和蝴蝶不是不同的生物,它们是同一生物的不同状态。
class Lepidoptera(Insect):
# Just use strings for states
CATERPILLAR = "caterpillar"
BUTTERFLY = "butterfly"
def __init__(self):
self.state = Lepidoptera.CATERPILLAR
def grow_up(self):
self.state = Lepidoptera.BUTTERFLY
def status(self):
""" Override superclass method. """
print "I am a %s, currently in the state: %s" % (self, self.state)
如果你需要更复杂的东西,状态应该是更复杂的对象,需要额外的参数(或者只是让Lepidoptera类在内部处理它)。
你实际上是在问如何将鳞翅目变成蟋蟀,这是不可能发生的。这是为什么你找不到在你的程序中表示这个概念的方法(或者为什么它看起来如此hacky)。您决定使用对象来表示昆虫,但实际上您创建的代表昆虫状态的类。然后你想知道为什么你不能正确模拟昆虫的行为。
另一种方式,如果你想让类代表昆虫状态,那么显然你需要其他类来代表昆虫本身,然后它们将包含这些状态和改变它们的方法。
就你的真实问题而言,听起来你把“与国家的关系”与“国家本身”混为一谈。
答案 4 :(得分:1)
正如亚历克斯所说,严格来说,没有办法做到这一点。 我无法想到这样的事情是可取的。也许你需要一个工厂函数insetad?或同一对象的不同状态?
然而,Python就是这样,你可以有一个“shell”对象,其唯一目的是授予对underlyign对象的访问权限。然后可以修改底层对象:当shell对象保持不变时,底层对象是另一个。
一种可能的实现如下(我再次尝试使用__getattribute__
的不洁实现 - 它可以做得更好)
# -*- coding: utf-8 -*-
class Insect(object):
pass
class Catterpillar(Insect):
a = "I am a caterpillar"
class Butterfly(Insect):
a = "I am a butterfly"
class Cocoon(object):
def __init__(self, *args, **kw):
self._true = Catterpillar(*args, **kw)
def __getattribute__(self, attr):
try:
if attr != "_true":
return getattr(object.__getattribute__(self, "_true"),attr)
except AttributeError:
pass
return object.__getattribute__(self, attr)
def __setattr__(self, attr, val):
if attr != "_true":
setattr(self._true, attr, val)
else:
object.__setattr__(self, attr, val)
def change(self, *args, **kw):
self._true = Butterfly(*args, **kw)
通过这个你可以得到像这样的东西:
>>>
>>> a= Cocoon()
>>> a.a
'I am a caterpillar'
>>> a.__class__
<class '__main__.Catterpillar'>
>>> a.change()
>>> a.a
'I am a butterfly'
>>> a.__class__
<class '__main__.Butterfly'>
>>>
。
在更改功能上,您可以备份所需的任何属性,并且可以在__getattribute__
方法中免除其他属性的更改。