Dekorator kelas dengan Python: kasus penggunaan praktis

9

Saya mencari kasus penggunaan praktis dan non-sintetis dekorator kelas Python. Sejauh ini, satu-satunya kasus yang masuk akal bagi saya adalah mendaftarkan kelas di sistem penerbit-pelanggan, misalnya plugin atau acara, seperti:

@register
class MyPlugin(Plugin):
    pass

atau

@recieves_notifications
class Console:
    def print(self, text):
        ...

Kasus waras lain yang saya pikirkan bisa saja dibangun di atas warisan, metaclasses atau metode dekorasi. Bisakah Anda berbagi contoh yang baik (atau buruk!) Menggunakan dekorator kelas?

Terima kasih!

Zaur Nasibov
sumber
Sebagai permulaan, dekorator secara konsep jauh lebih sederhana daripada metaclasses. Jauh lebih mudah untuk menulis dekorator daripada metaclass, dan menghindari kemungkinan harus mencari cara untuk menggabungkan beberapa metaclasses tanpa merusak apa pun.
amon
@amon ketika metaclass digunakan oleh pengembang berpengalaman, biasanya berarti bahwa opsi lain telah dipertimbangkan secara menyeluruh dan metaclass sejauh ini merupakan cara terbaik untuk menyelesaikan masalah. Selain itu, eksplisit lebih baik daripada implisit - itu mungkin menjadi alasan mengapa (sebagai contoh) kita miliki ABCMeta, bukan @abstractclassdekorator kelas.
Zaur Nasibov
2
Saya seorang programmer Python, dan jujur ​​saya tidak melihat kebutuhan untuk mereka. Hanya karena fitur bahasa ada bukan berarti Anda harus atau bahkan harus menggunakannya. Desainer datang dengan semua jenis fitur gila yang ternyata tidak perlu atau bahkan merusak dengan melihat ke belakang. Bahkan, Anda menyebutkan dua fitur lain dalam pertanyaan Anda :)
gardenhead
1
Bukan sesuatu yang saya tidak bisa hidup tanpanya, tetapi sesuatu yang saya temukan bermanfaat adalah menggunakan dekorator kelas untuk mencatat semua input dan output dari semua metode kelas.
bgusach

Jawaban:

8

Saat menulis tes unit memiliki @unittest.skipIfdan @unittest.skipUnlessdapat digunakan pada metode individu atau pada seluruh unittest.TestCasedefinisi kelas. Ini membuat penulisan tes untuk masalah spesifik platform jadi lebih mudah.

Contoh dari asyncio/test_selectors

# Some platforms don't define the select.kqueue object for these tests.
# On those platforms, this entire grouping of tests will be skipped.

@unittest.skipUnless(hasattr(selectors, 'KqueueSelector'),
                 "Test needs selectors.KqueueSelector)")
class KqueueSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
...
sethmlarson
sumber
2

Dekorator kelas secara eksplisit dibuat untuk membuat beberapa hal yang sudah dapat diekspresikan melalui metaclasses menjadi lebih menyenangkan, dari PEP :

Kasus penggunaan yang memotivasi adalah untuk membuat konstruksi tertentu lebih mudah diungkapkan dan kurang bergantung pada detail implementasi dari juru bahasa CPython. Meskipun dimungkinkan untuk mengekspresikan fungsionalitas seperti dekorator kelas menggunakan metaclasses, hasilnya umumnya tidak menyenangkan dan implementasinya sangat rapuh. Selain itu, metaclasses diwariskan, sedangkan dekorator kelas tidak, membuat metaclasses tidak cocok untuk beberapa, penggunaan kelas dekorator kelas khusus. Fakta bahwa proyek-proyek Python skala besar seperti Zope sedang melalui liuk liar ini untuk mencapai sesuatu seperti dekorator kelas menang atas BDFL.

quodlibetor
sumber
Terima kasih telah mengutip PEP-3129. Namun pertanyaannya bukan tentang mengapa dekorator kelas ada, apa yang dipikirkan Guido tentang mereka, dan bagaimana Zope atau IronPython dapat menggunakannya sebelum mereka muncul. Pertanyaannya adalah tentang penggunaan praktis mereka hari ini, di tahun 2016.
Zaur Nasibov
1
Benar, intinya adalah bahwa pertanyaan awal menampilkan metaclasses sebagai sesuatu yang dapat digunakan untuk mengimplementasikan fungsionalitas seperti dekorator kelas, tetapi seluruh poin dekorator adalah bahwa mereka lebih mudah digunakan dan lebih jelas daripada metaclasses. Jadi jawaban untuk bagian pertanyaan itu adalah "Jika Anda terbelah antara dekorator atau metaclasses, Anda harus menggunakan dekorator karena mereka lebih mudah dimengerti orang lain."
quodlibetor
Anda meninggalkan lebih banyak pertanyaan yang menjawab. "... inti dari dekorator adalah bahwa mereka lebih mudah digunakan dan lebih jelas daripada metaclasses" - Dalam kasus apa? Lalu "... kamu harus menggunakan dekorator karena mereka lebih mudah dimengerti orang lain" Benarkah? Untuk waktu yang lama kecanduan Python, saya telah melihat banyak metaclasses, beberapa jelek, beberapa cantik. Tetapi belum menemukan dekorator kelas sama sekali.
Zaur Nasibov
1

Dari ini pertanyaan stack overflow:

def singleton(class_):
  instances = {}
  def getinstance(*args, **kwargs):
    if class_ not in instances:
        instances[class_] = class_(*args, **kwargs)
    return instances[class_]
  return getinstance

@singleton
class MyClass(BaseClass):
  pass
Jared Smith
sumber
Yap, tetapi kontra diberikan tepat pada pertanyaan SO yang sama: metaclass adalah pendekatan yang lebih baik.
Zaur Nasibov
1

Mencari kasus penggunaan yang dapat dilakukan dengan dekorator di kelas adalah sia-sia - apa pun yang dapat dilakukan dengan dekorator di kelas dapat dilakukan dengan metaclasses. Bahkan contoh pendaftaran Anda. Untuk membuktikannya, ini adalah metaclass yang menerapkan dekorator:

Python 2:

def register(target):
    print 'Registring', target
    return target


class ApplyDecorator(type):
    def __new__(mcs, name, bases, attrs):
        decorator = attrs.pop('_decorator')
        cls = type(name, bases, attrs)
        return decorator(cls)

    def __init__(cls, name, bases, attrs, decorator=None):
        super().__init__(name, bases, attrs)


class Foo:
    __metaclass__ = ApplyDecorator
    _decorator = register

Python 3:

def register(target):
    print('Registring', target)
    return target


class ApplyDecorator(type):
    def __new__(mcs, name, bases, attrs, decorator):
        cls = type(name, bases, attrs)
        return decorator(cls)

    def __init__(cls, name, bases, attrs):
        super().__init__(name, bases, attrs)


class Foo(metaclass=ApplyDecorator, decorator=register):
    pass
Idan Arye
sumber
1
Seperti yang Anda katakan - apa pun bisa dilakukan dengan dekorator. Pertanyaannya adalah, apa kasus yang harus dilakukan melalui dekorator kelas daripada metaclasses.
Zaur Nasibov