पायथन एक फ़ंक्शन के अंदर स्थिर चर के बराबर क्या है?


630

इस C / C ++ कोड के मुहावरेदार पायथन क्या है?

void foo()
{
    static int counter = 0;
    counter++;
    printf("counter is %d\n", counter);
}

विशेष रूप से, क्लास स्तर के विपरीत, कोई व्यक्ति फ़ंक्शन स्तर पर स्थिर सदस्य को कैसे लागू करता है? और फ़ंक्शन को क्लास में रखने से कुछ भी बदल जाता है?


22
नहीं है कोई तुल्यता मुझे डर लग रहा। भले ही आप डेकोरेटर को फ़ंक्शन विशेषताओं के साथ हैक करते हैं, आप बाहर चर का उपयोग करने में सक्षम होंगे, जो थोड़े बिंदु को हराता है, दुख की बात है। इसके अलावा, आपको फ़ंक्शन में फ़ंक्शन नाम को कठिन कोड देना होगा, जो बहुत कष्टप्रद है। मैं पारंपरिक _उपसर्ग के बजाय एक वर्ग या मॉड्यूल वैश्विक चर का उपयोग करने का सुझाव दूंगा।
10

8
गैर-सी-प्रोग्रामर के लिए, [ stackoverflow.com/questions/5033627/… एक फ़ंक्शन के अंदर स्थिर चर केवल उस फ़ंक्शन के दायरे के अंदर दिखाई देता है, लेकिन इसका जीवनकाल कार्यक्रम का संपूर्ण जीवन है, और यह केवल एक बार आरंभिक है)। मूल रूप से, एक लगातार काउंटर या भंडारण चर जो फ़ंक्शन कॉल के बीच रहता है।
मुस्कान जू

2
@ llapp: वहाँ की तरह है, यह एक वर्ग के सदस्य है । आप सही हैं कि हम अन्य कोड को इसे देखने या इसे बदलने से रोक नहीं सकते हैं।
मुस्कान

जवाबों:


681

थोड़ा उलट, लेकिन यह काम करना चाहिए:

def foo():
    foo.counter += 1
    print "Counter is %d" % foo.counter
foo.counter = 0

यदि आप नीचे के बजाय शीर्ष पर काउंटर इनिशियलाइज़ेशन कोड चाहते हैं, तो आप एक डेकोरेटर बना सकते हैं:

def static_vars(**kwargs):
    def decorate(func):
        for k in kwargs:
            setattr(func, k, kwargs[k])
        return func
    return decorate

फिर इस तरह कोड का उपयोग करें:

@static_vars(counter=0)
def foo():
    foo.counter += 1
    print "Counter is %d" % foo.counter

यह अभी भी आपको foo.उपसर्ग का उपयोग करने की आवश्यकता होगी , दुर्भाग्य से।

( साभार : @ सोनी )


23
फू का केवल एक उदाहरण है - यह एक कार्य है। सभी आह्वान एक ही चर का उपयोग करते हैं।
क्लाउडीयू

121
इसे खोदने के लिए क्षमा करें, लेकिन मैं if "counter" not in foo.__dict__: foo.counter = 0इसकी पहली पंक्तियों के रूप में रखूंगा foo()। यह फ़ंक्शन के बाहर कोड से बचने में मदद करेगा। यकीन नहीं होता कि क्या यह 2008 में वापस संभव था। PS ने स्थैतिक फ़ंक्शन चर बनाने की संभावना की खोज करते हुए यह उत्तर पाया, इसलिए यह धागा अभी भी "जीवित" है :)
बाइनरीएलवी

8
@binaryLV: मैं शायद पहले दृष्टिकोण के लिए पसंद करूँगा। पहले दृष्टिकोण के साथ समस्या यह है कि तुरंत स्पष्ट नहीं है fooऔर foo.counter = अंतरंग रूप से संबंधित हैं। हालाँकि, मैं अंततः डेकोरेटर के दृष्टिकोण को पसंद करता हूं, क्योंकि कोई भी तरीका नहीं है जब डेकोरेटर को बुलाया नहीं जाएगा और यह शब्दार्थ अधिक स्पष्ट है कि यह क्या करता है ( @static_var("counter", 0)मेरी आंखों के लिए आसान है और अधिक समझ में आता है if "counter" not in foo.__dict__: foo.counter = 0, खासकर बाद के रूप में आपको उपयोग करना होगा फ़ंक्शन का नाम (दो बार) जो बदल सकता है)।
क्लाउडीयू

6
@lpapp: यह इस बात पर निर्भर करता है कि स्थिर चर का बिंदु क्या है। मैंने हमेशा सोचा था कि यह कई फ़ंक्शन कॉलों में समान मूल्य होगा, जो यह संतुष्ट करता है। जैसा कि आपने कहा, मैंने इसे परिवर्तनशील होने के बारे में कभी नहीं लिया।
क्लाउडीयू

3
def foo(): if not hasattr(foo,"counter"): foo.counter=0 foo.counter += 1
एरिक एरोनेस्टी

221

आप किसी फ़ंक्शन में विशेषताएँ जोड़ सकते हैं, और इसे एक स्थिर चर के रूप में उपयोग कर सकते हैं।

def myfunc():
  myfunc.counter += 1
  print myfunc.counter

# attribute must be initialized
myfunc.counter = 0

वैकल्पिक रूप से, यदि आप फ़ंक्शन के बाहर वैरिएबल सेटअप नहीं करना चाहते हैं, तो आप अपवाद hasattr()से बचने के लिए उपयोग कर सकते हैं AttributeError:

def myfunc():
  if not hasattr(myfunc, "counter"):
     myfunc.counter = 0  # it doesn't exist yet, so initialize it
  myfunc.counter += 1

वैसे भी स्थैतिक चर दुर्लभ हैं, और आपको इस चर के लिए एक बेहतर जगह मिलनी चाहिए, सबसे अधिक संभावना एक वर्ग के अंदर।


6
अगर बयान की बजाय कोशिश क्यों न की जाए?
रवोज्दिला

12
try: myfunc.counter += 1; except AttributeError: myfunc.counter = 1इसके बजाय अपवादों का उपयोग करते हुए, ऐसा ही करना चाहिए।
स्लीपब्लैंक

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

11
@Hack_Saw: खैर, यह पाइथोनिक है (अनुमति की तुलना में माफी के लिए पूछना बेहतर है)। यह वास्तव में पायथन अनुकूलन तकनीकों में अनुशंसित है क्योंकि यह एक की लागत को बचाता है (हालांकि मैं समय से पहले अनुकूलन की सिफारिश नहीं कर रहा हूं)। असाधारण मामलों के बारे में आपका नियम: 1. विफलता एक अर्थ में, यहाँ एक असाधारण मामला है। यह केवल एक बार होता है। 2. मुझे लगता है कि नियम अपवादों के उपयोग (यानी बढ़ाने) के बारे में है। यह कुछ ऐसी चीज़ों के लिए एक अपवाद को पकड़ रहा है जिनसे आप काम करने की उम्मीद करते हैं लेकिन उनके लिए एक बैकअप योजना है, जो कि अधिकांश भाषाओं में एक आम बात है।
लेवेज़

@leewangzhong: किसी tryभी लागत को जोड़ने के भीतर एक अपवाद नहीं बढ़ाता है कि एक ब्लॉक संलग्न करता है ? बस उत्सुक।
trss

201

एक भी विचार कर सकता है:

def foo():
    try:
        foo.counter += 1
    except AttributeError:
        foo.counter = 1

तर्क:

  • बहुत अजगर ("माफी के लिए पूछें अनुमति नहीं")
  • ifशाखा के बजाय अपवाद का उपयोग करें (केवल एक बार फेंका गया है) ( स्टॉपइंटरेशन अपवाद देखें)

11
मैं पाइथन लंबे समय से नहीं कर रहा हूं, लेकिन यह भाषा के निहित गुणों में से एक को संतुष्ट करता है: यदि यह (काफी) आसान नहीं है, तो आप इसे गलत कर रहे हैं
ZX9

क्लास के तरीकों के साथ तुरंत काम नहीं किया, "self.foo.counter = 1" फिर से एट्रीब्यूट उठाता है।
विलास

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

3
एक सरल तरीका: def fn(): if not hasattr(fn, 'c'): fn.c = 0 fn.c += 1 return fn.c
TheCuriousOne

5
@ इसके लिए प्रयोग करना hasattr()सरल नहीं है और कम कुशल भी है।
मूओईपिप

48

अन्य उत्तरों ने यह प्रदर्शित किया है कि आपको ऐसा करना चाहिए। यहाँ एक तरीका है जो आपको नहीं करना चाहिए:

>>> def foo(counter=[0]):
...   counter[0] += 1
...   print("Counter is %i." % counter[0]);
... 
>>> foo()
Counter is 1.
>>> foo()
Counter is 2.
>>> 

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


मैंने कोशिश की, लेकिन किसी कारण से, फ़ंक्शन पैरामीटर खुद को 140 से शुरू कर रहा था, न कि 0. यह क्यों होगा?
andrewdotnich

1
@bouvard एक स्थिर वैरिएबल की आवश्यकता वाले पुनरावर्ती कार्यों के लिए, यह एकमात्र ऐसा है जो वास्तव में अच्छी तरह से पढ़ता है।
जीवनदायिनी

1
मैंने कई तरीकों की कोशिश की और मैं चाहता हूं कि यह एक अजगर के रूप में स्वीकार किया जाए। कुछ सार्थक नामों के साथ जैसे def foo(arg1, arg2, _localstorage=DataClass(counter=0))मुझे यह अच्छी तरह से पढ़ने योग्य लगता है। एक और अच्छा बिंदु नाम बदलने का आसान कार्य है।
वीपीएफबी

2
आप ऐसा क्यों कहते हैं कि आपको ऐसा नहीं करना चाहिए? मुझे पूरी तरह से उचित लगता है!
कॉन्सटेंटिन

1
@ वीपीबीबी: सामान्य भंडारण के लिए, आप एक विशेष वर्ग को परिभाषित करने की आवश्यकता के बिना types.SimpleNamespaceइसका उपयोग कर सकते हैं def foo(arg1, arg2, _staticstorage=types.SimpleNamespace(counter=0)):
शैडो रेंजर

43

कई लोगों ने पहले ही 'hasattr' परीक्षण का सुझाव दिया है, लेकिन इसका एक सरल उत्तर है:

def func():
    func.counter = getattr(func, 'counter', 0) + 1

कोई प्रयास / छोड़कर, कोई परीक्षण hasattr नहीं, बस एक डिफ़ॉल्ट के साथ getattr।


2
जब आप एक फंक उदाहरण के लिए वहाँ डालते हैं, तो गेटअटर के तीसरे भाग पर ध्यान दें: डीफ़ फ़ेक (): डीफ़ फ़ू (): १११२ फ़न.काउंटर = गेटैट (फ़ंक, 'काउंटर ’, फ़ू () + 1) जब आप कॉल करते हैं दुर्गंध, फू हमेशा कहा जाएगा!
संहिता

1
बस हर बार कॉल करने के लिए एक कॉल जो फंक कहलाती है। यदि प्रदर्शन अच्छा नहीं है तो यह ठीक है, अगर यह कोशिश की जाए / सिवाय इसके कि हाथ नीचे चला जाए।
मार्क लॉरेंस

2
@MarkLawrence: वास्तव में, कम से कम मेरे विंडोज x64 3.8.0 पर स्थापित, इस उत्तर और रैवज़्डी के समतुल्य try/ exceptआधारित दृष्टिकोण के बीच प्रदर्शन अंतर बहुत अर्थहीन है। एक साधारण ipython %%timeitमाइक्रोबैनमार्क ने कॉल के लिए 255 n try/ exceptप्रति कॉल की लागत को , बनाम 263 ns के getattrआधार पर हल किया। हां, try/ exceptअधिक तेज़ है, लेकिन यह "हाथ नीचे जीतने" बिल्कुल नहीं है; यह एक छोटा सूक्ष्म अनुकूलन है। जो भी कोड स्पष्ट लगता है उसे लिखें, इस तरह के तुच्छ प्रदर्शन मतभेदों के बारे में चिंता न करें।
शैडो रेंजर

@ShadowRanger बेंचमार्किंग के लिए धन्यवाद। मैं 2 साल के लिए MarkLawrence के बयान के बारे में सोच रहा था, और मुझे बहुत खुशी है कि आपने शोध किया। मैं निश्चित रूप से आपके अंतिम वाक्य से सहमत हूं - "जो भी कोड स्पष्ट लगता है वह लिखें" - यही कारण है कि मैंने यह जवाब लिखा है।
जोनाथन

28

यहाँ एक पूरी तरह से समझाया गया संस्करण है जिसे बाहरी आरंभीकरण कॉल की आवश्यकता नहीं है:

def fn():
    fn.counter=vars(fn).setdefault('counter',-1)
    fn.counter+=1
    print (fn.counter)

पायथन में, फ़ंक्शंस ऑब्जेक्ट हैं और हम केवल विशेष विशेषता के माध्यम से उन्हें जोड़ सकते हैं, या बंदर पैच, सदस्य चर दे सकते हैं __dict__। अंतर्निहित vars()विशेष गुण देता है __dict__

संपादित करें: नोट, वैकल्पिक try:except AttributeErrorउत्तर के विपरीत , इस दृष्टिकोण के साथ चर हमेशा आरंभीकरण के बाद कोड तर्क के लिए तैयार होगा। मुझे लगता try:except AttributeErrorहै कि निम्नलिखित के विकल्प कम DRY और / या अजीब प्रवाह होगा:

def Fibonacci(n):
   if n<2: return n
   Fibonacci.memo=vars(Fibonacci).setdefault('memo',{}) # use static variable to hold a results cache
   return Fibonacci.memo.setdefault(n,Fibonacci(n-1)+Fibonacci(n-2)) # lookup result in cache, if not available then calculate and store it

EDIT2: मैं केवल उपरोक्त दृष्टिकोण की सिफारिश करता हूं जब फ़ंक्शन को कई स्थानों से बुलाया जाएगा। यदि इसके बजाय फ़ंक्शन को केवल एक ही स्थान पर बुलाया जाता है, तो इसका उपयोग करना बेहतर होता है nonlocal:

def TheOnlyPlaceStaticFunctionIsCalled():
    memo={}
    def Fibonacci(n):
       nonlocal memo  # required in Python3. Python2 can see memo
       if n<2: return n
       return memo.setdefault(n,Fibonacci(n-1)+Fibonacci(n-2))
    ...
    print (Fibonacci(200))
    ...

2
इसके साथ एकमात्र समस्या यह है कि यह वास्तव में साफ-सुथरा नहीं है, और जब भी आप इस पैटर्न का उपयोग करना चाहते हैं तो आपको कोड को काटना और पेस्ट करना होगा ... इसलिए मेरा एक डेकोरेटर का उपयोग
क्लाउडीयू

2
शायद कुछ का उपयोग करना चाहिएtry: mystaticfun.counter+=10 except AttributeError: mystaticfun.counter=0
एंडोलिथ

2
का उपयोग करें X not in Yके बजाय not X in Y(या सलाह का उपयोग कर यदि आप सिर्फ इतना है कि और के बीच एक और अधिक समान दिखने वाले तुलना की खातिर यह उपयोग कर रहे थे hasattr)
निक टी

इस बारे में कैसे: def fn(): if not hasattr(fn, 'c'): fn.c = 0 fn.c += 1 return fn.c
TheCuriousOne

यह आदर्श नहीं है क्योंकि यदि क्लॉज अनावश्यक घोंसले के शिकार को जोड़ता है, तो इस स्थिति में मैं सेटडेफॉल्ट पसंद करता हूं
रियाज़ रिज़वी

27

पायथन में स्थैतिक चर नहीं होते हैं, लेकिन आप इसे कॉल करने योग्य वर्ग ऑब्जेक्ट को परिभाषित करके और फिर फ़ंक्शन के रूप में उपयोग करके नकली कर सकते हैं। इसका उत्तर भी देखें

class Foo(object):
  # Class variable, shared by all instances of this class
  counter = 0

  def __call__(self):
    Foo.counter += 1
    print Foo.counter

# Create an object instance of class "Foo," called "foo"
foo = Foo()

# Make calls to the "__call__" method, via the object's name itself
foo() #prints 1
foo() #prints 2
foo() #prints 3

ध्यान दें कि __call__एक वर्ग (ऑब्जेक्ट) का एक उदाहरण अपने नाम से कॉल करने योग्य बनाता है। इसीलिए foo()ऊपर कॉलिंग क्लास की __call__विधि कहती है । प्रलेखन से :

__call__()अपनी कक्षा में एक विधि को परिभाषित करके मनमानी कक्षाओं के उदाहरणों को सुगम बनाया जा सकता है ।


15
फ़ंक्शंस पहले से ऑब्जेक्ट हैं इसलिए यह सिर्फ एक अनावश्यक परत जोड़ता है।
दशिच

एक लंबे विचार के लिए इस SO उत्तर को देखें कि यह वास्तव में एक अच्छा विचार है। stackoverflow.com/questions/460586 । मैं इस बात से सहमत हूं कि किसी भी वर्ग को एक सिंगलटन बनाना, शायद इस तरह की stackoverflow.com/questions/6760685 , भी एक अच्छा विचार होगा। मुझे नहीं पता कि @ S.Lott का अर्थ "... काउंटर काउंट इन क्लास डेफिनिशन ..." है, क्योंकि ऐसा लगता है कि यह मेरे लिए पहले से ही क्लास-वेरिएबल स्थिति में है।
Reb.Cabin

1
मेरे शोध के आधार पर, यह कक्षा तकनीक इस पृष्ठ पर प्रस्तुत दृष्टिकोणों में से सबसे "पायथोनिक" प्रतीत होती है, और कम से कम चालबाजी का उपयोग करती है। इसलिए मैं इसे एक नए पायथन डेवलपर के रूप में, कार्यों में सी-स्टैटिक जैसे वेरिएबल्स के प्रतिस्थापन के लिए इसे अपनाने के रूप में अपनाने की योजना बना रहा हूं।
गेब्रियल स्टेपल्स

1
अगर मुझे foo1 = Foo () और foo2 = Foo () चाहिए तो क्या होगा?
मार्क लॉरेंस

@MarkLawrence तब आपके पास एक कॉल करने योग्य वर्ग के दो अलग-अलग उदाहरण हैं, प्रत्येक अपने काउंटर के साथ। यदि आप उस उदाहरण का उपयोग कर रहे हैं fooजो आपको एक सिंगलटन के रूप में प्रदान किया गया है तो वास्तव में आपको क्या उम्मीद करनी चाहिए ।
एरोन मैकमिलिन

14

एक जनरेटर उत्पन्न करने के लिए एक जनरेटर फ़ंक्शन का उपयोग करें।

def foo_gen():
    n = 0
    while True:
        n+=1
        yield n

फिर इसका उपयोग करें

foo = foo_gen().next
for i in range(0,10):
    print foo()

यदि आप एक ऊपरी सीमा चाहते हैं:

def foo_gen(limit=100000):
    n = 0
    while n < limit:
       n+=1
       yield n

यदि इट्रेटर समाप्त हो जाता है (ऊपर दिए गए उदाहरण की तरह), तो आप सीधे उस पर भी लूप कर सकते हैं, जैसे

for i in foo_gen(20):
    print i

बेशक, इन सरल मामलों में xrange का उपयोग करना बेहतर है :)

यहाँ पैदावार विवरण पर प्रलेखन है ।


11

अन्य समाधान फ़ंक्शन को काउंटर विशेषता देते हैं, आमतौर पर प्रारंभ को संभालने के लिए जटिल तर्क के साथ। यह नए कोड के लिए अनुचित है।

पायथन 3 में, nonlocalकथन का उपयोग करने का सही तरीका है :

counter = 0
def foo():
    nonlocal counter
    counter += 1
    print(f'counter is {counter}')

के विनिर्देशन के लिए PEP 3104 देखेंnonlocalविवरण ।

यदि काउंटर मॉड्यूल के लिए निजी होने का इरादा है, तो इसे _counterइसके बजाय नाम दिया जाना चाहिए ।


पायथन 3 से पहले भी, आप हमेशा global counterइसके बजाय एक बयान के साथ ऐसा कर सकते थे nonlocal counter( nonlocalबस आपको नेस्टेड फ़ंक्शन में स्थिति को बंद करने के लिए लिखते हैं)। लोगों को फ़ंक्शन के लिए एक विशेषता संलग्न करने का कारण यह है कि राज्य के लिए वैश्विक नाम स्थान को प्रदूषित करने से बचना है जो फ़ंक्शन के लिए विशिष्ट है, इसलिए आपको दो कार्यों के स्वतंत्र होने पर भी हैकर चीजों को करने की आवश्यकता नहीं है counter। यह समाधान पैमाने नहीं करता है; समारोह पर विशेषताएँ करते हैं। kdb का उत्तर है कि कैसे nonlocalमदद की जा सकती है, लेकिन यह जटिलता को जोड़ता है।
शैडो रेंजर

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

8

स्थिर चर के रूप में फ़ंक्शन की विशेषता का उपयोग करना कुछ संभावित कमियां हैं:

  • हर बार जब आप चर का उपयोग करना चाहते हैं, तो आपको फ़ंक्शन का पूरा नाम लिखना होगा।
  • बाहर कोड आसानी से चर तक पहुंच सकता है और मूल्य के साथ गड़बड़ कर सकता है।

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

एक विकल्प लेक्सिकल क्लोजर का उपयोग करने वाला एक पैटर्न होगा, जो कि nonlocalअजगर 3 में कीवर्ड के साथ समर्थित है ।

def make_counter():
    i = 0
    def counter():
        nonlocal i
        i = i + 1
        return i
    return counter
counter = make_counter()

अफसोस की बात है कि मैं इस समाधान को डेकोरेटर में बदलना नहीं जानता।


7
def staticvariables(**variables):
    def decorate(function):
        for variable in variables:
            setattr(function, variable, variables[variable])
        return function
    return decorate

@staticvariables(counter=0, bar=1)
def foo():
    print(foo.counter)
    print(foo.bar)

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


7

थोड़ा सा अधिक पठनीय, लेकिन अधिक क्रिया (ज़ेन पायथन: स्पष्ट का अर्थ निहित से बेहतर है)

>>> def func(_static={'counter': 0}):
...     _static['counter'] += 1
...     print _static['counter']
...
>>> func()
1
>>> func()
2
>>>

यह कैसे काम करता है, इसकी व्याख्या के लिए यहां देखें ।


क्या आप इस बारे में विस्तार से बता सकते हैं कि यह कोड क्यों काम करता है? दूसरे foo()को फंक्शनल डेफिनिशन में निर्दिष्ट वैल्यू में शब्दकोश को फिर से इनिशियलाइज़ करना चाहिए (इसलिए काउंटर की की वैल्यू वाले 0)। ऐसा क्यों नहीं होता?
राफेल

3
@raffamaiden: डिफ़ॉल्ट तर्कों का मूल्यांकन केवल एक बार किया जाता है जब फ़ंक्शन को परिभाषित किया जाता है और प्रत्येक बार फ़ंक्शन को नहीं कहा जाता है।
डैनियल के।

6
_कार = ०
डीओ फू ():
   वैश्विक _ मुठभेड़
   _कार + + 1
   प्रिंट 'काउंटर' है, _काउंटर

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


4

कई तरीकों की कोशिश करने के बाद, मैं युद्धवीर के उत्तर के बेहतर संस्करण का उपयोग कर रहा हूं:

import types

def func(_static=types.SimpleNamespace(counter=0)):
    _static.counter += 1
    print(_static.counter)

3

मुहावरेदार तरह से एक का उपयोग करने के लिए है वर्ग , गुण हो सकता है। यदि आपको अलग न होने के उदाहरणों की आवश्यकता है, तो एक सिंगलटन का उपयोग करें।

ऐसे कई तरीके हैं जिनसे आप पायथन में "स्टैटिक" वैरिएबल को नकली या मर्ज कर सकते हैं (अब तक उल्लेख नहीं किया गया है कि एक परस्पर डिफ़ॉल्ट तर्क है), लेकिन यह ऐसा करने का पाइथोनिक, मुहावरेदार तरीका नहीं है। बस एक वर्ग का उपयोग करें।

या संभवतः एक जनरेटर, यदि आपका उपयोग पैटर्न फिट बैठता है।


स्टैंड-अलोन पुनरावर्ती कार्यों के लिए, defaultतर्क सबसे सुरुचिपूर्ण है।
लाइफबैलेंस

3

इस सवाल से प्रेरित होकर , क्या मैं एक और विकल्प प्रस्तुत कर सकता हूं जो उपयोग करने के लिए थोड़ा अच्छा हो सकता है और दोनों तरीकों और कार्यों के लिए समान दिखेगा:

@static_var2('seed',0)
def funccounter(statics, add=1):
    statics.seed += add
    return statics.seed

print funccounter()       #1
print funccounter(add=2)  #3
print funccounter()       #4

class ACircle(object):
    @static_var2('seed',0)
    def counter(statics, self, add=1):
        statics.seed += add
        return statics.seed

c = ACircle()
print c.counter()      #1
print c.counter(add=2) #3
print c.counter()      #4
d = ACircle()
print d.counter()      #5
print d.counter(add=2) #7
print d.counter()      #8    

यदि आपको उपयोग पसंद है, तो यहां कार्यान्वयन है:

class StaticMan(object):
    def __init__(self):
        self.__dict__['_d'] = {}

    def __getattr__(self, name):
        return self.__dict__['_d'][name]
    def __getitem__(self, name):
        return self.__dict__['_d'][name]
    def __setattr__(self, name, val):
        self.__dict__['_d'][name] = val
    def __setitem__(self, name, val):
        self.__dict__['_d'][name] = val

def static_var2(name, val):
    def decorator(original):
        if not hasattr(original, ':staticman'):    
            def wrapped(*args, **kwargs):
                return original(getattr(wrapped, ':staticman'), *args, **kwargs)
            setattr(wrapped, ':staticman', StaticMan())
            f = wrapped
        else:
            f = original #already wrapped

        getattr(f, ':staticman')[name] = val
        return f
    return decorator

3

एक और (अनुशंसित नहीं!) Https://stackoverflow.com/a/279598/916373 जैसे कॉल करने योग्य ऑब्जेक्ट पर ट्विस्ट करें , यदि आप फंकी कॉल सिग्नेचर का उपयोग करने में कोई आपत्ति नहीं करते हैं, तो यह करना होगा

class foo(object):
    counter = 0;
    @staticmethod
    def __call__():
        foo.counter += 1
        print "counter is %i" % foo.counter

>>> foo()()
counter is 1
>>> foo()()
counter is 2

3

स्टैटिक लोकल वेरिएबल वाले फंक्शन को बनाने के बजाय, आप हमेशा एक "फंक्शन ऑब्जेक्ट" कहलाने वाले को बना सकते हैं और इसे एक स्टैंडर्ड (नॉन-स्टैटिक) मेंबर वेरिएबल दे सकते हैं।

चूँकि आपने C ++ लिखा हुआ एक उदाहरण दिया है, इसलिए मैं पहले बताऊंगा कि C ++ में "फ़ंक्शन ऑब्जेक्ट" क्या है। एक "फ़ंक्शन ऑब्जेक्ट" एक अतिभारित के साथ बस किसी भी वर्ग है operator()। कक्षा के उदाहरण कार्य की तरह व्यवहार करेंगे। उदाहरण के लिए, आप लिख सकते हैं, int x = square(5);भले ही squareकोई वस्तु हो (अतिभारित operator()) और तकनीकी रूप से "फ़ंक्शन" नहीं है। आप फ़ंक्शन-ऑब्जेक्ट में से कोई भी सुविधा दे सकते हैं जिसे आप क्लास ऑब्जेक्ट दे सकते हैं।

# C++ function object
class Foo_class {
    private:
        int counter;     
    public:
        Foo_class() {
             counter = 0;
        }
        void operator() () {  
            counter++;
            printf("counter is %d\n", counter);
        }     
   };
   Foo_class foo;

पायथन में, हम यह भी अधिभार कर सकते हैं operator()सिवाय इसके कि विधि को नाम दिया गया है __call__:

यहाँ एक वर्ग परिभाषा है:

class Foo_class:
    def __init__(self): # __init__ is similair to a C++ class constructor
        self.counter = 0
        # self.counter is like a static member
        # variable of a function named "foo"
    def __call__(self): # overload operator()
        self.counter += 1
        print("counter is %d" % self.counter);
foo = Foo_class() # call the constructor

यहां कक्षा का एक उदाहरण दिया जा रहा है:

from foo import foo

for i in range(0, 5):
    foo() # function call

कंसोल पर मुद्रित आउटपुट है:

counter is 1
counter is 2
counter is 3
counter is 4
counter is 5

यदि आप चाहते हैं कि आपका कार्य इनपुट तर्कों को ले जाए, तो आप उन्हें भी जोड़ सकते हैं __call__:

# FILE: foo.py - - - - - - - - - - - - - - - - - - - - - - - - -

class Foo_class:
    def __init__(self):
        self.counter = 0
    def __call__(self, x, y, z): # overload operator()
        self.counter += 1
        print("counter is %d" % self.counter);
        print("x, y, z, are %d, %d, %d" % (x, y, z));
foo = Foo_class() # call the constructor

# FILE: main.py - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

from foo import foo

for i in range(0, 5):
    foo(7, 8, 9) # function call

# Console Output - - - - - - - - - - - - - - - - - - - - - - - - - - 

counter is 1
x, y, z, are 7, 8, 9
counter is 2
x, y, z, are 7, 8, 9
counter is 3
x, y, z, are 7, 8, 9
counter is 4
x, y, z, are 7, 8, 9
counter is 5
x, y, z, are 7, 8, 9

3

आत्माभ्यास n + = १

def foo():
  foo.__dict__.setdefault('count', 0)
  foo.count += 1
  return foo.count

3

एक वैश्विक घोषणा यह कार्यक्षमता प्रदान करती है। नीचे के उदाहरण में (अजगर 3.5 या "एफ" का उपयोग करने के लिए अधिक), काउंटर चर फ़ंक्शन के बाहर परिभाषित किया गया है। फ़ंक्शन में इसे वैश्विक रूप से परिभाषित करना दर्शाता है कि फ़ंक्शन के बाहर "वैश्विक" संस्करण को फ़ंक्शन को उपलब्ध कराया जाना चाहिए। इसलिए हर बार फ़ंक्शन चलता है, यह फ़ंक्शन के बाहर मान को संशोधित करता है, इसे फ़ंक्शन से परे संरक्षित करता है।

counter = 0

def foo():
    global counter
    counter += 1
    print("counter is {}".format(counter))

foo() #output: "counter is 1"
foo() #output: "counter is 2"
foo() #output: "counter is 3"

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

2

पायथन विधि के अंदर एक स्थिर चर

class Count:
    def foo(self):
        try: 
            self.foo.__func__.counter += 1
        except AttributeError: 
            self.foo.__func__.counter = 1

        print self.foo.__func__.counter

m = Count()
m.foo()       # 1
m.foo()       # 2
m.foo()       # 3

1

मैं व्यक्तिगत रूप से सज्जाकारों के लिए निम्नलिखित पसंद करता हूं। प्रत्येक अपने स्वयं के लिए।

def staticize(name, factory):
    """Makes a pseudo-static variable in calling function.

    If name `name` exists in calling function, return it. 
    Otherwise, saves return value of `factory()` in 
    name `name` of calling function and return it.

    :param name: name to use to store static object 
    in calling function
    :type name: String
    :param factory: used to initialize name `name` 
    in calling function
    :type factory: function
    :rtype: `type(factory())`

    >>> def steveholt(z):
    ...     a = staticize('a', list)
    ...     a.append(z)
    >>> steveholt.a
    Traceback (most recent call last):
    ...
    AttributeError: 'function' object has no attribute 'a'
    >>> steveholt(1)
    >>> steveholt.a
    [1]
    >>> steveholt('a')
    >>> steveholt.a
    [1, 'a']
    >>> steveholt.a = []
    >>> steveholt.a
    []
    >>> steveholt('zzz')
    >>> steveholt.a
    ['zzz']

    """
    from inspect import stack
    # get scope enclosing calling function
    calling_fn_scope = stack()[2][0]
    # get calling function
    calling_fn_name = stack()[1][3]
    calling_fn = calling_fn_scope.f_locals[calling_fn_name]
    if not hasattr(calling_fn, name):
        setattr(calling_fn, name, factory())
    return getattr(calling_fn, name)

3
कृपया नाराज न हों, लेकिन यह समाधान मुझे "बड़ी कंपनी शैली" के बारे में याद दिलाता है :-) willa.me/2013/11/the-six-most-common-species-of-code.html
JJC

हां, गैर-पोर्टेबल (सामान्य रूप से स्टैक हेरफेर का उपयोग करना एक CPython कार्यान्वयन विवरण है, न कि कुछ आप PyPy, Jython, IronPython, what-have-you) पर भरोसा कर सकते हैं, हर प्रयोग पर आधा दर्जन फ़ंक्शन कॉल के साथ नाजुक स्टैक हेरफेर। है जिस तरह से एक साधारण की तुलना में बेहतर डेकोरेटर ... </ s>
ShadowRanger

1

यह उत्तर @claudiu के उत्तर पर बनता है।

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

अर्थात्, मेरे फ़ंक्शन कोड में मैं लिखना पसंद करूंगा:

print(statics.foo)

के बजाय

print(my_function_name.foo)

तो, मेरा समाधान है:

  1. staticsफ़ंक्शन में एक विशेषता जोड़ें
  2. फ़ंक्शन स्कोप में, staticsएलियास टू के रूप में एक स्थानीय चर जोड़ेंmy_function.statics
from bunch import *

def static_vars(**kwargs):
    def decorate(func):
        statics = Bunch(**kwargs)
        setattr(func, "statics", statics)
        return func
    return decorate

@static_vars(name = "Martin")
def my_function():
    statics = my_function.statics
    print("Hello, {0}".format(statics.name))

टिप्पणी

मेरी विधि एक वर्ग नाम का उपयोग करती है Bunch, जो एक शब्दकोश है जो विशेषता-शैली के उपयोग का समर्थन करता है, एक ला जावास्क्रिप्ट (इसके बारे में मूल लेख देखें , लगभग 2000)

इसके माध्यम से स्थापित किया जा सकता है pip install bunch

इसे भी हाथ से लिखा जा सकता है:

class Bunch(dict):
    def __init__(self, **kw):
        dict.__init__(self,kw)
        self.__dict__ = self

नोट: types.SimpleNamespace(3.3 के बाद से उपलब्ध) इस व्यवहार को बॉक्स से बाहर का समर्थन करता है (और सीपीटीथॉन पर सी में लागू किया गया है, इसलिए यह जितनी तेजी से हो सकता है)।
शैडो रेंजर

0

डैनियल के जवाब पर निर्माण (परिवर्धन):

class Foo(object): 
    counter = 0  

def __call__(self, inc_value=0):
    Foo.counter += inc_value
    return Foo.counter

foo = Foo()

def use_foo(x,y):
    if(x==5):
        foo(2)
    elif(y==7):
        foo(3)
    if(foo() == 10):
        print("yello")


use_foo(5,1)
use_foo(5,1)
use_foo(1,7)
use_foo(1,7)
use_foo(1,1)

इस भाग को मैं क्यों जोड़ना चाहता था, इसका कारण यह है कि, स्थिर चर का उपयोग न केवल कुछ मूल्य में वृद्धि के लिए किया जाता है, बल्कि यह भी जांचता है कि क्या स्थैतिक संस्करण कुछ मूल्य के बराबर है, वास्तविक जीवन उदाहरण के रूप में।

स्थिर चर को अभी भी उपयोग किया जाता है और केवल फ़ंक्शन use_foo () के दायरे में उपयोग किया जाता है

इस उदाहरण में, foo को कॉल करें () फ़ंक्शंस के अनुसार (संबंधित c ++ समकक्ष के संबंध में):

stat_c +=9; // in c++
foo(9)  #python equiv

if(stat_c==10){ //do something}  // c++

if(foo() == 10):      # python equiv
  #add code here      # python equiv       

Output :
yello
yello

यदि क्लास फू को एक एकल वर्ग के रूप में सीमित रूप से परिभाषित किया जाता है, तो यह आदर्श होगा। यह इसे अधिक पायथोनिक बना देगा।


-1

यकीन है कि यह एक पुराना सवाल है, लेकिन मुझे लगता है कि मैं कुछ अपडेट प्रदान कर सकता हूं।

ऐसा लगता है कि प्रदर्शन तर्क अप्रचलित है। समान परीक्षण सूट siInt_try और isInt_re2 के लिए समान परिणाम देता है। बेशक परिणाम अलग-अलग होते हैं, लेकिन मेरे कंप्यूटर पर यह एक सत्र है, जो कि एक्सोन W3550 के साथ कर्नेल 4.3.01 पर अजगर 3.4.4 है। मैंने इसे कई बार चलाया है और परिणाम समान लगते हैं। मैंने वैश्विक रेगेक्स को फंक्शन स्टेटिक में स्थानांतरित किया, लेकिन प्रदर्शन अंतर नगण्य है।

isInt_try: 0.3690
isInt_str: 0.3981
isInt_re: 0.5870
isInt_re2: 0.3632

इस तरह से प्रदर्शन के मुद्दे के साथ, ऐसा लगता है कि कोशिश / पकड़ सबसे भविष्य का उत्पादन करेगी- और कॉर्नाकेज़- प्रूफ कोड ताकि शायद फ़ंक्शन में लपेटें


1
आप यहाँ क्या तुलना कर रहे हैं? यह अन्य उत्तरों पर एक टिप्पणी की तरह लगता है, लेकिन यह स्पष्ट नहीं है कि कौन सा है, और यह स्वयं प्रश्न का उत्तर नहीं देता है।
शैडो रेंजर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.