在python中用super执行父函数

Execute parent's function with super in Python

我对Python中的超级函数有一些问题。假设我有这两个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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,我如何才能做到这一点?

感谢您的时间:)

编辑:好吧,我想你错过了一些关于我实际情况的细节,因为我的例子不好。让我们开始真正的代码。我有这两门课(姜戈模特):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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__是第一次将对象记录到数据库时调用的方法,我主要将它用于通知目的。那么,这就是我想要做的:

  • 创建一个usercomment对象并保存它
  • 调用usercomment实例的__insert__
  • 调用comment的__insert__,它应该调用comment的__notify__
  • __insert__调用usercomment实例的__notify__
  • 这是可以用一种或多或少简单的方式实现的,还是我必须重构我的代码?再次感谢您的回答。


    你只是说你想执行A.p()

    1
    2
    3
    4
    5
    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()时,它将调用b中的p()定义,而不是a中的(overrridden)定义。这正是您应该期望的——您创建了一个混合类并重写了一个方法DS。


    记住,self指的是一个实例,由于B是b的实例,self.p()指的是method p() in class B而不是a,所以要么从B类中删除方法p(),要么从B中显式调用A's p()作为:

    1
    2
    3
    4
    5
    6
    7
    class B(A):
        def p(self):
                 super(B, self).p()
                 print 'B'
        def f(self):
                 super(B, self).f()
                 self.x*=2

    或者使p成为a的staticMethod,并使用A.p()从类a中的f()调用它,特别是当您不需要从使p成为"函数"而不是"方法"的方法访问类时:

    1
    2
    3
    4
    5
    6
    7
    8
    class A(object):
        x=5
        @staticmethod
        def p():
            print 'A'
        def f(self):
            A.p()
            self.x+=1

    使用此b,输出为:

    1
    2
    3
    4
    5
    6
    7
    8
    >>> b = B()
    >>> b.f()
    A
    >>> b.x
    12
    >>> b.p()
    A
    B

    注意b是如何只在b.p()调用中打印的,而不是在b.f()调用时打印的。


    注意代码中事件的进展:

    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的功能,有明显的区别。方法重载的基本目的是展示与父类不同的行为,看吧,它做到了!