При вызове super()
для решения родительской версии метода класса, метода экземпляра или метода static мы хотим передать текущий класс, объем которого мы находимся в качестве первого аргумента, чтобы указать область действия родителя, которую мы пытаемся чтобы разрешить и в качестве второго аргумента объект интереса указать, к какому объекту мы пытаемся применить эту область.
Рассмотрим иерархию классов A
, B
и C
где каждый класс является родителем следующего за ним и a
, b
и c
соответствующих экземпляров каждого.
super(B, b)
# resolves to the scope of B's parent i.e. A
# and applies that scope to b, as if b was an instance of A
super(C, c)
# resolves to the scope of C's parent i.e. B
# and applies that scope to c
super(B, c)
# resolves to the scope of B's parent i.e. A
# and applies that scope to c
super
со статическим методом , например используя super()
из метода __new__()
class A(object):
def __new__(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
return super(A, cls).__new__(cls, *a, **kw)
Объяснение:
1-, хотя обычно __new__()
обычно принимает в качестве первого параметра ссылку на вызывающий класс, это not , реализованный в Python как classmethod, а скорее статический метод. То есть ссылка на класс должна быть явно передана в качестве первого аргумента при непосредственном вызове __new__()
:
# if you defined this
class A(object):
def __new__(cls):
pass
# calling this would raise a TypeError due to the missing argument
A.__new__()
# whereas this would be fine
A.__new__(A)
2- при вызове super()
для перехода к родительскому классу мы передаем child class A
в качестве своего первого аргумента, тогда мы передаем ссылку на объект, представляющий интерес, в этом случае это ссылка на класс, которая была передана при вызове A.__new__(cls)
. В большинстве случаев это также ссылка на дочерний класс. В некоторых ситуациях это может быть не так, например, в случае наследования с несколькими поколениями.
super(A, cls)
3-, поскольку поскольку общее правило __new__()
является статическим методом, super(A, cls).__new__
также возвращает статический метод и должен быть предоставлен все аргументы явно, включая ссылку на объект insterest, в этом случае cls
.
super(A, cls).__new__(cls, *a, **kw)
4- делать то же самое без super
class A(object):
def __new__(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
return object.__new__(cls, *a, **kw)
super
с помощью метода экземпляра , например используя super()
из __init__()
class A(object):
def __init__(self, *a, **kw):
# ...
# you make some changes here
# ...
super(A, self).__init__(*a, **kw)
Объяснение:
1- __init__
- это метод экземпляра, означающий, что в качестве первого аргумента он принимает ссылку на пример. При вызове непосредственно из экземпляра ссылка передается неявно, то есть вам не нужно указывать ее:
# you try calling `__init__()` from the class without specifying an instance
# and a TypeError is raised due to the expected but missing reference
A.__init__() # TypeError ...
# you create an instance
a = A()
# you call `__init__()` from that instance and it works
a.__init__()
# you can also call `__init__()` with the class and explicitly pass the instance
A.__init__(a)
2- при вызове super()
в __init__()
мы передаем дочерний класс как первый аргумент и объект интереса как второй аргумент, который в общем случае является ссылкой на экземпляр дочернего класса.
super(A, self)
3- Вызов super(A, self)
возвращает прокси-сервер, который будет разрешите область действия и примените ее к self
, как если бы она стала экземпляром родительского класса. Назовем этот прокси s
. Поскольку метод __init__()
является методом экземпляра, вызов s.__init__(...)
будет неявно передавать ссылку self
в качестве первого аргумента родительскому __init__()
.
4- сделать то же самое без super
нам нужно передать ссылку на экземпляр явно в родительскую версию __init__()
.
class A(object):
def __init__(self, *a, **kw):
# ...
# you make some changes here
# ...
object.__init__(self, *a, **kw)
super
с помощью метода класса class A(object):
@classmethod
def alternate_constructor(cls, *a, **kw):
print "A.alternate_constructor called"
return cls(*a, **kw)
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
return super(B, cls).alternate_constructor(*a, **kw)
Объяснение:
1- Метод класса можно вызывать непосредственно из класса и в качестве его первого параметра берет ссылку на класс.
# calling directly from the class is fine,
# a reference to the class is passed implicitly
a = A.alternate_constructor()
b = B.alternate_constructor()
2- при вызове super()
в классе-методе, чтобы разрешить его родительскую версию, мы хотим передать текущий дочерний класс в качестве первого аргумента, чтобы указать, какую область действия родителя мы пытаемся разрешить и объект интереса в качестве второго аргумента, чтобы указать, к какому объекту мы хотим применить эту область действия, которая в общем случае является ссылкой на сам дочерний класс или один из его подклассов.
super(B, cls_or_subcls)
3- Вызов super(B, cls)
разрешает область действия A
и применяет ее к cls
. Поскольку alternate_constructor()
является методом класса, вызов super(B, cls).alternate_constructor(...)
будет неявно передавать ссылку cls
в качестве первого аргумента A
alternate_constructor()
super(B, cls).alternate_constructor()
[4] для выполнения то же самое без использования super()
вам нужно будет получить ссылку на unbound версию A.alternate_constructor()
(то есть на явную версию функции). Просто это не сработает:
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
return A.alternate_constructor(cls, *a, **kw)
Вышеупомянутое не будет работать, потому что метод A.alternate_constructor()
принимает в качестве первого аргумента неявную ссылку на A
. Здесь cls
будет вторым аргументом.
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
# first we get a reference to the unbound
# `A.alternate_constructor` function
unbound_func = A.alternate_constructor.im_func
# now we call it and pass our own `cls` as its first argument
return unbound_func(cls, *a, **kw)
Вы можете применить это, используя уникальный индекс, который включает оба поля:
submissionSchema.index({ email: 1, sweepstakes_id: 1 }, { unique: true });