2013-02-12 92 views
5

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

मैं कई चीजें देखा है:

  1. विधि नाम की पार्सिंग: मुख्य मॉड्यूल प्लगइन मॉड्यूल आयात और विधि के नाम कि एक निश्चित प्रारूप से मिलान के लिए इसे स्कैन होगा। उदाहरण के लिए, यह डाउनलोड_फाइल_command (फ़ाइल) विधि को निर्देश में "डाउनलोड फ़ाइल" -> download_file_command के रूप में जोड़ सकता है। हालांकि, संक्षिप्त, आसान-टाइप-प्रकार कमांड नाम (कहें, "डीएल") प्राप्त करने की आवश्यकता है कि फ़ंक्शन का नाम भी छोटा हो, जो कोड पठनीयता के लिए अच्छा नहीं है। यह प्लगइन डेवलपर को सटीक नामकरण प्रारूप के अनुरूप होने की भी आवश्यकता है।

  2. पार मॉड्यूल सज्जाकार: सज्जाकार दिया जाएगा प्लगइन डेवलपर उसकी समारोह जो कुछ भी वह चाहता है नाम और बस @ Main.register ("डेली") की तरह कुछ जोड़ सकते हैं, लेकिन वे आवश्यक रूप से है कि मैं दोनों की आवश्यकता होगी अन्य मॉड्यूल के नामस्थान को संशोधित करें और मुख्य मॉड्यूल में वैश्विक स्थिति रखें। मैं समझता हूं कि यह बहुत बुरा है।

  3. एक ही मॉड्यूल सज्जाकार: उपर दिए गए तर्क का उपयोग कर, मैं एक डेकोरेटर कुछ आदेश नाम-> समारोह मानचित्रण प्लगइन मॉड्यूल के लिए स्थानीय करने के लिए समारोह का नाम कहते हैं कि जोड़ सकते हैं और करने के लिए मानचित्रण पुनः प्राप्त कर सकता है एपीआई कॉल के साथ मुख्य मॉड्यूल। इसके लिए आवश्यक है कि कुछ विधियां हमेशा मौजूद हों या विरासत में हों, और - अगर सजावट की मेरी समझ सही है - फ़ंक्शन केवल स्वयं ही पहली बार पंजीकृत हो जाएगा और इसके बाद अनावश्यक रूप से प्रत्येक बाद के समय को फिर से पंजीकृत कर देगा।

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

सहायता के लिए धन्यवाद, और मेरी पाइथन समझ में कोई दोष होने पर माफी माँगती है; मैं भाषा के लिए अपेक्षाकृत नया हूँ।

  1. डिस्कवर प्लगइन्स
  2. उत्प्रेरक एक प्लगइन

अपने प्रश्न का पता ही दूसरे भाग में प्रस्तावित समाधान में कुछ कोड निष्पादन:

+1

बस आपको यह एहसास जाँच, लेकिन सज्जाकार (और कार्यशील परिभाषाएँ) रनटाइम पर अमल, केवल एक चीज अजगर संकलन समय पर करता है अपने कोड संकलन है। – Duncan

+1

विधि 2 के साथ कुछ भी गलत नहीं है। उन्हें 'आयात प्लगइन' जैसी कुछ करें और '@ plugin.register (' my_method_name ') \ ndef somefunc_meeting_an_api_spec(): ... ' –

+0

आप इस पर एक नजर डालना चाहेंगे [plac] (http://pypi.python.org/pypi/plac) वह करता है। – georg

उत्तर

4

उपयोगकर्ता परिभाषित कार्यों में मनमाना गुण हो सकते हैं। तो आप निर्दिष्ट कर सकते हैं कि प्लग-इन फ़ंक्शंस में एक निश्चित नाम के साथ एक विशेषता है। उदाहरण के लिए:

import inspect #from standard library 

import plugin 

mapping = {} 

for v in plugin.__dict__.itervalues(): 
    if inspect.isfunction(v) and v.hasattr('command_name'): 
     mapping[v.command_name] = v 

उपयोगकर्ता परिभाषित कार्यों को देखने के the docs

+0

यह वही प्रकार है जिसकी मैं तलाश कर रहा था! – mieubrisse

+0

मुझे एहसास है कि यह प्रश्न थोड़ा पुराना है, लेकिन यहां मेरा संबंधित प्रश्न देखें http://stackoverflow.com/questions/37192712/how-can-attributes-on-functions-survive-wrapping। क्या आप कार्यों पर संग्रहीत विशेषताओं का उपयोग करके रैपिंग के साथ समस्याओं में भाग लेते हैं? – matthewatabet

1

एक प्लगइन प्रणाली में दो भागों रहे हैं।

:

plugins = some_package.plugin_for_your_app 
    another_plugin_module 
    # ... 

प्लगइन मॉड्यूल की लोडिंग को लागू करने के लिए:

वहाँ कई दोनों अपनी आवश्यकताओं पर निर्भर करता है जैसे लागू करने के तरीकों, प्लग-इन सक्षम करने के लिए, वे एक विन्यास फाइल में आपके आवेदन के लिए निर्दिष्ट किया जा सकता है command name -> function:

commands = {name: func 
      for plugin in plugins 
      for name, func in plugin.get_commands().items()} 

एक शब्दकोश प्राप्त करने के लिए 0

प्लगइन लेखक get_commands() को लागू करने के लिए किसी भी विधि का उपयोग कर सकते हैं, उदाहरण के लिए, उपसर्ग या सजावटी का उपयोग करके - आपके मुख्य एप्लिकेशन को get_commands() प्रत्येक प्लगइन के लिए कमांड डिक्शनरी लौटाए जाने तक ध्यान नहीं देना चाहिए।

उदाहरण के लिए, some_plugin.py (पूर्ण स्रोत):

def f(a, b): 
    return a + b 

def get_commands(): 
    return {"add": f, "multiply": lambda x,y: x*y} 

यह दो आदेशों add परिभाषित करता है, multiply

+0

धन्यवाद; मुझे इसके पीछे डिजाइन स्पष्टीकरण पसंद है। यह स्पष्टीकरण बताता है कि get_commands() सूची लागू करने वाला एक सुपरक्लास एक अच्छा विचार हो सकता है, इसलिए डेवलपर्स को जितना संभव हो उतना कम काम करना होगा। – mieubrisse

+0

@mieubrisse: कोई कक्षा की आवश्यकता नहीं है। मैंने पूरा प्लगइन उदाहरण जोड़ा है। – jfs

4

भवन या पर खड़े होकर के लिए मनमाने ढंग से विशेषताओं के बारे में पढ़ने के लिए:

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

################################################################################ 
import functools 
def register(command_name): 
    def wrapped(fn): 
     @functools.wraps(fn) 
     def wrapped_f(*args, **kwargs): 
      return fn(*args, **kwargs) 
     wrapped_f.__doc__ += "(command=%s)" % command_name 
     wrapped_f.command_name = command_name 
     return wrapped_f 
    return wrapped 
################################################################################ 
@register('cp') 
def copy_all_the_files(*args, **kwargs): 
    """Copy many files.""" 
    print "copy_all_the_files:", args, kwargs 
################################################################################ 

print "Command Name: ", copy_all_the_files.command_name 
print "Docstring : ", copy_all_the_files.__doc__ 

copy_all_the_files("a", "b", keep=True) 

आउटपुट जब रन:

Command Name: cp 
Docstring : Copy many files.(command=cp) 
copy_all_the_files: ('a', 'b') {'keep': True}