एक अजगर शब्दकोश के अंदर एक समारोह क्यों स्टोर?


68

मैं एक अजगर शुरुआत कर रहा हूं, और मैंने सिर्फ एक तकनीक सीखी है जिसमें शब्दकोश और फ़ंक्शन शामिल हैं। वाक्यविन्यास आसान है और यह एक तुच्छ चीज की तरह लगता है, लेकिन मेरी अजगर इंद्रियां झुनझुनी होती हैं। कुछ मुझे बताता है कि यह एक गहरी और बहुत ही पवित्र अवधारणा है और मैं इसके महत्व को नहीं समझ रहा हूं। क्या कोई इस तकनीक का नाम रख सकता है और समझा सकता है कि यह कैसे / क्यों उपयोगी है?


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

मैं जिस उदाहरण से काम कर रहा हूं, वह लर्निंग पायथन द हार्ड वे, 2 थ एड से है। (यह उपलब्ध संस्करण है जब आप Udemy.com के माध्यम से साइन अप करते हैं , दुख की बात है कि लाइव मुफ्त HTML संस्करण वर्तमान में एड 3 है, और अब यह उदाहरण शामिल नहीं है)।

विवरण बताने के लिए:

# make a dictionary of US states and major cities
cities = {'San Diego':'CA', 'New York':'NY', 'Detroit':'MI'}

# define a function to use on such a dictionary
def find_city (map, city):
    # does something, returns some value
    if city in map:
        return map[city]
    else:
        return "Not found"

# then add a final dict element that refers to the function
cities['_found'] = find_city

फिर निम्नलिखित अभिव्यक्तियाँ समकक्ष हैं। आप फ़ंक्शन को सीधे कॉल कर सकते हैं, या उस मुख्य तत्व को संदर्भित कर सकते हैं जिसका मान फ़ंक्शन है।

>>> find_city (cities, 'New York')
NY

>>> cities['_found'](cities, 'New York')
NY

क्या कोई समझा सकता है कि यह किस भाषा की विशेषता है, और शायद यह "वास्तविक" प्रोग्रामिंग में खेलने के लिए कहाँ आता है? यह टॉय एक्सरसाइज मुझे सिंटैक्स सिखाने के लिए काफी थी, लेकिन मुझे वहां तक ​​नहीं ले गई।


13
यह पोस्ट ऑफ़-टॉपिक क्यों होगी? यह एक महान एल्गोरिथ्म और डेटा संरचना अवधारणा प्रश्न है!
मार्टिज़न पीटरसन 20

मैंने अन्य भाषाओं में कुछ इस तरह से देखा (और किया) है। आप इसे एक स्विच स्टेटमेंट के रूप में देख सकते हैं, लेकिन ओ (1) लुकअप समय के साथ एक निष्क्रिय वस्तु में अच्छी तरह से लिपटे हुए हैं।
KChaloux 21

1
मेरे पास एक कूबड़ था, जिसमें कुछ महत्वपूर्ण और आत्म-संदर्भ था, जिसमें फ़ंक्शन अपने स्वयं के अंदर शामिल था ... देखें @ आहारबुद्धि का उत्तर ... लेकिन शायद नहीं?
mdeutschmtl

जवाबों:


83

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

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

def do_ping(self, arg):
    return 'Pong, {0}!'.format(arg)

def do_ls(self, arg):
    return '\n'.join(os.listdir(arg))

dispatch = {
    'ping': do_ping,
    'ls': do_ls,
}

def process_network_command(command, arg):
    send(dispatch[command](arg))

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

प्रेषण विधि का उपयोग करना अन्य तकनीकों की तुलना में अधिक सुरक्षित है, जैसे eval()कि यह उन आज्ञाओं को सीमित करता है जो आपने पहले से परिभाषित की थीं। ls)"; DROP TABLE Students; --मिसाल के तौर पर कोई भी हमलावर किसी डिस्पैच टेबल पर एक इंजेक्शन नहीं लगाने जा रहा है ।


5
@Martjin - यह उस मामले में 'कमांड पैटर्न' का कार्यान्वयन नहीं कहा जा सकता है? ऐसा लगता है कि ओपी को समझने की कोशिश हो रही है?
पीएचडी

3
@PhD: हाँ, मैंने जो उदाहरण बनाया है वह एक कमांड पैटर्न कार्यान्वयन है; dictडिस्पैचर के रूप में कार्य करता है (कमांड मैनेजर, इनवॉकर, आदि)।
मार्टिज़न पीटर

महान शीर्ष-स्तरीय स्पष्टीकरण, @Martijn, धन्यवाद। मुझे लगता है कि मुझे "प्रेषण" विचार मिलता है।
mdeutschmtl

28

@Martijn Pieters ने तकनीक को समझाने का अच्छा काम किया, लेकिन मैं आपके प्रश्न से कुछ स्पष्ट करना चाहता था।

यह जानना महत्वपूर्ण है कि आप शब्दकोश में "फ़ंक्शन का नाम" संग्रहीत नहीं कर रहे हैं । आप फ़ंक्शन के लिए एक संदर्भ संग्रहीत कर रहे हैं। आप इसे printफंक्शन पर इस्तेमाल करके देख सकते हैं ।

>>> def f():
...   print 1
... 
>>> print f
<function f at 0xb721c1b4>

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

>>> a = f
>>> a
<function f at 0xb721c3ac>
>>> a()
1

इसी तरह, आप एक फ़ंक्शन को एक तर्क के रूप में पारित कर सकते हैं।

>>> def c(func):
...   func()
... 
>>> c(f)
1

5
प्रथम श्रेणी के कार्य का उल्लेख निश्चित रूप से :-)
फ्लोरियन मार्गाइन

7

ध्यान दें कि पायथन वर्ग वास्तव में शब्दकोश के लिए केवल एक वाक्यविन्यास चीनी है। जब तुम करोगे:

class Foo(object):
    def find_city(self, city):
        ...

जब तुमने फोन किया

f = Foo()
f.find_city('bar')

वास्तव में बस के रूप में ही है:

getattr(f, 'find_city')('bar')

जो, नाम समाधान के बाद, बस के रूप में ही है:

f.__class__.__dict__['find_city'](f, 'bar')

कॉलबैक में उपयोगकर्ता इनपुट की मैपिंग के लिए एक उपयोगी तकनीक है। उदाहरण के लिए:

def cb1(...): 
    ...
funcs = {
    'cb1': cb1,
    ...
}
while True:
    input = raw_input()
    funcs[input]()

इसे वैकल्पिक रूप से कक्षा में लिखा जा सकता है:

class Funcs(object):
    def cb1(self, a): 
        ...
funcs = Funcs()
while True:
    input = raw_input()
    getattr(funcs, input)()

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


मुझे लगता है कि इस परिवर्तनशीलता ने मुझे "पाइथोनिक" माना है, यह तथ्य कि आप जो कुछ सतह पर देखते हैं, वह केवल कुछ गहराई से पेश करने का एक पारंपरिक तरीका है। शायद यह अजगर के लिए विशेष रूप से नहीं है, हालांकि अजगर अभ्यास (और अजगर प्रोग्रामर?) इस तरह से भाषा सुविधाओं के बारे में बहुत कुछ बात करते हैं।
mdeutschmtl

एक और विचार है, क्या अजगर के लिए कुछ विशिष्ट है जिस तरह से यह मूल्यांकन करने के लिए तैयार है कि दो "शब्द" जैसे क्या लग रहा है, बस एक दूसरे से सटे बैठे हैं, तानाशाही संदर्भ और तर्क सूची? क्या अन्य भाषाएं इसकी अनुमति देती हैं? यह बीजगणित में छलांग के बराबर प्रोग्रामिंग के समान 5 * xहै 5x(सरल सादृश्य को क्षमा करें)।
mdeutschmtl

@mdeutschmtl: यह पायथन के लिए वास्तव में अद्वितीय नहीं है, हालांकि जिन भाषाओं में प्रथम श्रेणी फ़ंक्शन या फ़ंक्शन ऑब्जेक्ट की कमी होती है, उनमें कभी भी ऐसी परिस्थितियां नहीं हो सकती हैं जहां फ़ंक्शन कॉल के तुरंत बाद एक शब्दकोश का उपयोग संभव हो सके।
रेयान

2
@mdeutschmtl "तथ्य यह है कि आप सतह पर जो कुछ भी देखते हैं, वह सिर्फ कुछ गहराई से पेश करने का एक पारंपरिक तरीका है।" - जिसे सिंटैक्टिक शुगर कहा जाता है और यह सभी जगह मौजूद है
इज़्काटा

6

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

1. सूचना छुपाने की तकनीक / एनकैप्सुलेशन और सामंजस्य (वे आमतौर पर हाथ से चलते हैं इसलिए मैं उन्हें एक साथ लूप कर रहा हूं)।

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

2. डिस्पैच टेबल

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

समझौतों से

ध्यान देने वाली एक बात यह है कि आपका कार्य कुंजियों के ज्ञात नामस्थान के साथ ठीक काम करेगा। हालाँकि, आप डेटा और फ़ंक्शंस के बीच कुंजियों के अज्ञात नाम स्थान के बीच टकराव का जोखिम चलाते हैं।


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

0

मैं इस समाधान को पोस्ट करता हूं जो मुझे लगता है कि काफी सामान्य है और यह उपयोगी हो सकता है क्योंकि इसे विशिष्ट मामलों के लिए सरल और आसान रखा जाता है:

def p(what):
    print 'playing', cmpsr

def l(what):
    print 'listening', cmpsr

actions = {'Play' : p, 'Listen' : l}

act = 'Listen'
cmpsr = 'Vivaldi'

actions[act].__call__(cmpsr)

कोई एक सूची भी परिभाषित कर सकता है जहां प्रत्येक तत्व एक फ़ंक्शन ऑब्जेक्ट है और __call__अंतर्निहित विधि का उपयोग करता है । प्रेरणा और सहयोग के लिए सभी को श्रेय।

"महान कलाकार सरलीकृत है", हेनरी फ्रेडरिक एमियल

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.