स्व तर्क के साथ वर्ग विधि डेकोरेटर?


154

मैं एक तर्क के रूप में एक क्लास विधि पर एक डेकोरेटर के लिए एक क्लास फील्ड कैसे पास करूं? मैं जो करना चाहता हूं वह कुछ इस तरह है:

class Client(object):
    def __init__(self, url):
        self.url = url

    @check_authorization("some_attr", self.url)
    def get(self):
        do_work()

यह शिकायत करता self.urlहै कि डेकोरेटर को पास करने के लिए स्वयं मौजूद नहीं है । क्या इसके चारों ओर एक रास्ता है?


क्या यह एक कस्टम डेकोरेटर है जिस पर आपका नियंत्रण है, या जिसे आप बदल नहीं सकते हैं?
जोएल कॉर्नेट

यह मेरा डेकोरेटर है, इसलिए मेरा इस पर पूरा नियंत्रण है
मार्क

इससे पहले कि मुझे लगता है कि यह समस्या है मुझे लगता है ...
जोरन Beasley

7
समस्या यह है कि स्वयं फंक्शन डेफिनिशन समय पर मौजूद नहीं है। आपको इसे आंशिक फ़ंक्शन में बनाने की आवश्यकता है।
एंटिमोनी

जवाबों:


208

हाँ। क्लास डेफिनिशन समय में इंस्टेंस विशेषता में पास होने के बजाय, इसे रनटाइम पर जांचें:

def check_authorization(f):
    def wrapper(*args):
        print args[0].url
        return f(*args)
    return wrapper

class Client(object):
    def __init__(self, url):
        self.url = url

    @check_authorization
    def get(self):
        print 'get'

>>> Client('http://www.google.com').get()
http://www.google.com
get

डेकोरेटर विधि तर्कों को स्वीकार करता है; पहला तर्क उदाहरण है, इसलिए यह उस विशेषता को पढ़ता है। आप डेकोरेटर के लिए एक स्ट्रिंग के रूप में विशेषता नाम में पारित कर सकते हैं और उपयोग getattrकर सकते हैं यदि आप विशेषता नाम को हार्डकोड नहीं करना चाहते हैं:

def check_authorization(attribute):
    def _check_authorization(f):
        def wrapper(self, *args):
            print getattr(self, attribute)
            return f(self, *args)
        return wrapper
    return _check_authorization

38
from re import search
from functools import wraps

def is_match(_lambda, pattern):
    def wrapper(f):
        @wraps(f)
        def wrapped(self, *f_args, **f_kwargs):
            if callable(_lambda) and search(pattern, (_lambda(self) or '')): 
                f(self, *f_args, **f_kwargs)
        return wrapped
    return wrapper

class MyTest(object):

    def __init__(self):
        self.name = 'foo'
        self.surname = 'bar'

    @is_match(lambda x: x.name, 'foo')
    @is_match(lambda x: x.surname, 'foo')
    def my_rule(self):
        print 'my_rule : ok'

    @is_match(lambda x: x.name, 'foo')
    @is_match(lambda x: x.surname, 'bar')
    def my_rule2(self):
        print 'my_rule2 : ok'



test = MyTest()
test.my_rule()
test.my_rule2()

ouput: my_rule2: ठीक है


@raphael इस सेटअप में मैं _lambda या पैटर्न का उपयोग नहीं कर सकता। मैं कैसे उपाय कर सकता हूं।
जोनाथन

1
@ राफेल: मैं क्लासमैथोड के लिए कैसे कर सकता हूं, क्योंकि यहां सभी तरीके उदाहरण के तरीके हैं।
अपूर्वा कुंकुलोल

38

एक अधिक संक्षिप्त उदाहरण इस प्रकार हो सकता है:

#/usr/bin/env python3
from functools import wraps

def wrapper(method):
    @wraps(method)
    def _impl(self, *method_args, **method_kwargs):
        method_output = method(self, *method_args, **method_kwargs)
        return method_output + "!"
    return _impl

class Foo:
    @wrapper
    def bar(self, word):
        return word

f = Foo()
result = f.bar("kitty")
print(result)

जो प्रिंट करेगा:

kitty!

6

एक अन्य विकल्प सिंटैक्टिक शुगर को छोड़ना और __init__कक्षा में सजाना होगा ।

def countdown(number):
    def countdown_decorator(func):
        def func_wrapper():
            for index in reversed(range(1, number+1)):
                print("{}".format(index))
            func()
        return func_wrapper
    return countdown_decorator

class MySuperClass():
    def __init__(self, number):
        self.number = number
        self.do_thing = countdown(number)(self.do_thing)

    def do_thing(self):
        print('im doing stuff!')


myclass = MySuperClass(3)

myclass.do_thing()

जो छपेगा

3
2
1
im doing stuff!

4

आप नहीं कर सकते। कोई है selfक्योंकि कोई उदाहरण मौजूद है, वर्ग शरीर में। आपको इसे पास करने की आवश्यकता होगी, कहते हैं, strउदाहरण पर देखने के लिए विशेषता नाम युक्त, जिसे लौटाया गया फ़ंक्शन तब कर सकता है, या पूरी तरह से एक अलग विधि का उपयोग कर सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.