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


196

बहुत से लोग इस सुविधा से अवगत नहीं हैं, लेकिन पायथन के कार्यों (और विधियों) में विशेषताएं हो सकती हैं । देखो:

>>> 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

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


3
PEP 232 की जाँच करें ।
user140352

2
क्या यह बहुत आश्चर्य की बात है? सामान्य तौर पर, पायथन ऑब्जेक्ट्स तदर्थ विशेषताओं का समर्थन करते हैं। बेशक, कुछ नहीं, विशेष रूप से बिलिन प्रकार वाले। मेरे लिए, जो लोग इसका समर्थन नहीं करते हैं वे अपवाद प्रतीत होते हैं, नियम नहीं।
allyourcode


2
@GrijeshChauhan मैं इन डॉक्स को देखने के बाद इस सवाल पर आया था!
अलेक्जेंडर सुरफेल

5
अफ़सोस कि यह बंद है, मैं जोड़ना चाहता था कि आप किसी भी कस्टम अपवाद को संलग्न कर सकते हैं जो फ़ंक्शन उठा सकता है, कॉलिंग कोड में इसे पकड़ते समय आसान पहुंच प्रदान करने के लिए। मैं एक उदाहरण प्रदान करता हूँ, लेकिन यह एक उत्तर में सबसे अच्छा किया जाता है।
विल हार्डी

जवाबों:


154

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

class Foo(WebService):
    @webmethod
    def bar(self, arg1, arg2):
         ...

तब मैं परिभाषित कर सकता हूं

def webmethod(func):
    func.is_webmethod = True
    return func

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


2
क्या आपको लगता है कि इसके नीचे-किनारे हैं? उदाहरण यदि दो पुस्तकालय एक ही तदर्थ विशेषता लिखने की कोशिश करते हैं तो क्या होगा?
एलियोरकोड 6

18
मैं बिल्कुल यही करने की सोच रहा था। फिर मैंने खुद को रोक लिया। "क्या यह एक बुरा विचार है?" मैं अचंभित हुआ। फिर, मैं एसओ के लिए भटक गया। कुछ बुदबुदाहट के बाद, मुझे यह प्रश्न / उत्तर मिला। अभी भी यकीन नहीं है कि यह एक अच्छा विचार है।
एलियोरकोड 7

7
यह निश्चित रूप से सभी उत्तरों के फ़ंक्शन विशेषताओं का सबसे वैध उपयोग है (नवंबर, 2012 के अनुसार)। अधिकांश (यदि सभी नहीं) अन्य उत्तर वैश्विक चर के प्रतिस्थापन के रूप में फ़ंक्शन विशेषताओं का उपयोग करते हैं; हालाँकि, उन्हें वैश्विक स्थिति से छुटकारा नहीं मिलता है, जो कि वैश्विक चर के साथ समस्या है। यह अलग है, क्योंकि एक बार मूल्य निर्धारित होने के बाद, यह बदलता नहीं है; यह स्थिर है। इसका एक अच्छा परिणाम यह है कि आप सिंक्रनाइज़ेशन समस्याओं में नहीं चलते हैं, जो वैश्विक चर के लिए अंतर्निहित हैं। हां, आप अपना खुद का सिंक्रनाइज़ेशन प्रदान कर सकते हैं, लेकिन यह बात है: यह स्वचालित रूप से सुरक्षित नहीं है।
allyourcode

वास्तव में, मैं कहता हूं, जब तक विशेषता प्रश्न में फ़ंक्शन के व्यवहार को नहीं बदलती, यह अच्छा है। तुलना.__doc__
दिमा तिस्नेक

इस दृष्टिकोण का उपयोग सजाए गए फ़ंक्शन के आउटपुट विवरण को संलग्न करने के लिए भी किया जा सकता है, जो कि अजगर 2 में गायब है। * *।
जुह_ १५'१३

126

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

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

मैं पायथन में इसी तरह से फंक्शन को लागू कर सकता हूं:

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

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


2
दिलचस्प। क्या अजगर में स्थिर चर को लागू करने के अन्य तरीके हैं?
एली बेंडरस्की

4
-1, यह अजगर में एक जनरेटर के साथ लागू किया जाएगा।

124
यह इस जवाब को नीचा दिखाने का एक बहुत खराब कारण है, जो सी और पायथन के बीच एक समानता का प्रदर्शन कर रहा है, न कि इस विशेष कार्य को लिखने के सर्वोत्तम संभव तरीके की वकालत कर रहा है।
रॉबर्ट रोसनी

3
@RobertRossney लेकिन अगर जनरेटर जाने का रास्ता है, तो यह फ़ंक्शन विशेषताओं का एक खराब उपयोग है। यदि ऐसा है, तो यह एक दुरुपयोग है। सुनिश्चित नहीं हैं कि क्या गालियों को उभारना है, क्योंकि सवाल उन लोगों के लिए भी पूछता है: पी
अलॉउरोडेकोड

1
निश्चित रूप से एक दुरुपयोग की तरह लगता है, PEP 232 प्रति, धन्यवाद @ user140352, और हॉप की टिप्पणी और यह SO उत्तर
hobs

53

आप जावास्क्रिप्ट तरीके से ऑब्जेक्ट कर सकते हैं ... इसका कोई मतलब नहीं है लेकिन यह काम करता है;)

>>> def FakeObject():
...   def test():
...     print "foo"
...   FakeObject.test = test
...   return FakeObject
>>> x = FakeObject()
>>> x.test()
foo

36
+1 इस सुविधा के दुरुपयोग का एक अच्छा उदाहरण है, जो उन चीजों में से एक है जो सवाल पूछा गया है।
माइकल डन

1
यह मीपाड़ी के उत्तर से कैसे भिन्न है? लगता है कि एक ही बात हो रही है, एक इंट के बजाय, विशेषता मान एक फ़ंक्शन है।
एलियोरकोड 7

क्या def test()वास्तव में आवश्यक है?
कीर्तन प्रभाकरन

15

मैं उन्हें संयम से इस्तेमाल करता हूं, लेकिन वे बहुत सुविधाजनक हो सकते हैं:

def log(msg):
   log.logfile.write(msg)

अब मैं logअपने पूरे मॉड्यूल का उपयोग कर सकता हूं, और आउटपुट को बस सेट करके रीडायरेक्ट कर सकता हूं log.logfile। इसे पूरा करने के लिए बहुत सारे और बहुत से अन्य तरीके हैं, लेकिन यह एक हल्का और गंदगी सरल है। और जब मैंने इसे पहली बार मजाकिया ढंग से सूंघा, तो मुझे विश्वास है कि यह एक वैश्विक logfileचर होने से बेहतर खुशबू आ रही है ।


7
फिर से गंध: यह हालांकि वैश्विक logfile से छुटकारा नहीं मिलता है। यह सिर्फ एक और वैश्विक, लॉग फ़ंक्शन में इसे दूर करता है।
एलिउरोडेकोड

2
@allyourcode: लेकिन यदि आप एक ही मॉड्यूल में विभिन्न कार्यों के लिए वैश्विक लॉगफ़ाइल्स का एक समूह है, तो यह नाम से बचने में मदद कर सकते हैं।
फायरगुरफिकु

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()

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

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

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


3
जब हमारे पास कक्षाएं होती हैं तो फ़ंक्शंस क्यों धक्का देते हैं? और चलो नहीं भूल जाते हैं कि कक्षाएं एक फ़ंक्शन का अनुकरण कर सकती हैं।
मुहुर्त '

1
यह भी time.sleep(1)बेहतर हैos.system('sleep 1')
बोरिस गोर्लिक

3
@ बर्ग ट्रू, हालांकि यह उदाहरण सोने के बारे में नहीं है।
allyourcode

यह निश्चित रूप से एक दुरुपयोग है; यहाँ कार्यों का उपयोग पूरी तरह से आभारी है। muhuk बिल्कुल सही है: कक्षाएं एक बेहतर समाधान हैं।
allyourcode

1
मैं यह भी पूछूंगा, "एक वर्ग के ऊपर इसका क्या फायदा है?" कई पायथन प्रोग्रामर के लिए यह स्पष्ट नहीं होने के नुकसान का मुकाबला करने के लिए।
cjs

6

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

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

डेकोरेटर कैसे मदद करता है? factory1.datatype=listपुरानी शैली के सज्जाकारों की तरह घोषणा के ठीक नीचे क्यों नहीं ?
सीज़र बॉतिस्ता

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

त्वरित अपडेट: पायथन 3 के साथ आपको items()इसके बजाय उपयोग करने की आवश्यकता है iteritems()
स्कॉट का मतलब

4

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


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

1

मैं हमेशा इस धारणा पर था कि ऐसा करने का एकमात्र कारण संभव था इसलिए डॉक्स-स्ट्रिंग या इस तरह के अन्य सामान को रखने के लिए एक तार्किक स्थान था। मुझे पता है कि अगर मैं किसी भी उत्पादन कोड के लिए इसका इस्तेमाल करता हूं तो यह सबसे ज्यादा भ्रमित करेगा जो इसे पढ़ता है।


1
मैं इस सबसे संभावित रूप से भ्रमित होने के बारे में आपके मुख्य बिंदु से सहमत हूं, लेकिन पुन: docstrings: हाँ, लेकिन फ़ंक्शन में AD-HOC विशेषताएँ क्यों हैं? डॉकस्ट्रिंग को होल्ड करने के लिए, विशेषताओं का एक निश्चित सेट हो सकता है।
allyourcode

@allyourcode भाषा में डिज़ाइन किए गए विशिष्ट तदर्थ मामलों के बजाय सामान्य मामला होने से चीजें सरल हो जाती हैं और पायथन के पुराने संस्करणों के साथ संगतता बढ़ जाती है। (जैसे, कोड जो डॉकस्ट्रिंग्स को सेट / मैनिपुलेट करता है, फिर भी पायथन के एक संस्करण के साथ काम करेगा जो डॉकस्ट्रिंग नहीं करता है, इसलिए जब तक यह उस मामले को संभालता है जहां विशेषता मौजूद नहीं है।)
cjs
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.