python super() - __new__上下文中的两个参数版本

时间:2016-07-29 14:33:32

标签: python

我已经多次阅读the documentation for super()但我仍然没有得到两个参数版本返回的内容。

  

返回将方法调用委托给父或者的代理对象   兄弟类的类型。这对于访问继承的方法很有用   在课堂上被覆盖的。

  1. 什么是代理对象?
  2. 或兄弟
  3.   

    如果第二个参数是一个对象,isinstance(obj, type)必须是   真正。如果第二个参数是类型,则issubclass(type2, type)必须   是真的(这对于类方法很有用。)

    1. 这一切都很好,但返回的内容?语法super(a,b) 意味着是什么意思?
    2. __new__

      的背景下
        

      典型实现通过调用创建类的新实例   超类的__new __()方法使用super(currentclass, cls).__new__(cls[, ...])和适当的参数然后修改   在返回之前必要时新创建的实例。

      super(currentclass, cls).__new__(cls[, ...])

      如果currentclass等于cls,则您有super(currentclass, currentclass)

      1. 那回报是什么?这句法是什么意思?
      2. 此语句如何返回cls的实例,以便在返回的对象上调用__init__

2 个答案:

答案 0 :(得分:2)

super返回的内容”的答案不是“它返回列表”或“它返回第二个对象的修改后的副本”。 super返回super类型的对象,该类型专门设计为具有文档所具有的品质。

也许有助于展示super的纯Python实现。如果super没有用C语言编写,它看起来基本上就是这样:

class super(object):
    def __init__(self, klass, object_or_klass):
        # The real super can be called with 0 arguments on Python 3,
        # but digging into the magic that makes that work isn't relevant here.

        if isinstance(object_or_klass, klass):
            mro = type(object_or_klass).__mro__
            self.obj_type = type(object_or_klass)
            self.obj = object_or_klass
        elif issubclass(object_or_klass, klass):
            mro = object_or_klass.__mro__
            self.obj_type = object_or_klass
            self.obj = None
        else:
            raise TypeError

        # Set up a copy of the MRO to search,
        # with everything up to and including klass skipped
        self.searchlist = mro[mro.index(klass)+1:]

    def __getattribute__(self, name):
        # self.searchlist would be infinite recursion, as would super().__getattribute__
        searchlist = object.__getattribute__(self, 'searchlist')

        # Search the method resolution order for the attribute we want.
        for klass in searchlist:
            if name in klass.__dict__:
                attr = klass.__dict__[name]
                break
        else:
            raise AttributeError

        if hasattr(attr, '__get__'):
            # Handle descriptors.
            obj = object.__getattribute__(self, 'obj')
            obj_type = object.__getattribute__(self, 'obj_type')
            attr = attr.__get__(obj, obj_type)
        return attr

现在您可以看到super(a, b)构建了一个super对象,super(a, b).whatever调用了该__getattribute__对象的super方法来搜索方法解析顺序我们想要的属性的第二个参数。 b.whatever的属性查找过程非常相似,只是没有删除MRO的第一部分,并检查实例dict b是否不是类。

答案 1 :(得分:-1)

你应该肯定观看Raymond Hettinger在PyCon 2015上的演讲,Super is considered super!

但如果没有,为什么不添加一堆打印陈述来回答你的问题?

# (object) is only required in Python2
class Mom(object):
    def __init__(self, *args, **kwargs):
        print('Mom is initializing - args: {!r} kwargs: {!r}'.format(
              args, kwargs))

    def do_something(self):
        print('Doing some Mom thing')


class Dad(object):
    def __init__(self, *args, **kwargs):
        print('Dad is initializing - args: {!r} kwargs: {!r}'.format(
              args, kwargs))

    def do_something(self):
        print('Doing some Dad thing')


class Sister(Mom, Dad):
    def __init__(self, name):
        print('initializing a Sister with name: {!r}'.format(name))
        parent = super(Sister, self)
        print(type(parent))
        print(parent)
        print('Calling super __init__')
        parent.__init__(name)

    def do_something(self, value):
        if value == 5:
            print('calling method on super')
            super(Sister, self).do_something()
        else:
            print('Sister did something')


class Brother(Mom):
    def __init__(self, name):
        print('initializing a Brother with name: {!r}'.format(name))
        parent = super(Brother, self)
        print(type(parent))
        print(parent)
        print('Calling super __init__')
        parent.__init__(name)

    def do_something(self, value):
        if value == 5:
            print('calling method on super')
            super(Brother, self).do_something()
        else:
            print('Brother did something')


b = Brother('Bear')
s = Sister('Moon')

b.do_something(3)
b.do_something(5)

s.do_something(3)
s.do_something(5)

产生以下输出(附加评论):

<type 'super'>
<super: <class 'Brother'>, <Brother object>>
Calling super __init__
Mom is initializing - args: ('Bear',) kwargs: {}

显然,super会返回super类的类。根据文档,这是一个代理对象。根据定义,代理是其他东西的替代品。在这种情况下,代理是获取Mom的替代品。你可以看到,当我们实际调用__init__函数时,会调用Mom的init函数。

initializing a Sister with name: 'Moon'
<type 'super'>
<super: <class 'Sister'>, <Sister object>>
Calling super __init__
Mom is initializing - args: ('Moon',) kwargs: {}

你会注意到,没有调用爸爸的init函数。那是因为,如果你看雷蒙德的谈话,你会知道super从左到右寻找父母的功能。

Brother did something
calling method on super
Doing some Mom thing

您在此处重复了相同的行为

Sister did something
calling method on super
Doing some Mom thing

如果您将姐妹的订单更改为Dad, Mom,您会看到这些来电更改:

initializing a Brother with name: 'Bear'
<type 'super'>
<super: <class 'Brother'>, <Brother object>>
Calling super __init__
Mom is initializing - args: ('Bear',) kwargs: {}
initializing a Sister with name: 'Moon'
<type 'super'>
<super: <class 'Sister'>, <Sister object>>
Calling super __init__
Dad is initializing - args: ('Moon',) kwargs: {}
Brother did something
calling method on super
Doing some Mom thing
Sister did something
calling method on super
Doing some Dad thing

总结一下:

  1. 代理是代替其他东西的东西。在我们的案例中,super是妈妈和妈妈的代理人。爸爸,取决于他们继承的顺序。

  2. 老实说,我无法找到任何有意义的兄弟姐妹的事情。我不确定你什么时候甚至不需要它。

  3. 返回super的实例。

  4. 如果你有从type继承的东西,那就真的有效。 super(type, type),因为您需要该类型的实例object也可以,因为:

    print(isinstance(object,object)) print(isinstance(type,type)) print(isinstance(object,type)) print(isinstance(type,object))

  5. 围绕 进程有一些非常复杂的魔法。

    1. 你问的是函数如何返回东西?因为 new 是一个函数 - 它返回或不返回。 object.__new__会返回一些内容。我不确定该函数的实际源代码在哪里,或者如果您对确切的机制感兴趣,我可以指出那里。