SORU
6 Mayıs 2011, Cuma


Nasıl yapılır verilen dekoratör ile bir python sınıfının tüm metotlarını

Nasıl @decorator2 dekore edilmiş olan belirli bir sınıfın Bir bütün yöntemleri almak için?

class A():
    def method_a(self):
      pass

    @decorator1
    def method_b(self, b):
      pass

    @decorator2
    def method_c(self, t=5):
      pass

CEVAP
6 Mayıs 2011, Cuma


Yöntem 1: Temel kayıt dekoratör

Ben zaten burada bu soruyu yanıtladı:* = *54)


Yöntem 2: kaynak kod ayrıştırma

Bu kontrol yoksasınıftanımsanırım doğru bir yorum değil buimkansızörneğin dekoratör sadece döndüren hayır-op bir dekoratör (bağlı benim örnekte olduğu gibi) olabilir beri (kod-okuma-yansıma) olmadan, işlevi değişmemiş. Yine de eğer kendinizi/dekoratörler wrap yeniden tanımlamak için izin verirseniz (bkzYöntem 3: dekoratörler için Dönüştürme "öz-farkındalık"sonra zarif bir çözüm bulmak)

Bir korkunç korkunç kesmek, ama inspect modül yaptırıyor kendisi okumak için kullanın, ve ayrıştırılamadı. Bu modülü etkileşimli modda yaptırıyor bunları söyleyecektir inceleyin çünkü interaktif bir tercüman olarak çalışmaz. Ancak, aşağıda bir kanıtı.

#!/usr/bin/python3

import inspect

def deco(func):
    return func

def deco2():
    def wrapper(func):
        pass
    return wrapper

class Test(object):
    @deco
    def method(self):
        pass

    @deco2()
    def method2(self):
        pass

def methodsWithDecorator(cls, decoratorName):
    sourcelines = inspect.getsourcelines(cls)[0]
    for i,line in enumerate(sourcelines):
        line = line.strip()
        if line.split('(')[0].strip() == '@' decoratorName: # leaving a bit out
            nextLine = sourcelines[i 1]
            name = nextLine.split('def')[1].split('(')[0].strip()
            yield(name)

İşe yarıyor!:

>>> print(list(  methodsWithDecorator(Test, 'deco')  ))
['method']

Not Bu bir dikkat ayrıştırma ve python sözdizimi, örneğin @deco @deco(... geçerli kabul edilen @deco2 olmamalı döndü eğer biz sadece sormak için 'deco'. http://docs.python.org/reference/compound_stmts.html resmi python sözdizimi göre dekoratörler aşağıdaki gibi olduğunu fark ettik

decorator      ::=  "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE

@(deco) gibi bir dava ile uğraşmak zorunda kalmadan rahat bir nefes nefes. Ama bu gerçekten gerçekten gerçekten dekoratörler, @getDecorator(...) örneğin gibi karmaşık varsa yardımcı olmuyor unutmayın

def getDecorator():
    return deco

Böylece, kod ayrıştırma en iyi----Bu strateji, bu gibi durumlarda algılar. Eğer bu yöntemi kullanıyorsanız rağmen, gerçekten neyin peşinde olduğunuzu bu durumda getDecorator hangi tanımlama yöntemi, üstüne yazılır.

Spec göre, aynı zamanda bir mimar olarak @foo1.bar2.baz3(...) için geçerlidir. Bu yöntem ile çalışmak genişletebilirsiniz. Ayrıca bu yöntem, işlev adı, çaba ile yerine <function object ...> dönüş uzatmak mümkün olabilir. Bu yöntem, ancak hackish ve korkunç.


Yöntem 3: dekoratörler için Dönüştürme "öz-farkındalık"

Bu kontrol yoksadekoratörtanımistediğin başka bir yorumu olan, bu konular üzerinden gidin çünkü nasıl dekoratör uygulanır. Böylece, dekoratör değiştirsarmabu, oluşturmak içinkendidekoratör ve kullanınbufonksiyonları süslemek için. Bilin ki, bu yine: sen-ebilmek yapmak bir dekoratör olduğunu süsleyen dekoratör var üzerinde hiçbir kontrolü, "aydınlatıcı" bu, bizim davamız yapar ne oldu yapmadan önce amaayrıca29 ** çağrı özelliği için meta verileri, seni izlemek için izin verir, bu fonksiyon dekore edilmiş"? Ekle hadi kontrol fonksiyonu.". dekoratör! Vesonrasınıfının yöntemleri üzerinde yineleme, ve sadece kontrol ederseniz dekoratör .decorator uygun özelliği olup olmadığını görmek için! Burada gösterildiği gibi=):

def makeRegisteringDecorator(foreignDecorator):
    """
        Returns a copy of foreignDecorator, which is identical in every
        way(*), except also appends a .decorator property to the callable it
        spits out.
    """
    def newDecorator(func):
        # Call to newDecorator(method)
        # Exactly like old decorator, but output keeps track of what decorated it
        R = foreignDecorator(func) # apply foreignDecorator, like call to foreignDecorator(method) would have done
        R.decorator = newDecorator # keep track of decorator
        #R.original = func         # might as well keep track of everything!
        return R

    newDecorator.__name__ = foreignDecorator.__name__
    newDecorator.__doc__ = foreignDecorator.__doc__
    # (*)We can be somewhat "hygienic", but newDecorator still isn't signature-preserving, i.e. you will not be able to get a runtime list of parameters. For that, you need hackish libraries...but in this case, the only argument is func, so it's not a big issue

    return newDecorator

@decorator gösteri:

deco = makeRegisteringDecorator(deco)

class Test2(object):
    @deco
    def method(self):
        pass

    @deco2()
    def method2(self):
        pass

def methodsWithDecorator(cls, decorator):
    """ 
        Returns all methods in CLS with DECORATOR as the
        outermost decorator.

        DECORATOR must be a "registering decorator"; one
        can make any decorator "registering" via the
        makeRegisteringDecorator function.
    """
    for maybeDecorated in cls.__dict__.values():
        if hasattr(maybeDecorated, 'decorator'):
            if maybeDecorated.decorator == decorator:
                print(maybeDecorated)
                yield maybeDecorated

İşe yarıyor!:

>>> print(list(   methodsWithDecorator(Test2, deco)   ))
[<function method at 0x7d62f8>]

Ancak, bir "kayıtlı mimar" olması gerekiyoren dıştaki dekoratör.decorator öznitelik açıklama kaybolacak , aksi takdirde. Bir trende örneğin

@decoOutermost
@deco
@decoInnermost
def func(): ...

sadece başvurular devam ettiğimiz sürece decoOutermost ortaya çıkaran meta görebilirsiniz "daha iç" paketleri.

Not: Yukarıdaki yöntem de izler .decorator birikebilirve fonksiyonları ve dekoratör-fabrika argümanlar uygulanan dekoratörler giriş yığını tüm. Eğer açıklamalı hat çıkışı göz önüne alırsak =) örneğin R.original = func, mümkün böyle bir yöntem tüm sarıcı katmanları izlemek için kullanın. Bu derin iç gözlem için izin verir, çünkü dekoratör bir kütüphane yazsam, ne yapardım şahsen.

Ayrıca @foo @bar(...) arasında bir fark yoktur. "Spec olarak tanımlanan, foo bar(...) dinamik olarak oluşturulan sonra uygulanan dekoratör,. bir verir, ancak bir dekoratör olduğunu unutmayın "dekoratör expressons ikisi de olsa Böylece ayrı bir fonksiyon lazım biraz makeRegisteringDecorator ama DAHA da META gibi makeRegisteringDecoratorFactory,:

def makeRegisteringDecoratorFactory(foreignDecoratorFactory):
    def newDecoratorFactory(*args, **kw):
        oldGeneratedDecorator = foreignDecoratorFactory(*args, **kw)
        def newGeneratedDecorator(func):
            modifiedFunc = oldGeneratedDecorator(func)
            modifiedFunc.decorator = newDecoratorFactory # keep track of decorator
            return modifiedFunc
        return newGeneratedDecorator
    newDecoratorFactory.__name__ = foreignDecoratorFactory.__name__
    newDecoratorFactory.__doc__ = foreignDecoratorFactory.__doc__
    return newDecoratorFactory

@decorator(...) gösteri:

def deco2():
    def simpleDeco(func):
        return func
    return simpleDeco

deco2 = makeRegisteringDecoratorFactory(deco2)

print(deco2.__name__)
# RESULT: 'deco2'

@deco2()
def f():
    pass

Jeneratör-fabrika yaparak da çalışır:

>>> print(f.decorator)
<function deco2 at 0x6a6408>

bonusHadi bile Yöntem #3 ile aşağıdakileri deneyin:

def getDecorator(): # let's do some dispatching!
    return deco

class Test3(object):
    @getDecorator()
    def method(self):
        pass

    @deco2()
    def method2(self):
        pass

Sonuç:

>>> print(list(   methodsWithDecorator(Test3, deco)   ))
[<function method at 0x7d62f8>]

Gördüğünüz gibi, method2, @aksine deco asla açıkça sınıfta yazılı olmasına rağmen doğru olarak kabul edilmektedir. Method2, bu da eğer bu yöntemi zamanında eklenirse çalışacak (elle, bir metaclass), vb.) aksine ya da miras kaldı.

Ayrıca, eğer sen "" her iki yöntem ve sınıf süslemeleri, ve bir sınıf yazmak için kullanılan bir dekoratör . aydınlat eğer bir sınıf dekore edebilirsiniz farkında ^em>sınıf gövdesi içinde analiz etmek istiyorumo zaman methodsWithDecorator döndürecektir sınıflar olarak dekore edilmiş yöntemleri dekore edilmiş. Bu özelliği göz önünde olabilir, ama kolayca mantık dekoratör için argüman, 53 *yani*, istenen anlamı elde etmek için inceleyerek bu görmezden yazabilirsiniz.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Ben Schoon

    Ben Schoon

    23 Kasım 2012
  • Edge-CGI 3D Tutorials and more!

    Edge-CGI 3D

    11 HAZİRAN 2013
  • USI Events

    USI Events

    6 AĞUSTOS 2013