[Python] पायथन फ़ंक्शन विशेषताएँ - उपयोग और दुरुपयोग


Answers

मैंने उन्हें फ़ंक्शन के लिए स्थिर चर के रूप में उपयोग किया है। उदाहरण के लिए, निम्नलिखित सी कोड दिया गया है:

int fn(int i)
{
    static f = 1;
    f += i;
    return f;
}

मैं पाइथन में समान रूप से फ़ंक्शन को कार्यान्वित कर सकता हूं:

def fn(i):
    fn.f += i
    return fn.f
fn.f = 1

यह निश्चित रूप से स्पेक्ट्रम के "दुरुपयोग" अंत में गिर जाएगा।

Question

इस सुविधा के बारे में बहुत से लोग नहीं जानते हैं, लेकिन पायथन के कार्यों (और विधियों) में attributes हो सकते हैं। निहारना:

>>> def foo(x):
...     pass
...     
>>> foo.score = 10
>>> dir(foo)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name', 'score']
>>> foo.score
10
>>> foo.score += 1
>>> foo.score
11

पायथन में इस सुविधा के संभावित उपयोग और दुरुपयोग क्या हैं? एक अच्छा उपयोग मुझे पता है कि एक विधि के साथ एक वाक्यविन्यास नियम को जोड़ने के लिए पीएलवाई का डॉकस्ट्रिंग का उपयोग है। लेकिन कस्टम विशेषताओं के बारे में क्या? क्या उनका उपयोग करने के अच्छे कारण हैं?




फंक्शन विशेषताओं का उपयोग लाइट-वेट क्लोजर लिखने के लिए किया जा सकता है जो कोड और संबंधित डेटा को एक साथ लपेटते हैं:

#!/usr/bin/env python

SW_DELTA = 0
SW_MARK  = 1
SW_BASE  = 2

def stopwatch():
   import time

   def _sw( action = SW_DELTA ):

      if action == SW_DELTA:
         return time.time() - _sw._time

      elif action == SW_MARK:
         _sw._time = time.time()
         return _sw._time

      elif action == SW_BASE:
         return _sw._time

      else:
         raise NotImplementedError

   _sw._time = time.time() # time of creation

   return _sw

# test code
sw=stopwatch()
sw2=stopwatch()
import os
os.system("sleep 1")
print sw() # defaults to "SW_DELTA"
sw( SW_MARK )
os.system("sleep 2")
print sw()
print sw2()

१.००९३४००४७८४

२.००६४४३९७७३६

३.०१५९३४९४४१५




कभी-कभी मैं पहले से गणना किए गए मानों को कैशिंग के लिए फ़ंक्शन की विशेषता का उपयोग करता हूं। आप एक सामान्य सजावट भी कर सकते हैं जो इस दृष्टिकोण को सामान्यीकृत करता है। इस तरह के कार्यों के समवर्ती मुद्दों और साइड इफेक्ट्स से अवगत रहें!




मैंने फ़ंक्शन विशेषताओं को आसानी से सेट करने के लिए इस सहायक सजावट को बनाया है:

def with_attrs(**func_attrs):
    """Set attributes in the decorated function, at definition time.
    Only accepts keyword arguments.
    E.g.:
        @with_attrs(counter=0, something='boing')
        def count_it():
            count_it.counter += 1
        print count_it.counter
        print count_it.something
        # Out:
        # >>> 0
        # >>> 'boing'
    """
    def attr_decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            return fn(*args, **kwargs)

        for attr, value in func_attrs.iteritems():
            setattr(wrapper, attr, value)

        return wrapper

    return attr_decorator

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

@with_attrs(datatype=list)
def factory1():
    return [1, 2, 3]

@with_attrs(datatype=SomeClass)
def factory2():
    return SomeClass()

factories = [factory1, factory2]

def create(datatype):
    for f in factories:
        if f.datatype == datatype:
            return f()
    return None