पायथन डेकोरेटर्स के लिए कुछ सामान्य उपयोग क्या हैं? [बन्द है]


337

जबकि मैं खुद को एक बहुत ही सक्षम पायथन कोडर के रूप में सोचना पसंद करता हूं, भाषा का एक पहलू जो मैं कभी नहीं कर सका हूं वह सज्जाकार है।

मुझे पता है कि वे क्या कर रहे हैं (सतही तौर पर), मैंने स्टैच ओवरफ्लो पर ट्यूटोरियल, उदाहरण, प्रश्न पढ़े हैं, और मैं सिंटैक्स को समझता हूं, अपना खुद का लिख ​​सकता हूं, कभी-कभी @classmethod और @staticmethod का उपयोग कर सकता हूं, लेकिन कभी भी मेरे लिए उपयोग नहीं होता है a मेरे अपने पायथन कोड में एक समस्या को हल करने के लिए डेकोरेटर। मुझे कभी भी ऐसी समस्या का सामना नहीं करना पड़ता जहां मुझे लगता है, "हम्म ... यह एक डेकोरेटर के लिए एक नौकरी की तरह दिखता है!"

इसलिए, मैं सोच रहा था कि क्या आप लोग अपने स्वयं के कार्यक्रमों में डेकोरेटर का उपयोग करने के कुछ उदाहरण पेश कर सकते हैं, और उम्मीद है कि मेरे पास "ए-हा!" पल और उन्हें प्राप्त करें।


5
इसके अलावा, डेकोरेटिंग मेमोइज़िंग के लिए उपयोगी होते हैं - जो किसी फ़ंक्शन के धीमी-से-गणना परिणाम को कैशिंग कर रहा है। डेकोरेटर एक फ़ंक्शन वापस कर सकता है जो इनपुट्स की जांच करता है, और यदि वे पहले से ही प्रस्तुत किए गए हैं, तो एक कैश्ड परिणाम लौटाएं।
पीटर

1
ध्यान दें कि पाइथन में एक बिल्ट-इन डेकोरेटर है, functools.lru_cacheजो वास्तव में पीटर ने कहा है, चूंकि पायथन 3.2, फरवरी 2011 में जारी किया गया था।
ताईयुंग जुंग

पायथन डेकोरेटर लाइब्रेरी की सामग्री आपको उनके लिए अन्य उपयोगों का एक अच्छा विचार देना चाहिए।
मार्टिअन

जवाबों:


126

मैं मुख्य रूप से समय के प्रयोजनों के लिए सज्जाकारों का उपयोग करता हूं

def time_dec(func):

  def wrapper(*arg):
      t = time.clock()
      res = func(*arg)
      print func.func_name, time.clock()-t
      return res

  return wrapper


@time_dec
def myFunction(n):
    ...

13
यूनिक्स के तहत, time.clock()सीपीयू समय को मापता है। time.time()यदि आप दीवार-घड़ी समय को मापना चाहते हैं, तो आप इसके बजाय उपयोग करना चाह सकते हैं ।
Jabba

20
महान उदाहरण! हालांकि यह क्या करता है कोई विचार नहीं है। एक स्पष्टीकरण जो आप वहां कर रहे हैं, और डेकोरेटर समस्या को हल करता है वह बहुत अच्छा होगा।
16

7
खैर, इसे myFunctionचलाने में लगने वाले समय को मापता है ...
आरएसबीटी

98

मैंने उन्हें सिंक्रनाइज़ेशन के लिए उपयोग किया है।

import functools

def synchronized(lock):
    """ Synchronization decorator """
    def wrap(f):
        @functools.wraps(f)
        def newFunction(*args, **kw):
            lock.acquire()
            try:
                return f(*args, **kw)
            finally:
                lock.release()
        return newFunction
    return wrap

जैसा कि टिप्पणियों में कहा गया है, पायथन 2.5 के बाद से आप डेकोरेटर के कार्यान्वयन को सरल बनाने के लिए ऑब्जेक्ट (या संस्करण 2.6 के बाद से) withके साथ संयोजन में उपयोग कर सकते हैं :threading.Lockmultiprocessing.Lock

import functools

def synchronized(lock):
    """ Synchronization decorator """
    def wrap(f):
        @functools.wraps(f)
        def newFunction(*args, **kw):
            with lock:
                return f(*args, **kw)
        return newFunction
    return wrap

इसके बावजूद, आप इसे इस तरह उपयोग करते हैं:

import threading
lock = threading.Lock()

@synchronized(lock)
def do_something():
  # etc

@synchronzied(lock)
def do_something_else():
  # etc

मूल रूप से यह सिर्फ फंक्शन कॉल के दोनों ओर lock.acquire()/ डालता है lock.release()


18
संभवतः उचित है, लेकिन सज्जाकार स्वाभाविक रूप से भ्रामक हैं। प्रथम वर्ष के नॉब्स जो आपके पीछे आते हैं और आपके कोड को मॉड करने की कोशिश करते हैं। इसे सादगी से बचें: बस do_something () इसके कोड को 'लॉक विद लॉक' के तहत एक ब्लॉक में संलग्न करें और हर कोई आपके उद्देश्य को स्पष्ट रूप से देख सकता है। सज्जाकार बहुत हद तक स्मार्ट दिखने के इच्छुक लोगों द्वारा अत्यधिक उपयोग किए जाते हैं (और वास्तव में बहुत से होते हैं) लेकिन फिर कोड केवल नश्वरता के लिए आता है और अप-अप हो जाता है।
केविन जे। चावल

18
@ केविनजे.राइस अपने कोड को सीमित करें ताकि 'प्रथम वर्ष के नॉब्स' बेहतर समझ सकें कि यह भयानक अभ्यास है। डेकोरेटर सिंटैक्स पढ़ने में बहुत आसान है और कोड को बहुत कम करता है।
तैयारजोन 20

18
जब लेखन, @TaylerJones, कोड पठनीयता मेरी सर्वोच्च प्राथमिकता है। कोड हर बार संशोधित होने पर 7+ बार पढ़ा जाता है। कोड को समझना मुश्किल है (नोब्स के लिए या ऐसे विशेषज्ञों के लिए जो समय के दबाव में काम कर रहे हैं) तकनीकी ऋण है जिसका भुगतान हर बार किसी को स्रोत के पेड़ पर जाना पड़ता है।
केविन जे। चावल

@TaylerJones प्रोग्रामर के लिए सबसे महत्वपूर्ण कार्यों में से एक है स्पष्टता प्रदान करना।
JDOaktown

71

मैं प्रकार की जाँच के मापदंडों के लिए डेकोरेटर का उपयोग करता हूं जो कुछ आरएमआई के माध्यम से मेरे पायथन तरीकों से पारित होते हैं। इसलिए एक ही पैरामीटर की गिनती को दोहराने के बजाय, बार-बार मुंबो-जंबो को अपवाद करना।

उदाहरण के लिए, इसके बजाय:

def myMethod(ID, name):
    if not (myIsType(ID, 'uint') and myIsType(name, 'utf8string')):
        raise BlaBlaException() ...

मैं सिर्फ घोषणा करता हूं:

@accepts(uint, utf8string)
def myMethod(ID, name):
    ...

और accepts()मेरे लिए सभी काम करता है।


15
रुचि रखने वाले किसी के लिए, @acceptsपीईपी 318 में कार्यान्वयन है ।
मार्टीन्यू

2
मुझे लगता है कि टाइपो है .. पहली विधि को स्वीकार किया जाना चाहिए .. आपने दोनों को "myMethod" घोषित किया
DevC

1
@DevC नहीं, यह टाइपो की तरह नहीं दिखता है। चूँकि यह स्पष्ट रूप से "एक्सेप्ट (..)" का कार्यान्वयन नहीं है, और यहाँ "एक्सेप्ट (..)" वह कार्य करता है जो अन्यथा "myMethod (..)" के प्रारंभ में दो लाइनों द्वारा किया जाएगा। केवल व्याख्या जो फिट बैठती है।
एवगेनी सर्गेव

1
टक्कर के लिए खेद है, मैं सिर्फ यह बताना चाहता था कि टाइप किए गए तर्कों के प्रकार की जाँच करना और एक टाइप-इयरर को उठाना अन्यथा एक बुरा अभ्यास माना जाता है क्योंकि यह स्वीकार करने वाला नहीं है उदाहरण के लिए अगर यह केवल फ़्लोट के लिए जाँच करता है, और क्योंकि सामान्य रूप से कोड को अधिकतम लचीलेपन के लिए पारित विभिन्न प्रकार के मूल्यों के लिए अनुकूल होना चाहिए।
गुस्तावो ६०४६

2
पायथन में टाइप चेकिंग करने के लिए अनुशंसित तरीका बिल्ट-इन isinstance()फ़ंक्शन के माध्यम से होता है, क्योंकि यह सज्जाकार के पीईपी 318 कार्यान्वयन में किया जाता है । चूंकि इसका classinfoतर्क एक या एक से अधिक प्रकार का हो सकता है, इसलिए इसका उपयोग करना @ Gustavo6046 की (वैध) आपत्तियों को कम करेगा। पायथन में एक Numberसार आधार वर्ग भी है , इसलिए बहुत सामान्य परीक्षण isinstance(42, numbers.Number)संभव हैं।
मार्टीन्यू

48

डेकोरेटर्स का उपयोग किसी भी चीज के लिए किया जाता है जिसे आप अतिरिक्त कार्यक्षमता के साथ पारदर्शी रूप से "रैप" करना चाहते हैं।

Django उन्हें "फ़ंक्शन आवश्यक" कार्यक्षमता को देखने के कार्यों के साथ-साथ फ़िल्टर फ़ंक्शन को पंजीकृत करने के लिए रैप करने के लिए उपयोग करता है ।

कक्षाओं में नाम लॉग को जोड़ने के लिए आप क्लास डेकोरेटर्स का उपयोग कर सकते हैं ।

किसी भी पर्याप्त सामान्य कार्यक्षमता जिसे आप मौजूदा क्लास या फ़ंक्शन के व्यवहार पर "व्यवहार" कर सकते हैं, सजावट के लिए उचित खेल है।

PEP 31 -8 द्वारा सजाए गए पायथन-देव समाचार समूह पर उपयोग के मामलों की एक चर्चा भी है - कार्य और विधियों के लिए सज्जाकार


Cherrypy का उपयोग करता है @ cherrypy.expose सीधे रखने के लिए कि कौन से कार्य सार्वजनिक हैं और कौन से छिपे हुए कार्य हैं। यह मेरा पहला परिचय था और मुझे इसकी आदत थी।
मार्क मैक्समिस्टर

26

Nosetests के लिए, आप एक डेकोरेटर लिख सकते हैं जो एक यूनिट परीक्षण फ़ंक्शन या विधि की आपूर्ति करता है जिसमें कई मापदंडों का सेट होता है:

@parameters(
   (2, 4, 6),
   (5, 6, 11),
)
def test_add(a, b, expected):
    assert a + b == expected

23

मुड़ पुस्तकालय जनरेटर के साथ संयुक्त सज्जाकार का उपयोग करता है ताकि यह भ्रम पैदा किया जा सके कि एक अतुल्यकालिक फ़ंक्शन तुल्यकालिक है। उदाहरण के लिए:

@inlineCallbacks
def asyncf():
    doStuff()
    yield someAsynchronousCall()
    doStuff()
    yield someAsynchronousCall()
    doStuff()

इसका उपयोग करते हुए, कोड जो कि एक छोटे कॉलबैक फ़ंक्शन के एक टन में टूट गया होता है, को स्वाभाविक रूप से एकल ब्लॉक के रूप में लिखा जा सकता है, जिससे इसे समझना और बनाए रखना बहुत आसान हो जाता है।


14

एक स्पष्ट उपयोग लॉगिंग के लिए है, बिल्कुल:

import functools

def log(logger, level='info'):
    def log_decorator(fn):
        @functools.wraps(fn)
        def wrapper(*a, **kwa):
            getattr(logger, level)(fn.__name__)
            return fn(*a, **kwa)
        return wrapper
    return log_decorator

# later that day ...
@log(logging.getLogger('main'), level='warning')
def potentially_dangerous_function(times):
    for _ in xrange(times): rockets.get_rocket(NUCLEAR=True).fire()

10

मैं उन्हें मुख्य रूप से डिबगिंग के लिए उपयोग करता हूं (एक फ़ंक्शन के चारों ओर आवरण जो इसके तर्कों और परिणाम को प्रिंट करता है) और सत्यापन (उदाहरण के लिए यह जांचने के लिए कि क्या तर्क सही प्रकार का है या, वेब एप्लिकेशन के मामले में, यदि उपयोगकर्ता के पास किसी विशेष कॉल को प्राप्त करने के लिए पर्याप्त विशेषाधिकार हैं तरीका)।


6

मैं एक समारोह सूत्र बनाने के लिए निम्नलिखित डेकोरेटर का उपयोग कर रहा हूं। यह कोड को अधिक पठनीय बनाता है। यह लगभग जॉन फ़ूही द्वारा प्रस्तावित एक के समान है लेकिन अंतर यह है कि एक ही कार्य पर एक काम करता है और एक ताला वस्तु को स्पष्ट रूप से बनाने की आवश्यकता नहीं है।

def threadsafe_function(fn):
    """decorator making sure that the decorated function is thread safe"""
    lock = threading.Lock()
    def new(*args, **kwargs):
        lock.acquire()
        try:
            r = fn(*args, **kwargs)
        except Exception as e:
            raise e
        finally:
            lock.release()
        return r
    return new

class X:
    var = 0

    @threadsafe_function     
    def inc_var(self):
        X.var += 1    
        return X.var

1
क्या इसका मतलब प्रत्येक कार्य है, इसलिए सजाया गया है, इसका अपना ताला है?
शोक करें

1
@ हाँ, हर बार जब डेकोरेटर का उपयोग किया जाता है (कहा जाता है) यह फ़ंक्शन / विधि को सजाने के लिए एक नया लॉक ऑब्जेक्ट बनाता है।
मार्टिउ

5
यह वास्तव में खतरनाक है। Inc_var () विधि "थ्रेडसेफ़" है जिसमें एक समय में केवल एक ही व्यक्ति इसे कॉल कर सकता है। कहा कि, चूंकि विधि सदस्य चर "var" पर चल रही है और संभवत: अन्य विधियाँ भी सदस्य चर "var" पर काम कर सकती हैं और वे एक्सेस थ्रेडसेफ़ नहीं हैं क्योंकि लॉक साझा नहीं किया गया है। इस तरह से चीजें करने से दसवीं कक्षा के उपयोगकर्ता को सुरक्षा का झूठा एहसास होता है।
बॉब वान ज़ैंट

जब तक एकल लॉक का उपयोग नहीं किया जाता है, थ्रेड्स सुरक्षित नहीं होते हैं।
चंदू

5

डेकोरेटर या तो एक फ़ंक्शन के गुणों को परिभाषित करने के लिए या बॉयलरप्लेट के रूप में उपयोग किया जाता है जो इसे बदल देता है; यह संभव है लेकिन उनके लिए पूरी तरह से अलग-अलग कार्यों को वापस करने के लिए काउंटर-सहज ज्ञान युक्त। यहां अन्य प्रतिक्रियाओं को देखते हुए, ऐसा लगता है कि सबसे आम उपयोगों में से एक कुछ अन्य प्रक्रिया के दायरे को सीमित करना है - यह लॉगिंग, प्रोफाइलिंग, सुरक्षा जांच आदि।

चेरीपी ऑब्जेक्ट को यूआरएल से मिलान करने के लिए ऑब्जेक्ट-डिस्पैचिंग और अंततः, विधियों का उपयोग करता है। उन तरीकों पर सज्जाकार संकेत देते हैं कि चेरीप्री को उन तरीकों का उपयोग करने की अनुमति है या नहीं । उदाहरण के लिए, ट्यूटोरियल से अनुकूलित :

class HelloWorld:

    ...

    def secret(self):
        return "You shouldn't be here."

    @cherrypy.expose
    def index(self):
        return "Hello world!"

cherrypy.quickstart(HelloWorld())

यह सच नहीं है। एक डेकोरेटर एक फ़ंक्शन के व्यवहार को पूरी तरह से बदल सकता है।
पुनरावर्ती

ठीक है। लेकिन कितनी बार एक डेकोरेटर "एक फ़ंक्शन के व्यवहार को पूरी तरह से बदल देता है?" मैंने जो देखा है, जब वे गुणों को निर्दिष्ट करने के लिए उपयोग नहीं किए जाते हैं, तो वे केवल बॉयलरप्लेट कोड के लिए उपयोग किए जाते हैं। मैंने अपनी प्रतिक्रिया संपादित की है।
निखिल चेलिया

5

मैंने हाल ही में उनका उपयोग किया, सोशल नेटवर्किंग वेब एप्लिकेशन पर काम करते हुए। समुदाय / समूहों के लिए, मुझे सदस्यता चर्चा को नई चर्चा बनाने के लिए देना था और एक संदेश का जवाब देना होगा जो आपको उस विशेष समूह का सदस्य होना चाहिए। इसलिए, मैंने एक डेकोरेटर लिखा @membership_requiredऔर कहा कि मुझे अपने विचार में जहां आवश्यकता थी।


1

मैं पैरामीटर को ठीक करने के लिए इस डेकोरेटर का उपयोग करता हूं

def fill_it(arg):
    if isinstance(arg, int):
        return "wan" + str(arg)
    else:
        try:
            # number present as string
            if str(int(arg)) == arg:
                return "wan" + arg
            else:
                # This should never happened
                raise Exception("I dont know this " + arg)
                print "What arg?"
        except ValueError, e:
            return arg

def fill_wanname(func):
    def wrapper(arg):
        filled = fill_it(arg)
        return func(filled)
    return wrapper

@fill_wanname
def get_iface_of(wanname):
    global __iface_config__
    return __iface_config__[wanname]['iface']

यह तब लिखा जब मैंने कुछ कार्यों को तर्क से "wanN" पारित करने की आवश्यकता की, लेकिन अपने पुराने कोड में, मैंने N या 'N' को ही पास किया


1

डेकोरेटर को आसानी से फंक्शन मेथड वैरिएबल बनाने के लिए इस्तेमाल किया जा सकता है।

def static_var(varname, value):
    '''
    Decorator to create a static variable for the specified function
    @param varname: static variable name
    @param value: initial value for the variable
    '''
    def decorate(func):
        setattr(func, varname, value)
        return func
    return decorate

@static_var("count", 0)
def mainCallCount():
    mainCallCount.count += 1

6
आपके उदाहरण के लिए धन्यवाद, लेकिन (अपोलजी) मुझे डब्ल्यूटीएफ कहना है - आप इसका उपयोग क्यों करेंगे? इसमें लोगों को भ्रमित करने की बड़ी क्षमता है। बेशक, मुझे किनारे-केस के उपयोग के लिए सम्मान की आवश्यकता है, लेकिन आप एक आम समस्या पर जोर दे रहे हैं जो कई अनुभवहीन पायथन देवों के पास है - पर्याप्त कक्षाओं का उपयोग नहीं करना। यही है, बस गणना का एक सरल वर्ग संस्करण है, इसे इनिशियलाइज़ करें और इसका उपयोग करें। नॉब्स ड्रॉप-थ्रू (नॉन-क्लास-आधारित कोड) लिखने के लिए और विस्तृत कार्यक्षेत्र के साथ वर्ग की कार्यक्षमता की कमी का सामना करने की कोशिश करते हैं। कृपया नहीं? कृप्या? वीणा के लिए खेद है, आपके उत्तर के लिए धन्यवाद, लेकिन आपने मेरे लिए एक हॉट-बटन मारा है।
केविन जे। राइस

मैं इस पर -1 होगा यदि यह मेरे लिए कोड समीक्षा के लिए एक पुल अनुरोध के रूप में दिखाया गया है, और इसलिए मैं भी इस पर अच्छा अजगर के रूप में -1 हूं।
टेकड्रगन

प्यारा। मूर्ख, लेकिन प्यारा। :) मुझे कभी-कभी फ़ंक्शन विशेषता से कोई आपत्ति नहीं है, लेकिन वे विशिष्ट पायथन कोड में ऐसी दुर्लभ चीज़ हैं कि अगर मैं एक का उपयोग करने जा रहा हूं, तो मैं इसे स्पष्ट रूप से करूँगा, बजाय एक सज्जाकार के नीचे छिपाने के लिए।
PM 2Ring
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.