Python'daki sınıf dekoratörleri: pratik kullanım örnekleri


9

Python sınıfı dekoratörlerin pratik ve sentetik olmayan kullanım durumlarını arıyorum. Şimdiye kadar, bana mantıklı gelen tek örnek, bir yayıncı-abone sisteminde örneğin eklentiler veya etkinlikler gibi bir sınıfa kayıt olmaktır:

@register
class MyPlugin(Plugin):
    pass

veya

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

Düşündüğüm diğer aklı başında davalar, kalıtım, metasınıflar veya dekorasyon yöntemleri üzerine inşa edilmiş olabilir. Sınıf dekoratörü kullanmanın iyi (ya da kötü!) Örneklerini paylaşabilir misiniz?

Teşekkür ederim!


Yeni başlayanlar için dekoratörler kavramsal olarak metasınıflardan çok daha basittir. Bir dekoratörü bir metasınıftan yazmak çok daha basittir ve muhtemelen bir şey kırmadan birden fazla metasınıfın nasıl birleştirileceğini bulmak zorunda kalmaz.
amon

@ amon tecrübeli bir geliştirici tarafından bir metasınıf kullanıldığında, genellikle diğer seçeneklerin iyice ele alındığı ve metasınıfın sorunu çözmenin en iyi yolu olduğu anlamına gelir. Dahası, açık, örtük olmaktan iyidir - sınıf dekoratörünün ABCMetadeğil (örnek olarak) sahip olmamızın nedeni bu olabilir @abstractclass.
Zaur Nasibov

2
Ben bir Python programcısıyım ve dürüstçe onlara ihtiyaç duymuyorum. Bir dil özelliğinin mevcut olması, onu kullanmanız gerektiği veya hatta kullanmanız gerektiği anlamına gelmez. Tasarımcılar, gereksiz ve hatta arkaya zarar veren her türlü çılgın özellik ile geliyorlar. Aslında, sorunuzdaki diğer iki özellikten de bahsettiniz :)
gardenhead

1
Olmadan yaşayamayacağım bir şey değil, ama yararlı bulduğum bir şey, sınıfın tüm yöntemlerinin tüm giriş ve çıkışlarını günlüğe kaydetmek için bir sınıf dekoratörü kullanmaktır.
bgusach

Yanıtlar:


8

Birim testleri yazarken @unittest.skipIfve @unittest.skipUnlessya bireysel yöntemlerde ya da tüm unittest.TestCasesınıf tanımında kullanılabilir. Bu, platforma özgü sorunlar için testler yazmayı çok daha kolay hale getirir.

Şu kaynaktan örnek: 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):
...

2

Sınıf dekoratörler açıkça zaten daha hoş metaclasses aracılığıyla expressible bazı şeyleri yapmak için yaratılmıştır PEP :

Motive edici kullanım örneği, belirli yapıların daha kolay ifade edilmesini ve CPython yorumlayıcısının uygulama ayrıntılarına daha az güven duymasını sağlamaktı. Sınıf dekoratörü benzeri işlevselliği metasınıflar kullanarak ifade etmek mümkün olmakla birlikte, sonuçlar genellikle hoş değildir ve uygulama oldukça kırılgandır. Buna ek olarak, metasınıflar kalıtsaldır, oysa sınıf dekoratörleri değildir, bu da metasınıfları sınıf dekoratörlerinin bazı, tek sınıfa özgü kullanımları için uygun hale getirmez. Zope gibi büyük ölçekli Python projelerinin BDFL üzerinde kazandığı sınıf dekoratörleri gibi bir şeyi başarmak için bu vahşi çarpışmalardan geçtiği gerçeği.


PEP-3129'u belirttiğiniz için teşekkür ederiz. Ancak soru, sınıf dekoratörlerinin neden var olduğu, Guido'nun ne düşündüğü ve Zope veya IronPython'un ortaya çıkmadan önce onları nasıl kullanabileceği ile ilgili değil. Soru, bugün 2016 yılında pratik kullanımları ile ilgili.
Zaur Nasibov

1
Doğru, asıl mesele, orijinal sorunun sınıf-dekoratör benzeri işlevselliği uygulamak için kullanılabilecek bir şey olarak metasınıfları getirmesidir, ancak dekoratörlerin tüm amacı, kullanımlarının daha kolay ve metasınıflardan daha açık olmasıdır. Bu yüzden sorunun o kısmının cevabı "Dekoratörler veya metasınıflar arasında sıkışırsanız, dekoratörler kullanmalısınız çünkü başkalarının anlaması daha kolaydır."
quodlibetor

Cevap veren başka sorular bırakıyorsunuz. “... dekoratörün asıl amacı, kullanımlarının daha kolay ve metasınıflardan daha açık olmasıdır” - Hangi durumlarda? Sonra "... dekoratörler kullanmalısınız çünkü başkalarının anlaması daha kolay" Gerçekten mi? Python'a uzun süre bağımlılık yaptığım için tonlarca metasınıf gördüm, bazıları çirkin, bazıları güzel. Ama hiç bir sınıf dekoratörü keşfetmedim.
Zaur Nasibov

1

Gönderen bu yığın taşması soruya:

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

Evet, ama tam tersi aynı SO sorusunda verilir: metasınıf daha iyi bir yaklaşımdır.
Zaur Nasibov

1

Sınıflar üzerinde dekoratörler ile yapılabilecek kullanım durumları aramak boşuna - sınıflar üzerinde dekoratörler ile yapılabilecek her şey metasınıflarla yapılabilir. Kayıt örneğiniz bile. Bunu kanıtlamak için, bir dekoratör uygulayan bir metasınıf:

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

1
Dediğiniz gibi - dekoratör ile her şey yapılabilir. Soru, metasınıflar yerine sınıf dekoratörleri aracılığıyla yapılması gereken durumlar nelerdir .
Zaur Nasibov
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.