Bir sınıf yöntemiyle süper kullanma


83

Python'da super () işlevini öğrenmeye çalışıyorum.

Bu örnek (2.6) üzerine gelene ve kendimi sıkışıp kalana kadar anladığımı düşündüm.

http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html#super-with-classmethod-example

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test.py", line 9, in do_something
    do_something = classmethod(do_something)
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)
>>>

Örnekten hemen önce bu satırı okuduğumda beklediğim gibi değildi:

Bir sınıf yöntemi kullanıyorsak, super çağırabileceğimiz bir örneğimiz yok. Neyse ki bizim için süper, ikinci argüman olarak bir türle bile çalışır. --- Tür, aşağıda gösterildiği gibi doğrudan süper'e geçirilebilir.

Python'un bana söylediği şey, do_something () 'in B örneğiyle çağrılması gerektiğini söyleyerek mümkün değildir.


Yanıtlar:


99

Bazen metinler, ayrıntılardan ziyade fikrin lezzeti için daha fazla okunmalıdır. Bu, o davalardan biri.

Olarak bağlanmış, sayfa , Örnek 2.5, 2.6 ve 2.7 olmalıdır tüm kullanım için tek bir yöntem olup, do_your_stuff. (Yani, do_somethingolarak değiştirilmelidir do_your_stuff.)

Ayrıca Ned Deily'nin de belirttiği gibi , A.do_your_stuffbir sınıf metodu olmalıdır.

class A(object):
    @classmethod
    def do_your_stuff(cls):
        print 'This is A'

class B(A):
    @classmethod
    def do_your_stuff(cls):
        super(B, cls).do_your_stuff()

B.do_your_stuff()

super(B, cls).do_your_stuffilişkili bir yöntem döndürür (bkz. dipnot 2 ). Yana clsikinci bağımsız değişken olarak kabul edildi super(), öyle clsdöndürülür yönteme bağlı olur. Başka bir deyişle, A sınıfının clsyöntemine ilk argüman olarak aktarılır do_your_stuff().

Yinelemek için: super(B, cls).do_your_stuff()nedenleri AVar do_your_stuffolan yöntem çağrılacak clsilk argümanı olarak. Bunun işe yaraması için, A'nin do_your_stuffbir sınıf yöntemi olması gerekir. Bağlantı verilen sayfa bundan bahsetmiyor, ancak durum kesinlikle bu.

PS. do_something = classmethod(do_something)sınıf yöntemi yapmanın eski yoludur. Yeni (er) yol, @classmethod dekoratörünü kullanmaktır.


İle super(B, cls)değiştirilemeyeceğini unutmayın super(cls, cls). Bunu yapmak sonsuz döngülere yol açabilir. Örneğin,

class A(object):
    @classmethod
    def do_your_stuff(cls):
        print('This is A')

class B(A):
    @classmethod
    def do_your_stuff(cls):
        print('This is B')
        # super(B, cls).do_your_stuff()  # CORRECT
        super(cls, cls).do_your_stuff()  # WRONG

class C(B):
    @classmethod
    def do_your_stuff(cls):
        print('This is C')
        # super(C, cls).do_your_stuff()  # CORRECT
        super(cls, cls).do_your_stuff()  # WRONG

C.do_your_stuff()

yükselecek RuntimeError: maximum recursion depth exceeded while calling a Python object.

Eğer clsbir Csonra super(cls, cls)aramalar C.mro()sonra gelen sınıf için C.

In [161]: C.mro()
Out[161]: [__main__.C, __main__.B, __main__.A, object]

O sınıf olduğundan Bzaman clsolduğu C, super(cls, cls).do_your_stuff() her zaman çağırır B.do_your_stuff. Yana super(cls, cls).do_your_stuff()içeride denir B.do_your_stuff, aradığınız sona B.do_your_stuffsonsuz döngüye.

Python3'te, 0-argüman formusuper eklendi, böylece super(B, cls)ile değiştirilebilir super()ve Python3 bağlamdan super(), tanımında class Beşdeğer olması gerektiğini anlayacaktır super(B, cls).

Ancak hiçbir koşulda super(cls, cls)(veya benzer nedenlerle super(type(self), self)) asla doğru değildir.


Süper (cls, cls) kullanmanın tuzakları var mı?
George Moutsopoulos

2
@GeorgeMoutsopoulos: super(cls, cls)neredeyse kesinlikle bir hata. Nedenini açıklamak için yukarıdaki gönderiyi düzenledim.
unutbu

39

Python 3'te, aşağıdakiler için bağımsız değişken belirtmeyi atlayabilirsiniz super,

class A:
    @classmethod
    def f(cls):
        return "A's f was called."

class B(A):
    @classmethod
    def f(cls):
        return super().f()

assert B.f() == "A's f was called."

Bu özel soru özellikle Python 2 ile ilgiliyse, bu cevap başka bir soruya taşınabilir (bağlantılı web sitesi CafePy artık mevcut olmadığından bunu söylemek zor).
Tankobot

Benim bir projemde işe yaramıyor. Bu veriyorRuntimeError: super(): no arguments
madtyn

4

Makaleyi biraz daha net hale getirmek için güncelledim: Python Nitelikleri ve Yöntemleri # Süper

Yukarıdaki sınıf yöntemini kullanan örneğiniz, bir sınıf yönteminin ne olduğunu gösterir - ilk parametre olarak örnek yerine sınıfın kendisini geçer. Ancak yöntemi çağırmak için bir örneğe bile ihtiyacınız yoktur, örneğin:

>>> class A(object):
...     @classmethod
...     def foo(cls):
...         print cls
... 
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>

2

Web sayfasındaki örnek yayınlandığı gibi çalışıyor gibi görünüyor. do_somethingÜst sınıf için de bir yöntem yarattınız, ancak onu bir sınıf yöntemi haline getirmediniz mi? Bunun gibi bir şey size şu hatayı verecektir:

>>> class A(object):
...     def do_something(cls):
...         print cls
... #   do_something = classmethod(do_something)
... 
>>> class B(A):
...     def do_something(cls):
...         super(B, cls).do_something()
...     do_something = classmethod(do_something)
... 
>>> B().do_something()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in do_something
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)

Hayır, benim A sınıfım şuna benziyor: class A (nesne): def do_your_stuff (self): print "bu A" Gönderirken "A sınıfı" olması gerekli mi? (do_something = classmethod (do_something) ile)? Belgenin bununla ilgili hiçbir şey söylemediğini hissediyorum ..
dza

1
Bütün noktası superB do_something yöntemde çağrı kendi üst sınıfı birinde bu isimde bir yöntem aramak. A'da (veya Nesnede) bir tane yoksa, B (). Do_something () çağrısı ile başarısız olur super object has no attribute do_something. ~ unutbu haklı olarak belgedeki örneğin hatalı olduğuna işaret eder.
Ned Deily

0

Sanırım bu güzel site ve sevimli topluluk sayesinde asıl noktayı anladım.

Eğer sakıncası yoksa, sınıf yöntemlerinde yanılıyorsam lütfen beni düzeltin (şimdi tam olarak anlamaya çalışıyorum):


# EXAMPLE #1
>>> class A(object):
...     def foo(cls):
...             print cls
...     foo = classmethod(foo)
... 
>>> a = A()
>>> a.foo()
# THIS IS THE CLASS ITSELF (__class__)
class '__main__.A'

# EXAMPLE #2
# SAME AS ABOVE (With new @decorator)
>>> class A(object):
...     @classmethod
...     def foo(cls):
...             print cls
... 
>>> a = A()
>>> a.foo()
class '__main__.A'

# EXAMPLE #3
>>> class B(object):
...     def foo(self):
...             print self
... 
>>> b = B()
>>> b.foo()
# THIS IS THE INSTANCE WITH ADDRESS (self)
__main__.B object at 0xb747a8ec
>>>

Umarım bu resim gösterir ..


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.