我正在编写一个可以通过特效修改内容的游戏。我决定使用python的能力来分配一个实例,而不是类。请注意,这是不修改整个班级'成员,只是它的一个实例。把它想象成MtG的当地魅力。
我如何回到原班级的会员?
采用以下示例代码:
class Dog(object):
noise = "Woof!"
def bark(self):
print self.noise
def make_alpha(self):
self.noise = self.noise.upper()
class Bulldog(Dog):
noise = "Grr!"
class EnormousBulldog(Bulldog):
pass
puppy = Dog()
print puppy.bark() # Woof!
bulldog = Bulldog()
print bulldog.bark() #Grr!
big_dog = EnormousBulldog()
print big_dog.bark() # Grr!
big_dog.make_alpha()
print puppy.bark() # Woof!
print bulldog.bark() # Grr!
print big_dog.bark() # GRR!
这一切都有效。
但是假设我想制作一个remove_alpha()方法。我可以尝试扭转make_alpha()对噪音的影响(因此在实际游戏中为每一种可能的特效做到这一点),但我感觉到这条道路是疯狂的。更简单的是回到Bulldog.noise。但是EnormousBulldog是如何得到Bulldog.noise的?
self.__dict__["noise"]
会给我修改后的噪音。
EnormousBulldog.__dict__
不会给我任何东西,因为噪音是Bulldog,它的超类。
type(self).__getattribute__(self, "noise")
会看到有一个经过修改的噪音,而是给我这个。
我已考虑覆盖__getattribute__
,而不是完全将实例更改为备用架构,但我认为性能损失并不值得。
有什么想法吗?
答案 0 :(得分:3)
超类变量始终可用self.__class__.noise
或EnormousBulldog.noise
或getattr(self.__class__, 'noise')
。
或者,如果您的问题是"如何取消每个实例的更改",然后del
来自实例的属性,可能还有一个警卫:
def remove_alpha(self):
if 'noise' in self.__dict__:
del self.noise
之后,属性查找会在超类中找到它。
不,不要将__getattr__
与__getattribute__
混淆;你想要覆盖前__getattr__
;后者几乎肯定不是你想要做的。
答案 1 :(得分:1)
有一个相当肮脏和令人困惑的解决方案,但这可能会做你想要的:它依赖于在 class 属性之前评估实例属性的事实:
class Dog(object):
noise = "Woof!"
def bark(self):
print self.noise
def make_alpha(self):
self.noise = self.__class__.noise.upper()
def remove_alpha(self):
try:
del self.noise
except AttributeError:
print ("You tried to call remove_alpha into an"
" instance that doesn't have its own noise!!")
class Bulldog(Dog):
noise = "Grr!"
if __name__ == '__main__':
bulldog = Bulldog()
bulldog.bark()
print "Checkpoint: noise is NOT among the instance's vars: %s" % vars(bulldog)
bulldog.make_alpha()
print "Checkpoint: now noise is among the instance's vars: %s" % vars(bulldog)
bulldog.bark()
bulldog.remove_alpha()
print "Checkpoint: noise is NOT among the instance's vars: %s" % vars(bulldog)
bulldog.bark()
print "Second test:"
bulldog02 = Bulldog()
bulldog02.bark()
print "Checkpoint: noise is NOT among the instance's vars: %s" % vars(bulldog)
bulldog02.remove_alpha()
print "Checkpoint: noise is NOT among the instance's vars: %s" % vars(bulldog)
bulldog02.bark()
哪个输出:
Grr!
Checkpoint: noise is NOT among the instance's vars: {}
Checkpoint: now noise is among the instance's vars: {'noise': 'GRR!'}
GRR!
Checkpoint: noise is NOT among the instance's vars: {}
Grr!
Second test:
Grr!
Checkpoint: noise is NOT among the instance's vars: {}
You tried to call remove_alpha into an instance that doesn't have its own noise!!
Checkpoint: noise is NOT among the instance's vars: {}
Grr!
当您拨打make_alpha
时,会在实例中添加一个新的noise
属性,该属性会取代noise属性> class 级别。您可能想要检查内置vars的内容。
答案 2 :(得分:0)
我建议采用不同的方法,这会对性能产生一些影响,但会使代码更简单,更灵活:
class EnhancedAction(object):
"""
A way to keep track of the enhanced implementation,
as well as the original one, to allow to go back to it
"""
def __init__(self, target, original, impl):
self._target = target
self._original = original
self._impl = impl
def __call__(self, *args):
return self._impl(self._target, self._original, args)
@property
def original(self):
return self._original
class Dog(object):
noise = "Woof!"
def bark(self):
return self.noise
def make_alpha(self):
self.bark = EnhancedAction(
target=self, original=self.bark,
impl=lambda self, original, args: original().upper()
)
def revert_alpha(self):
if isinstance(self.bark, EnhancedAction):
self.bark = self.bark.original
class Bulldog(Dog):
noise = "Grr!"
class EnormousBulldog(Bulldog):
pass
big_dog = EnormousBulldog()
print "Regular bark:", big_dog.bark() # Grr!
big_dog.make_alpha()
print "Enhanced bark:", big_dog.bark() # GRR!
big_dog.revert_alpha()
print "Back to regular:", big_dog.bark() # Grr!
<强>缺点强>:
<强>赞成强>: