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
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.
Nasıl YAPILIR: Python Girinti Düzeltme...
Nasıl Python fonksiyonu dekoratörler z...
Nasıl tek bir ifadede iki Python sözlü...
Nasıl Python ile bir dizinin tüm dosya...
Nasıl (şap) Python bir satır kaldırabi...