我在使用Python中的超级函数时遇到了一些问题。假设我有这两个类:
class A(object):
x=5
def p(self):
print 'A'
def f(self):
self.p()
self.x+=1
class B(A):
def p(self):
print 'B'
def f(self):
super(B, self).f()
self.x*=2
b = B()
b.f()
然后b.x将等于12,但该函数将输出'B',而不是'A'。我需要的是执行A.p而不是B.p,我该如何实现呢?
感谢您的时间:)
class Comment(Insert, models.Model):
content = models.TextField()
sender = models.ForeignKey('logic.User')
sent_on = models.DateTimeField(auto_now_add=True)
def __insert__(self):
self.__notify__()
def __notify__(self):
receivers = self.retrieve_users()
notif_type = self.__notificationtype__()
for user in receivers:
Notification.objects.create(
object_id=self.id,
receiver=user,
sender_id=self.sender_id,
type=notif_type
)
def __unicode__(self):
return self.content
class Meta:
abstract = True
class UserComment(Comment):
is_reply = models.BooleanField()
reply_to = models.ForeignKey('self', blank=True,
null=True, related_name='replies')
receiver = models.ForeignKey('User', related_name='comments')
def __insert__(self):
super(UserComment, self).__insert__()
self.__notify__()
def __notification__(self, notification):
if self.is_reply:
return '%s has replied your comment' % self.sender
return super(UserComment, self).__notification__(notification)
def __notify__(self):
# Notification objects "should" be created by Comment's __notify__
Update.objects.create(
object_id=self.id,
target=self.receiver,
type=self.__updatetype__(),
)
@classmethod
@cache(prop_name='_notificationtype')
def __notificationtype__(cls):
return NotificationType.objects.get(name='USER_COMMENT')
@classmethod
@cache(prop_name='_updatetype')
def __updatetype__(cls):
return UpdateType.objects.get(name='USER_COMMENT')
def retrieve_users(self):
return [self.receiver] # retrieve_users MUST return an iterable
问题在于两种模型上的__insert__
和__notify__
方法。 __insert__
是一种在第一次将对象记录到数据库时调用的方法,我主要将其用于通知目的。然后,这就是我想要做的事情:
__insert__
__insert__
,其中应致电评论__notify__
__notify__
__insert__
醇>
这可能是一种或多或少的方式,还是我必须重构我的代码? 再次感谢您的所有答案。
答案 0 :(得分:5)
您只是说要执行A.p()
:
class B(A):
def p(self):
print 'B'
def super_p(self):
return A.p(self) # prints 'A'
如果您想确保A.p()
被排除,最好的办法就是从B
中的方法明确调用它。正如Rajesh所说,避免这种情况的最好方法是不要覆盖你打算在基类中调用的方法。
超类无法了解子类的任何信息。例如,如果您实例化子类B并且它继承方法x()
并覆盖方法p()
,那么当您调用x()
时,将调用p()
定义 B ,而不是A中的(overrridden)定义。这正是您应该期望的 - 您已经创建了一个混合类并覆盖了其中一个方法。
答案 1 :(得分:1)
请记住,self
是指实例,因为b
是B的实例,self.p()引用method p() in class B
,而不是A.所以要么删除方法{{1来自B类或明确地从B调用p()
:
A's p()
或者创建A的pa静态方法并使用class B(A):
def p(self):
super(B, self).p()
print 'B'
def f(self):
super(B, self).f()
self.x*=2
从A类中的f()调用它,特别是如果您不需要从该方法访问该类,那么p a 'function' rather than a 'method':
A.p()
使用此B,输出为:
class A(object):
x=5
@staticmethod
def p():
print 'A'
def f(self):
A.p()
self.x+=1
请注意B仅在>>> b = B()
>>> b.f()
A
>>> b.x
12
>>> b.p()
A
B
来电时打印,而不是b.p()
时打印。
答案 2 :(得分:0)
观察代码中事件的进展情况:
self.x = 5
self.x = 6
self.x = 12
鉴于您的代码,这是获得12作为输出的唯一方法。但是,如果我们从A类而不是B运行它,则会出现以下行为:
self.x = 5
self.x = 6
在我看来,你想要这种行为。唯一的区别在于行self.x += 2
。
这引出了一个更有趣的问题:为什么你希望(或者甚至期望)在将方法重载到不同的方法之后,子类的行为与其超级方法完全相同! A
执行函数x+1
,而B
执行函数(x+1)*2
,这显然是不同的。方法重载的根本目的是表现出与父类不同的行为,而 lo和behold ,它确实发生了!