2011-01-02 14 views
7

मैं पीईक्यूटी 4 के साथ कैलकुलेटर बनाने और बटन से 'क्लिक किए गए()' सिग्नल को जोड़ने की कोशिश नहीं करता है। मैं लूप के अंदर संख्याओं के लिए अपने बटन बना रहा हूं जहां मैं उन्हें बाद में कनेक्ट करने का प्रयास करता हूं।एक लूप में PyQt4 में स्लॉट्स और सिग्नल कनेक्ट करना

def __init__(self):  
    for i in range(0,10): 
     self._numberButtons += [QPushButton(str(i), self)] 
     self.connect(self._numberButtons[i], SIGNAL('clicked()'), lambda : self._number(i)) 

def _number(self, x): 
    print(x) 

जब मैं बटन पर क्लिक करता हूं तो उनमें से सभी '9' प्रिंट करते हैं। ऐसा क्यों है और मैं इसे कैसे ठीक कर सकता हूं?

उत्तर

12

यह सिर्फ, स्कूपिंग, नाम लुकअप और बंदरगाहों को पाइथन में परिभाषित किया गया है।

पायथन केवल असाइनमेंट के माध्यम से और कार्यों की पैरामीटर सूचियों के माध्यम से नामस्थान में नई बाइंडिंग पेश करता है। i इसलिए lambda के नामस्थान में वास्तव में परिभाषित नहीं किया गया है, लेकिन __init__() के नामस्थान में। लैम्ब्डा में i के लिए नाम लुकअप परिणामस्वरूप __init__() के नामस्थान में समाप्त होता है, जहां i अंततः 9 तक सीमित होता है। इसे "बंद" कहा जाता है।

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

self._numberButtons[i].clicked.connect(lambda i=i: self._number(i)) 

एक अधिक पठनीय, कम जादू विकल्प functools.partial है:

self._numberButtons[i].clicked.connect(partial(self._number, i)) 

मैं बस सुविधा के लिए नए स्टाइल सिग्नल और स्लॉट सिंटैक्स का उपयोग कर रहा हूं, पुरानी स्टाइल सिंटैक्स बस वही काम करता है।

+0

इसके लिए 'functools.partial' का उपयोग करना एक बहुत अच्छा विचार है। +1 – delnan

+0

धन्यवाद। मैं functools.partial समाधान के साथ जाऊंगा। – lukad

2

आप बंद कर रहे हैं। बंदरगाह वास्तव में एक चर को पकड़ते हैं, एक चर के मूल्य नहीं। __init__ के अंत में, irange(0, 10) का अंतिम तत्व है, यानी 9। इस दायरे में आपके द्वारा बनाए गए सभी लैम्ब्डा इस i को संदर्भित करते हैं और केवल जब उन्हें बुलाया जाता है, तो उन्हें i का मूल्य प्राप्त होने पर मूल्य मिलता है (हालांकि, __init__ के अलग-अलग आमंत्रण अलग-अलग चरों का जिक्र करते हुए लैम्बडा बनाते हैं!)।

  1. एक डिफ़ॉल्ट पैरामीटर का उपयोग: lambda i=i: self._number(i)

    इस से बचने के लिए दो लोकप्रिय तरीके हैं। यह काम क्योंकि डिफ़ॉल्ट पैरामीटर फ़ंक्शन परिभाषा समय पर मान को बांधते हैं।

  2. एक सहायक समारोह helper = lambda i: (lambda: self._number(i)) परिभाषित करना और लूप में helper(i) का उपयोग करें। यह काम करता है क्योंकि i पर "बाहरी" i का मूल्यांकन किया जाता है, और जैसा कि पहले उल्लेख किया गया है - helper के अगले आमंत्रण में बनाए गए अगले बंद होने से एक अलग चर दिखाई देगा।
0

Qt तरीके का उपयोग करें, इसके बजाय QSignalMapper का उपयोग करें।

+1

कृपया मत करो। 'QSignalMapper' सी ++ 98 का ​​अवशेष है, जिसमें लैम्बडा या आंशिक कार्य नहीं होते हैं और जहां इस तरह के कामकाज एक आवश्यक बुराई हैं।अजगर में हालांकि '' QSignalMapper' functools.partial की तुलना में बस ज़रूरत से ज़्यादा है और वास्तव में फूला हुआ है() 'या लैम्ब्डा। साथ 'आंशिक()' या 'lambda' समाधान छोटे और' QSignalMapper' की तुलना में अधिक सुंदर हैं। – lunaryorn

+0

ओह ठीक है इसके बारे में, मैं क्यूटी/सी ++ संगतता के लिए 'QSignalMapper' चुनूंगा। – ismail

+1

बेशक यह पसंद के बारे में है, लेकिन मैं बस आपकी पसंद को समझ नहीं पा रहा हूं और मैं इसका पालन नहीं कर सकता। मैं क्यूटी अनुप्रयोगों के लिए पाइथन का उपयोग कर रहा हूं क्योंकि यह * नहीं * सी ++ है, और यदि मैं सी ++ संगतता को बनाए रखने या पहुंचने के लिए पाइथन की विशेष विशेषताओं को छोड़ दूंगा, तो मैं सी ++ का भी उपयोग कर सकता हूं;) – lunaryorn

संबंधित मुद्दे