পাইথনে ন্যূনতম প্লাগইন আর্কিটেকচার তৈরি করা


190

পাইথনে লেখা আমার একটি অ্যাপ্লিকেশন রয়েছে যা মোটামুটি প্রযুক্তিগত শ্রোতা (বিজ্ঞানীরা) ব্যবহার করেন।

আমি ব্যবহারকারীদের দ্বারা অ্যাপ্লিকেশনটিকে এক্সটেনসিবল করার একটি ভাল উপায় খুঁজছি, যেমন একটি স্ক্রিপ্টিং / প্লাগইন আর্কিটেকচার।

আমি অত্যন্ত হালকা ওজনের কিছু খুঁজছি । বেশিরভাগ স্ক্রিপ্টস বা প্লাগইনগুলি কোনও তৃতীয় পক্ষ দ্বারা বিকাশ ও বিতরণ করা হবে না এবং ইনস্টল করা হবে না, তবে কোনও পুনরাবৃত্তি টাস্ক স্বয়ংক্রিয় করতে, ফাইল ফর্ম্যাটের জন্য সমর্থন যোগ করতে কয়েক মিনিটের মধ্যে কোনও ব্যবহারকারীকে বেত্রাঘাত করা হবে, ইত্যাদি। সুতরাং প্লাগইনগুলির সর্বনিম্ন ন্যূনতম বয়লারপ্লেট কোড থাকা উচিত এবং কোনও ফোল্ডারে অনুলিপি করা ছাড়া কোনও 'ইনস্টলেশন' দরকার নেই (সুতরাং সেটআপল্টস এন্ট্রি পয়েন্টগুলির মতো কিছু, বা জোপ প্লাগইন আর্কিটেকচারটি খুব বেশি মনে হচ্ছে))

ইতিমধ্যে এখানে ইতিমধ্যে কোনও সিস্টেম রয়েছে, বা এমন কোনও প্রকল্প যা একই ধরণের স্কিম বাস্তবায়িত করে যা আমি ধারণা / অনুপ্রেরণার সন্ধান করা উচিত?

উত্তর:


150

মাইন মূলত, "প্লাগইনস" নামে পরিচিত একটি ডিরেক্টরি যা প্রধান অ্যাপ্লিকেশনটি পোল করতে পারে এবং তারপরে ফাইলগুলি তুলতে ইমপলোড_মডিউল ব্যবহার করতে পারে, মডিউল-স্তরের কনফিগার প্যারামগুলির সাথে একটি সুপরিচিত প্রবেশিকা পয়েন্টটি সন্ধান করতে পারে এবং সেখান থেকে যেতে পারে। আমি নির্দিষ্ট পরিমাণ গতিশীলতার জন্য ফাইল-মনিটরিং স্টাফ ব্যবহার করি যার মধ্যে প্লাগইনগুলি সক্রিয় রয়েছে, তবে এটি খুব সুন্দর।

অবশ্যই, "আমার [বড়, জটিল জিনিস] এক্সের দরকার নেই" বলে বলার সাথে যে কোনও প্রয়োজনীয়তা আসে, আমি কেবলমাত্র হালকা কিছু চাই "এক্স একবারে এক্স আবিষ্কার হওয়া প্রয়োজনীয়তার পুনরায় বাস্তবায়নের ঝুঁকি নিয়ে যায়। তবে এটি যেভাবেই হোক আপনি কিছুটা মজা করতে পারবেন না বলে মনে হয় না :)


26
অনেক ধন্যবাদ! আমি আপনার পোস্টের উপর ভিত্তি করে একটি ছোট টিউটোরিয়াল লিখেছি: lkubuntu.wordpress.com/2012/10/02/writing-a-python-plugin-api
MiJyn

9
impমডিউল পক্ষে অবচিত করা হচ্ছে importlibপাইথন 3.4 থেকে শুরু
b0fh

1
অনেকগুলি ব্যবহারের ক্ষেত্রে আপনি Importlib.import_module এর প্রতিস্থাপন হিসাবে ব্যবহার করতে পারেন imp.load_module
ক্রিস আরেন্ড্ট

58

module_example.py:

def plugin_main(*args, **kwargs):
    print args, kwargs

loader.py:

def load_plugin(name):
    mod = __import__("module_%s" % name)
    return mod

def call_plugin(name, *args, **kwargs):
    plugin = load_plugin(name)
    plugin.plugin_main(*args, **kwargs)

call_plugin("example", 1234)

এটি অবশ্যই "ন্যূনতম", এটির পরীক্ষা করতে একেবারেই ত্রুটি নেই, সম্ভবত অসংখ্য সুরক্ষা সমস্যা রয়েছে, এটি খুব নমনীয় নয় - তবে পাইথনের প্লাগইন সিস্টেমটি কতটা সহজ হতে পারে তা আপনাকে দেখানো উচিত ..

আপনি সম্ভবত মধ্যে দেখতে চাই বিচ্ছু মডিউল খুব, যদিও আপনি শুধু সঙ্গে অনেক কিছু করতে পারেন __import__, os.listdirএবং কিছু স্ট্রিং ম্যানিপুলেশন।


4
আমার মনে হয় আপনি পরিবর্তন করতে চান পারে def call_plugin(name, *args)থেকে def call_plugin(name, *args, **kwargs)তারপর, এবং plugin.plugin_main(*args)থেকেplugin.plugin_main(*args, **kwargs)
রন ক্লেইন

12
পাইথন 3 সালে impপক্ষে অবচিতimportlib
আদম ব্যাক্সটার

30

বিদ্যমান প্লাগইন ফ্রেমওয়ার্ক / লাইব্রেরিগুলি সম্পর্কে এই ওভারভিউটি একবার দেখুন , এটি একটি ভাল সূচনা পয়েন্ট। আমি বেশ ইয়াপসি পছন্দ করি তবে এটি আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে।


25

যদিও এই প্রশ্নটি সত্যিই আকর্ষণীয়, আমি মনে করি এটির উত্তর দেওয়া মোটামুটি কঠিন, আরও বিশদ ছাড়াই। এটি কোন ধরণের প্রয়োগ? এটির একটি জিইউআই আছে? এটি একটি কমান্ড-লাইন সরঞ্জাম? স্ক্রিপ্টের সেট? একটি অনন্য এন্ট্রি পয়েন্ট সহ একটি প্রোগ্রাম ... ইত্যাদি

আমার কাছে থাকা সামান্য তথ্য দেওয়া, আমি খুব সাধারণ পদ্ধতিতে উত্তর দেব।

প্লাগইন যুক্ত করার অর্থ কী?

  • আপনাকে সম্ভবত একটি কনফিগারেশন ফাইল যুক্ত করতে হবে যা পাথ / ডিরেক্টরিগুলি লোড করার জন্য তালিকাবদ্ধ করবে।
  • আর একটি উপায় বলতে হবে "সেই প্লাগইন / ডিরেক্টরিতে যে কোনও ফাইল লোড হবে", তবে এতে আপনার ব্যবহারকারীদের ফাইলগুলি ঘুরে বেড়াতে অসুবিধা হয়।
  • একটি শেষ, মধ্যবর্তী বিকল্পটি হ'ল সমস্ত প্লাগইন একই প্লাগইন / ফোল্ডারে থাকা প্রয়োজন এবং তারপরে একটি কনফিগার ফাইলে আপেক্ষিক পথ ব্যবহার করে এগুলি সক্রিয় / নিষ্ক্রিয় করা উচিত।

খাঁটি কোড / ডিজাইনের অনুশীলনে, আপনি আপনার ব্যবহারকারীদের কী আচরণ / নির্দিষ্ট ক্রিয়াগুলি প্রসারিত করতে চান তা স্পষ্ট করে নির্ধারণ করতে হবে। সাধারণ এন্ট্রি পয়েন্ট / ক্রিয়াকলাপগুলির একটি সেট সনাক্ত করুন যা সর্বদা ওভাররাইড হবে এবং এই ক্রিয়াগুলির মধ্যে গ্রুপ নির্ধারণ করে। এটি হয়ে গেলে আপনার অ্যাপ্লিকেশনটি প্রসারিত করা সহজ হওয়া উচিত,

হুক ব্যবহারের উদাহরণ , মিডিয়াউইকি থেকে অনুপ্রাণিত (পিএইচপি, তবে ভাষা কি সত্যই গুরুত্ব দেয়?):

import hooks

# In your core code, on key points, you allow user to run actions:
def compute(...):
    try:
        hooks.runHook(hooks.registered.beforeCompute)
    except hooks.hookException:
        print('Error while executing plugin')

    # [compute main code] ...

    try:
        hooks.runHook(hooks.registered.afterCompute)
    except hooks.hookException:
        print('Error while executing plugin')

# The idea is to insert possibilities for users to extend the behavior 
# where it matters.
# If you need to, pass context parameters to runHook. Remember that
# runHook can be defined as a runHook(*args, **kwargs) function, not
# requiring you to define a common interface for *all* hooks. Quite flexible :)

# --------------------

# And in the plugin code:
# [...] plugin magic
def doStuff():
    # ....
# and register the functionalities in hooks

# doStuff will be called at the end of each core.compute() call
hooks.registered.afterCompute.append(doStuff)

আর একটি উদাহরণ, উদয় থেকে অনুপ্রাণিত। এখানে, এক্সটেনশানগুলি কেবল এইচজি কমান্ডলাইন এক্সিকিউটেবলের মধ্যে কমান্ড যুক্ত করে, আচরণটি প্রসারিত করে।

def doStuff(ui, repo, *args, **kwargs):
    # when called, a extension function always receives:
    # * an ui object (user interface, prints, warnings, etc)
    # * a repository object (main object from which most operations are doable)
    # * command-line arguments that were not used by the core program

    doMoreMagicStuff()
    obj = maybeCreateSomeObjects()

# each extension defines a commands dictionary in the main extension file
commands = { 'newcommand': doStuff }

উভয় পদ্ধতির জন্য আপনার সাধারণ আরম্ভ এবং চূড়ান্তকরণের প্রয়োজন হতে পারে আপনার এক্সটেনশানের জন্য। আপনি হয় একটি সাধারণ ইন্টারফেস ব্যবহার করতে পারেন যা আপনার সমস্ত এক্সটেনশানটি প্রয়োগ করতে হবে (দ্বিতীয় পদ্ধতির সাথে আরও ভাল ফিট করে; পার্শ্চারাল একটি রিপোসেটআপ ব্যবহার করে (ইউআই, রেপো) যা সমস্ত এক্সটেনশনের জন্য ডাকা হয়), অথবা একটি হুক-ধরণের পদ্ধতির ব্যবহার করে hooks.setup হুক।

তবে আবার আপনি যদি আরও দরকারী উত্তর চান তবে আপনার প্রশ্নটি সঙ্কুচিত করতে হবে;)


11

মার্টি অলচিনের সাধারণ প্লাগইন ফ্রেমওয়ার্কটি আমি আমার নিজের প্রয়োজনের জন্য ব্যবহার করি। আমি এটিকে একবার দেখার জন্য সত্যই পুনঃতফসিল করি, আমি মনে করি আপনি যদি সহজ এবং সহজে হ্যাকযোগ্য কিছু করতে চান তবে এটি সত্যিই ভাল শুরু। আপনি এটি জ্যাঙ্গো স্নিপেট হিসাবেও খুঁজে পেতে পারেন ।


আমি ভিত্তিতে পাইকার্ক দিয়ে এরকম কিছু করার চেষ্টা করছি।
এডোমোর

আমি যা বলতে পারি তা এটি খুব জ্যাঙ্গো-নির্দিষ্ট।
জোড়ান পাভলভিক

3
@ জোড়ানপাভলভিক: মোটেই নয়, স্ট্যান্ডার্ড পাইথনের কয়েকটি লাইন, আপনাকে জ্যাঙ্গো ব্যবহার করতে হবে না।
এডোমোর

11

আমি একজন অবসরপ্রাপ্ত জীববিজ্ঞানী যিনি ডিজিটাল মাইক্রোগ্রাফিক্স নিয়ে কাজ করেছেন এবং দেখেছিলেন যে কোনও এসজিআই মেশিনে চালানোর জন্য তিনি নিজেকে একটি চিত্র প্রক্রিয়াকরণ এবং বিশ্লেষণ প্যাকেজ (প্রযুক্তিগতভাবে একটি লাইব্রেরি নয়) লিখেছেন। আমি সি তে কোডটি লিখেছি এবং স্ক্রিপ্টিং ভাষার জন্য টিসিএল ব্যবহার করেছি। জিইউআই যেমনটি ছিল, ২ হাজার টাকা ব্যবহার করে করা হয়েছিল। টিসিএল-এ হাজির কমান্ডগুলি হ'ল "এক্সটেনশননেম কমান্ডনেম আরজি 0 আরগ 1 ... প্যারাম0 প্যারাম 1 ...", যা স্পেস-বিভাজিত সরল শব্দ এবং সংখ্যাগুলির রূপ of যখন টিসিএল "এক্সটেনশননাম" সাবস্ট্রিং দেখেছিল, নিয়ন্ত্রণটি প্যাকেজটিতে পৌঁছে দেওয়া হয়েছিল। যার ফলে লেক্সার / পার্সারের মাধ্যমে কমান্ডটি চালানো হয়েছিল (লেক্স / ইয়্যাক করা) এবং তারপরে প্রয়োজনীয় হিসাবে সি রুটিনকে ডাকা হয়।

প্যাকেজটি পরিচালনার আদেশগুলি জিইউআইতে একটি উইন্ডো দিয়ে একে একে চালানো যেতে পারে তবে ব্যাচের কাজগুলি পাঠ্য ফাইলগুলি সম্পাদন করে করা হয়েছিল যা বৈধ টিসিএল স্ক্রিপ্ট ছিল; আপনি যে টেম্পলেটটি বেছে নিতে চেয়েছিলেন সে ধরণের ফাইল-স্তরীয় ক্রিয়াকলাপটি আপনি করতে চেয়েছিলেন এবং তারপরে প্রকৃত ডিরেক্টরি এবং ফাইলের নাম এবং প্যাকেজ কমান্ডগুলি ধারণ করতে একটি অনুলিপি সম্পাদনা করতে পারেন। এটি একটি মোহন মত কাজ করে। অবধি ...

1) বিশ্ব পিসিগুলিতে পরিণত হয়েছিল এবং ২) স্ক্রিপ্টগুলি প্রায় 500 লাইনের চেয়ে বেশি হয়ে যায়, যখন টিসিএল এর ইফফাই সাংগঠনিক ক্ষমতাগুলি সত্যিকারের অসুবিধা হতে শুরু করে। সময় পাস ...

আমি অবসর নিয়েছি, পাইথন আবিষ্কার হয়েছিল এবং এটি টিসিএল এর নিখুঁত উত্তরসূরীর মতো লাগছিল। এখন, আমি বন্দরটি কখনই করিনি, কারণ আমি কোনও পিসিতে সি প্যাকেজ সহ পাইথন প্রসারিত এবং পাইথন / জিটি? / টাকা? / / জিওআই করানোর চ্যালেঞ্জগুলির মুখোমুখি হয়েছি না? । তবে সম্পাদনাযোগ্য টেম্পলেট স্ক্রিপ্টগুলির পুরানো ধারণাটি এখনও কার্যক্ষম বলে মনে হচ্ছে। এছাড়াও, নেটিভ পাইথন আকারে প্যাকেজ কমান্ডগুলি প্রবেশ করা খুব বেশি বোঝা হওয়া উচিত নয়: যেমন:

প্যাকেজনাম.কম.মন্ড (আরগ 0, আরজি 1, ..., প্যারাম0, প্যারাম 1, ...)

কয়েকটি অতিরিক্ত বিন্দু, প্যারেনস এবং কমা, কিন্তু সেগুলি শোস্টোপার নয়।

আমার মনে আছে যে পাইথনে কেউ লেক্স এবং ইয়্যাক সংস্করণ করেছে (চেষ্টা করুন: http://www.dabeaz.com/ply/ ), সুতরাং যদি এখনও প্রয়োজন হয় তবে তারা আশেপাশে রয়েছে।

এই দমকাবার বিষয়টি আমার কাছে দেখে মনে হয়েছিল যে পাইথন নিজেই বিজ্ঞানীদের দ্বারা প্রয়োজনীয় "লাইটওয়েট" সামনের প্রান্তটি IS আমি কেন জানতে আগ্রহী যে আপনি কেন এটি না বলে মনে করেন, এবং আমি এটি গুরুত্ব সহকারে বলতে চাই।


পরে যুক্ত: অ্যাপ্লিকেশন gedit প্লাগইনগুলি যুক্ত হওয়ার প্রত্যাশা করে এবং তাদের সাইটের কাছাকাছি দেখার কয়েক মিনিটের মধ্যে আমি খুঁজে পেয়েছি এমন একটি সাধারণ প্লাগইন পদ্ধতিটির স্পষ্ট ব্যাখ্যা। চেষ্টা করুন:

https://wiki.gnome.org/Apps/Gedit/PythonPluginHowToOld

আমি আপনার প্রশ্নটি আরও ভালভাবে বুঝতে চাই। আপনি 1) বিজ্ঞানীরা আপনার (পাইথন) অ্যাপ্লিকেশনটি বিভিন্ন উপায়ে সরাসরি ব্যবহার করতে সক্ষম হতে চান কিনা সে সম্পর্কে আমি অস্পষ্ট অথবা 2) বিজ্ঞানীরা আপনার প্রয়োগে নতুন ক্ষমতা যুক্ত করতে চান allow পছন্দ # 1 হ'ল আমরা চিত্রগুলির মুখোমুখি হওয়া পরিস্থিতি এবং আমাদের জেনেরিক স্ক্রিপ্টগুলি ব্যবহার করতে পরিচালিত করে যা মুহুর্তের প্রয়োজন অনুসারে আমরা সংশোধন করেছি। এটি কি পছন্দ # 2 যা আপনাকে প্লাগইনগুলির ধারণার দিকে নিয়ে যায়, বা এটি আপনার অ্যাপ্লিকেশনটির কোনও দিক যা এটির জন্য আদেশগুলি জারি করা অবর্ণনীয় করে তোলে?


2
লিঙ্ক পচা মেরামত: গেডিট
ohhorob

1
এটি একটি সুন্দর পোস্ট, কারণ এটি স্পষ্টভাবে এবং সংক্ষিপ্তভাবে দেখায় যে আমাদের আধুনিক সময়ের জীববিজ্ঞানীরা কতটা ভাগ্যবান। তার জন্য, অজগর হ'ল মডিউল স্ক্রিপ্টিং ভাষা যা মডিউল বিকাশকারীদের কিছু বিমূর্ততা দেয় যাতে তাদের মূল সি কোডটি বিশ্লেষণের প্রয়োজন হয় না। এখনকার দিনগুলিতে, অল্প কিছু জীববিজ্ঞানী সিটি শিখবেন, তার পরিবর্তে পাইথনে সমস্ত কিছু করবেন। মডিউল লেখার সময় কীভাবে আমরা আমাদের মূল অজগর প্রোগ্রামগুলি বিমূর্ত করতে পারি? এখন থেকে 10 বছরে, সম্ভবত ইমোজিগুলিতে প্রোগ্রামগুলি লেখা হবে এবং মডিউলগুলি কেবল অডিও ফাইল হবে যা গ্রান্টগুলির একটি সিরিজ রয়েছে। এবং সম্ভবত ঠিক আছে।
জেজে

10

আমি যখন পাইথন ডেকোরেটরগুলির সন্ধান করলাম তখন একটি সাধারণ তবে দরকারী কোড স্নিপেট খুঁজে পেয়েছি। এটি আপনার প্রয়োজনের সাথে খাপ খায় না তবে খুব অনুপ্রেরণামূলক।

স্কিপি অ্যাডভান্সড পাইথন # প্লাগইন রেজিস্ট্রেশন সিস্টেম

class TextProcessor(object):
    PLUGINS = []

    def process(self, text, plugins=()):
        if plugins is ():
            for plugin in self.PLUGINS:
                text = plugin().process(text)
        else:
            for plugin in plugins:
                text = plugin().process(text)
        return text

    @classmethod
    def plugin(cls, plugin):
        cls.PLUGINS.append(plugin)
        return plugin


@TextProcessor.plugin
class CleanMarkdownBolds(object):
    def process(self, text):
        return text.replace('**', '')

ব্যবহার:

processor = TextProcessor()
processed = processor.process(text="**foo bar**", plugins=(CleanMarkdownBolds, ))
processed = processor.process(text="**foo bar**")

1
দ্রষ্টব্য: এই উদাহরণে, WordProcessor.pluginকিছুই ( None) ফেরত দেয় না , সুতরাং CleanMdashesExtensionক্লাসটি পরে আমদানি করে কেবল আমদানি করে None। প্লাগইন ক্লাসগুলি যদি তাদের নিজস্বভাবে কার্যকর হয় তবে .pluginক্লাস পদ্ধতিটি তৈরি করুন return plugin
jkmacc

@jkmacc আপনি ঠিক বলেছেন আমি আপনার মন্তব্যের 13 দিন পরে স্নিপেট পরিবর্তন করেছি। ধন্যবাদ.
guneysus

7

আমি পাইকন ২০০৯ এ ডাঃ আন্দ্রে রবার্জ দ্বারা প্রদত্ত বিভিন্ন প্লাগইন আর্কিটেকচারের উপর চমৎকার আলোচনা উপভোগ করেছি He

এটি পডকাস্ট হিসাবে উপলব্ধ (বানর-প্যাচিংয়ের ব্যাখ্যা অনুসরণের দ্বিতীয় ভাগ) সহ ছয়টি ব্লগ এন্ট্রি সহ

আপনি কোনও সিদ্ধান্ত নেওয়ার আগে তাড়াতাড়ি শোনার পরামর্শ দিচ্ছি।


4

আমি এখানে একটি ন্যূনতম প্লাগইন আর্কিটেকচারের সন্ধানে পৌঁছেছি এবং অনেকগুলি জিনিস পেয়েছি যা আমার কাছে ওভারকিলের মতো মনে হয়েছিল। সুতরাং, আমি সুপার সিম্পল পাইথন প্লাগইনগুলি প্রয়োগ করেছি । এটি ব্যবহার করতে, আপনি এক বা একাধিক ডিরেক্টরি তৈরি করেন এবং __init__.pyপ্রত্যেকটিতে একটি বিশেষ ফাইল ফেলে দেন । এই ডিরেক্টরিগুলি আমদানি করার ফলে অন্যান্য সমস্ত পাইথন ফাইল সাবমোডিয়ুল হিসাবে লোড হতে পারে এবং তাদের নাম (গুলি) __all__তালিকায় রাখা হবে । তারপরে সেই সমস্ত মডিউলগুলি বৈধকরণ / আরম্ভ / নিবন্ধিত করা আপনার উপর নির্ভর করে। README ফাইলে একটি উদাহরণ রয়েছে।


4

আসলে setuptools , একটি "প্লাগ-ইন ডিরেক্টরি" সঙ্গে কাজ নিম্নলিখিত উদাহরণে প্রকল্পের ডকুমেন্টেশন থেকে নেওয়া হিসাবে: http://peak.telecommunity.com/DevCenter/PkgResources#locating-plugins

ব্যবহারের উদাহরণ:

plugin_dirs = ['foo/plugins'] + sys.path
env = Environment(plugin_dirs)
distributions, errors = working_set.find_plugins(env)
map(working_set.add, distributions)  # add plugins+libs to sys.path
print("Couldn't load plugins due to: %s" % errors)

দীর্ঘমেয়াদে, সেটআপলগুলি অনেক বেশি নিরাপদ পছন্দ যেহেতু এটি কোনও দ্বন্দ্ব বা অনুপস্থিত প্রয়োজনীয়তা ছাড়াই প্লাগিনগুলি লোড করতে পারে।

আর একটি সুবিধা হ'ল প্লাগইনগুলি নিজেরাই যত্নবান না হওয়া মূল অ্যাপ্লিকেশন ছাড়াই একই প্রক্রিয়া ব্যবহার করে বাড়ানো যেতে পারে।


3

প্লাগইন সিস্টেমে অন্যরকম দৃষ্টিভঙ্গি হিসাবে আপনি এক্সটেন্ড মি প্রকল্পটি পরীক্ষা করতে পারেন

উদাহরণস্বরূপ, আসুন সহজ শ্রেণি এবং এর প্রসারকে সংজ্ঞায়িত করি

# Define base class for extensions (mount point)
class MyCoolClass(Extensible):
    my_attr_1 = 25
    def my_method1(self, arg1):
        print('Hello, %s' % arg1)

# Define extension, which implements some aditional logic
# or modifies existing logic of base class (MyCoolClass)
# Also any extension class maby be placed in any module You like,
# It just needs to be imported at start of app
class MyCoolClassExtension1(MyCoolClass):
    def my_method1(self, arg1):
        super(MyCoolClassExtension1, self).my_method1(arg1.upper())

    def my_method2(self, arg1):
        print("Good by, %s" % arg1)

এবং এটি ব্যবহার করার চেষ্টা করুন:

>>> my_cool_obj = MyCoolClass()
>>> print(my_cool_obj.my_attr_1)
25
>>> my_cool_obj.my_method1('World')
Hello, WORLD
>>> my_cool_obj.my_method2('World')
Good by, World

এবং দৃশ্যের পিছনে কী লুকিয়ে আছে তা দেখান:

>>> my_cool_obj.__class__.__bases__
[MyCoolClassExtension1, MyCoolClass]

extend_me metaclasses মাধ্যমে গ্রন্থাগার নিপূণভাবে ব্যবহার করেন বর্গ সৃষ্টি প্রক্রিয়া, এইভাবে উদাহরণে উপরে, নতুন দৃষ্টান্ত তৈরি যখন MyCoolClassআমরা নতুন ক্লাসের নিদর্শনের সঙ্গে উভয়ের উপশ্রেণী যে পেয়েছিলাম MyCoolClassExtensionএবং MyCoolClassপাইথন এর উভয়ের থাকার কার্যকারিতা, ধন্যবাদ একাধিক উত্তরাধিকার

শ্রেণি তৈরির উপর আরও ভাল নিয়ন্ত্রণের জন্য এই লিবিতে সংজ্ঞায়িত কয়েকটি মেটাচ্লাস রয়েছে:

  • ExtensibleType - সাবক্লাসিং করে সহজ এক্সটেনসিবিলিটি অনুমতি দেয়

  • ExtensibleByHashType - এক্সটেনসিবল টাইপের অনুরূপ, তবে ক্লাসের বিশেষায়িত সংস্করণ তৈরি করার ক্ষমতা রয়েছে, বেস ক্লাসের বিশ্বব্যাপী সম্প্রসারণ এবং শ্রেণীর বিশেষ সংস্করণগুলির বর্ধনের অনুমতি দেওয়া হচ্ছে

এই lib ওপেনারপিপি প্রক্সি প্রকল্পে ব্যবহৃত হয় এবং মনে হয় যথেষ্ট ভাল কাজ করছে!

ব্যবহারের বাস্তব উদাহরণের জন্য, ওপেনআরপি প্রক্সি 'ফিল্ড_ডেটটাইম' এক্সটেনশানটিতে দেখুন :

from ..orm.record import Record
import datetime

class RecordDateTime(Record):
    """ Provides auto conversion of datetime fields from
        string got from server to comparable datetime objects
    """

    def _get_field(self, ftype, name):
        res = super(RecordDateTime, self)._get_field(ftype, name)
        if res and ftype == 'date':
            return datetime.datetime.strptime(res, '%Y-%m-%d').date()
        elif res and ftype == 'datetime':
            return datetime.datetime.strptime(res, '%Y-%m-%d %H:%M:%S')
        return res

Recordএখানে অস্তিত্বযোগ্য বস্তু। RecordDateTimeএক্সটেনশন হয়।

এক্সটেনশন সক্ষম করতে, কেবল এক্সটেনশান ক্লাসযুক্ত মডিউল আমদানি করুন এবং Recordএরপরে তৈরি সমস্ত অবজেক্টের বেস শ্রেণিতে এক্সটেনশন ক্লাস থাকবে, এইভাবে এর সমস্ত কার্যকারিতা থাকবে।

এই লাইব্রেরির প্রধান সুবিধাটি হ'ল, এমন কোড যা এক্সটেনসিবল অবজেক্টগুলি পরিচালনা করে, এক্সটেনশান এবং এক্সটেনশন সম্পর্কে জানতে হবে না যা এক্সটেনসিবল অবজেক্টগুলিতে সমস্ত কিছু পরিবর্তন করতে পারে।


আমার মনে হয় আপনি উপশ্রেণী থেকে instantiate চাওয়ার কথা বলছেন, অর্থাত্ my_cool_obj = MyCoolClassExtension1()পরিবর্তেmy_cool_obj = MyCoolClass()
pylang

না, এক্সটেনসিবল শ্রেণীর __new__পদ্ধতিটি ওভাররাইড করা আছে , সুতরাং এটি স্বয়ংক্রিয়ভাবে সমস্ত উপক্লাগুলি খুঁজে বের করে এবং নতুন শ্রেণি তৈরি করে, এটি তাদের সকলের উপশ্রেনকেন্দ্র এবং এই তৈরি শ্রেণীর নতুন উদাহরণ পুনরায় ফিরে আসে। সুতরাং, মূল অ্যাপ্লিকেশনটি সমস্ত এক্সটেনশন সম্পর্কে জানতে হবে না। গ্রন্থাগারটি তৈরি করার সময়, এই ব্যবহারকারীটি সহজে ব্যবহারযোগ্যরূপে পরিবর্তন বা প্রসারিত করার মঞ্জুরি দেওয়ার জন্য এই পদ্ধতিটি কার্যকর। উপরে উদাহরণস্বরূপ, মাইকুলক্লাসটি গ্রন্থাগারে সংজ্ঞায়িত করা হতে পারে এবং এটি ব্যবহার করে এবং মাইকুলক্লাসএক্সটেনশনটি শেষ ব্যবহারকারী দ্বারা সংজ্ঞায়িত হতে পারে।
ফায়ারমেজ 23'16

উত্তরে আরও একটি উদাহরণ যুক্ত করা হয়েছিল
ফায়ারমেজ

3

সেটআপলগুলিতে একটি এন্ট্রিপয়েন্ট রয়েছে :

এন্ট্রি পয়েন্টগুলি বিতরণ করার জন্য পাইথন অবজেক্টগুলিকে (যেমন ফাংশন বা ক্লাস হিসাবে) অন্যান্য বিতরণগুলির দ্বারা ব্যবহারের জন্য বিতরণ করার একটি সহজ উপায়। এক্সটেনসিবল অ্যাপ্লিকেশন এবং ফ্রেমওয়ার্কগুলি নির্দিষ্ট নাম বা গোষ্ঠীর সাথে প্রবেশের পয়েন্টগুলি সুনির্দিষ্ট ডিস্ট্রিবিউশন থেকে অথবা সিস.পাথের সমস্ত সক্রিয় বিতরণ থেকে অনুসন্ধান করতে পারে এবং তারপরে ইচ্ছামত বিজ্ঞাপনিত বস্তুগুলি পরীক্ষা বা লোড করতে পারে।

আফাইক এই প্যাকেজটি সর্বদা উপলভ্য থাকে যদি আপনি পিপ বা ভার্চুয়ালেনভ ব্যবহার করেন।


2

@ এডোম’র জবাবটি প্রসারিত করার জন্য আমি পরামর্শ দিতে পারি যে সিম্পিপ্লাগিনগুলি (নির্লজ্জ প্লাগ) দেখুন, যা মার্টি আলচিনের কাজ দ্বারা অনুপ্রাণিত একটি সাধারণ প্লাগইন কাঠামো ।

প্রকল্পের README এর উপর ভিত্তি করে একটি সংক্ষিপ্ত ব্যবহারের উদাহরণ:

# All plugin info
>>> BaseHttpResponse.plugins.keys()
['valid_ids', 'instances_sorted_by_id', 'id_to_class', 'instances',
 'classes', 'class_to_id', 'id_to_instance']

# Plugin info can be accessed using either dict...
>>> BaseHttpResponse.plugins['valid_ids']
set([304, 400, 404, 200, 301])

# ... or object notation
>>> BaseHttpResponse.plugins.valid_ids
set([304, 400, 404, 200, 301])

>>> BaseHttpResponse.plugins.classes
set([<class '__main__.NotFound'>, <class '__main__.OK'>,
     <class '__main__.NotModified'>, <class '__main__.BadRequest'>,
     <class '__main__.MovedPermanently'>])

>>> BaseHttpResponse.plugins.id_to_class[200]
<class '__main__.OK'>

>>> BaseHttpResponse.plugins.id_to_instance[200]
<OK: 200>

>>> BaseHttpResponse.plugins.instances_sorted_by_id
[<OK: 200>, <MovedPermanently: 301>, <NotModified: 304>, <BadRequest: 400>, <NotFound: 404>]

# Coerce the passed value into the right instance
>>> BaseHttpResponse.coerce(200)
<OK: 200>

2

আমি পাইথনে প্লাগইন ফ্রেমওয়ার্কটি অনুসন্ধান করার সময় এই থ্রেডটি পড়তে সময় কাটিয়েছি। আমি কিছু ব্যবহার করেছি তবে তাদের সাথে কিছু ত্রুটি ছিল । আমি আপনার তদন্তের জন্য যা নিয়ে আসছি তা এখানে 2017, একটি ইন্টারফেস মুক্ত, আলগাভাবে যুগল প্লাগইন ম্যানেজমেন্ট সিস্টেম: পরে আমাকে লোড করুন । এটি কীভাবে ব্যবহার করবেন সে সম্পর্কে টিউটোরিয়াল এখানে ।


2

আপনি প্লাগইনলিব ব্যবহার করতে পারেন ।

প্লাগইনগুলি তৈরি করা সহজ এবং অন্যান্য প্যাকেজ, ফাইল পাথ বা এন্ট্রি পয়েন্টগুলি থেকে লোড করা যায়।

কোনও প্রয়োজনীয় পদ্ধতি নির্ধারণ করে একটি প্লাগইন প্যারেন্ট ক্লাস তৈরি করুন:

import pluginlib

@pluginlib.Parent('parser')
class Parser(object):

    @pluginlib.abstractmethod
    def parse(self, string):
        pass

পিতামাতা শ্রেণীর উত্তরাধিকার সূত্রে একটি প্লাগইন তৈরি করুন:

import json

class JSON(Parser):
    _alias_ = 'json'

    def parse(self, string):
        return json.loads(string)

প্লাগইনগুলি লোড করুন:

loader = pluginlib.PluginLoader(modules=['sample_plugins'])
plugins = loader.plugins
parser = plugins.parser.json()
print(parser.parse('{"json": "test"}'))

1
উদাহরণের জন্য ধন্যবাদ। আমি 1 টি প্রশ্নের সাথে লড়াই করে যাচ্ছি। যেহেতু আপনি বিভিন্ন প্যাকেজগুলি থেকে প্লাগইনগুলি লোড করার সম্ভাবনার কথা উল্লেখ করেছেন, সম্ভবত আপনি এটি ইতিমধ্যে ভেবেছিলেন। আমি ভাবছি অভিভাবক শ্রেণীর কোথায় অবস্থান করা উচিত। সাধারণত এটি অ্যাপ্লিকেশনটির প্যাকেজে (সম্ভবত পৃথক উত্স কোড সংগ্রহস্থল) রাখার প্রস্তাব দেওয়া হয়, তবে তারপরে আমরা কীভাবে প্লাগিনের কোডবেজে উত্তরাধিকারী হব? আমরা কি এর জন্য পুরো অ্যাপ্লিকেশনটি আমদানি করব? অথবা পার্সার ক্লাসের মতো ইন্টারফেস কোড বা তৃতীয় প্যাকেজের অনুরূপ বিমূর্ততা (যা একটি তৃতীয় কোডের সংগ্রহশালা হবে) থাকা দরকার?
JAponte

1
অভিভাবক শ্রেণীর আবেদনের মতো একই কোড বেসে থাকা উচিত, তবে সম্ভবত তাদের নিজস্ব মডিউলে থাকতে হবে। সুতরাং, বলা প্যাকেজের জন্য fooআপনার কাছে এমন একটি মডিউল বলা যেতে পারে foo.parentsযেখানে আপনি প্যারেন্ট ক্লাসগুলি সংজ্ঞায়িত করেন। তারপরে আপনার প্লাগইনগুলি আমদানি করবে foo.parents। এটি বেশিরভাগ ব্যবহারের ক্ষেত্রে ভাল কাজ করে। কারণ 'foo' নিজেও আমদানি হয়ে যায়, বিজ্ঞপ্তি আমদানির সম্ভাবনা এড়াতে, প্রচুর প্রকল্পগুলি মডিউলটির মূলটি ফাঁকা ছেড়ে দেয় এবং __main__.pyঅ্যাপ্লিকেশন আরম্ভ করার জন্য একটি ফাইল বা এন্ট্রি পয়েন্ট ব্যবহার করে।
এভিসো

1

আমি পাইথনের জন্য ছোট প্লাগইন সিস্টেম আবিষ্কার করার চেষ্টা করে অনেক সময় ব্যয় করেছি যা আমার প্রয়োজন অনুসারে উপযুক্ত। তবে আমি কেবল ভেবেছিলাম, যদি ইতিমধ্যে যদি কোনও উত্তরাধিকার থাকে যা প্রাকৃতিক এবং নমনীয় হয় তবে কেন এটি ব্যবহার করবেন না।

প্লাগইনগুলির জন্য উত্তরাধিকার ব্যবহারের ক্ষেত্রে একমাত্র সমস্যা হ'ল আপনি জানেন না যে সর্বাধিক সুনির্দিষ্ট (উত্তরাধিকারের গাছের নিচে) প্লাগইন ক্লাসগুলি কী।

তবে এটি মেটাক্লাসের সাহায্যে সমাধান করা যেতে পারে যা বেস বর্গের উত্তরাধিকারের উপর নজর রাখে এবং সম্ভবত বর্গ তৈরি করতে পারে যা বেশিরভাগ নির্দিষ্ট প্লাগইন থেকে প্রাপ্ত হয় (নীচের চিত্রটিতে 'রুট প্রসারিত')

এখানে চিত্র বর্ণনা লিখুন

সুতরাং আমি এই জাতীয় একটি মেটাগ্লাস কোড করে একটি সমাধান নিয়ে এসেছি:

class PluginBaseMeta(type):
    def __new__(mcls, name, bases, namespace):
        cls = super(PluginBaseMeta, mcls).__new__(mcls, name, bases, namespace)
        if not hasattr(cls, '__pluginextensions__'):  # parent class
            cls.__pluginextensions__ = {cls}  # set reflects lowest plugins
            cls.__pluginroot__ = cls
            cls.__pluginiscachevalid__ = False
        else:  # subclass
            assert not set(namespace) & {'__pluginextensions__',
                                         '__pluginroot__'}     # only in parent
            exts = cls.__pluginextensions__
            exts.difference_update(set(bases))  # remove parents
            exts.add(cls)  # and add current
            cls.__pluginroot__.__pluginiscachevalid__ = False
        return cls

    @property
    def PluginExtended(cls):
        # After PluginExtended creation we'll have only 1 item in set
        # so this is used for caching, mainly not to create same PluginExtended
        if cls.__pluginroot__.__pluginiscachevalid__:
            return next(iter(cls.__pluginextensions__))  # only 1 item in set
        else:
            name = cls.__pluginroot__.__name__ + 'PluginExtended'
            extended = type(name, tuple(cls.__pluginextensions__), {})
            cls.__pluginroot__.__pluginiscachevalid__ = True
return extended

সুতরাং যখন আপনার কাছে রুট বেস রয়েছে, মেটাক্লাস দিয়ে তৈরি এবং প্লাগইনগুলির গাছ রয়েছে যা এটি থেকে উত্তরাধিকার সূত্রে আসে, আপনি স্বয়ংক্রিয়ভাবে ক্লাস পেতে পারেন, যা কেবলমাত্র সাবক্লাসিংয়ের মাধ্যমে সর্বাধিক নির্দিষ্ট প্লাগইন থেকে উত্তরাধিকার সূত্রে প্রাপ্ত:

class RootExtended(RootBase.PluginExtended):
    ... your code here ...

কোড বেসটি বেশ ছোট (খাঁটি কোডের 30 ডলার লাইন) এবং উত্তরাধিকারের অনুমতি অনুসারে নমনীয়।

আপনি যদি আগ্রহী হন তবে জড়িত হন @ https://github.com/thodnev/pluginlib


1

গ্রাউন্ড ওয়ার্কে আপনার নজর থাকতে পারে ।

ধারণাটি হ'ল পুনরায় ব্যবহারযোগ্য উপাদানগুলির চারপাশে অ্যাপ্লিকেশনগুলি তৈরি করা, যাকে বলা হয় নিদর্শন এবং প্লাগইন। প্লাগইনগুলি এমন ক্লাস যা থেকে প্রাপ্ত GwBasePattern। এখানে একটি প্রাথমিক উদাহরণ:

from groundwork import App
from groundwork.patterns import GwBasePattern

class MyPlugin(GwBasePattern):
    def __init__(self, app, **kwargs):
        self.name = "My Plugin"
        super().__init__(app, **kwargs)

    def activate(self): 
        pass

    def deactivate(self):
        pass

my_app = App(plugins=[MyPlugin])       # register plugin
my_app.plugins.activate(["My Plugin"]) # activate it

কমান্ড লাইন ইন্টারফেস, সিগন্যালিং বা ভাগ করা বস্তুগুলি হ্যান্ডেল করার জন্য আরও উন্নত নিদর্শন রয়েছে।

গ্রাউন্ড ওয়ার্ক তার প্লাগইনগুলিকে প্রোগ্রাম হিসাবে বা কোনও অ্যাপ্লিকেশনকে উপরের মতো দেখানো হয়েছে বা স্বয়ংক্রিয়ভাবে মাধ্যমে বাঁধার মাধ্যমে তা আবিষ্কার করে setuptools। প্ল্যাগইনযুক্ত পাইথন প্যাকেজগুলিকে একটি বিশেষ এন্ট্রি পয়েন্ট ব্যবহার করে এগুলি ঘোষণা করতে হবে groundwork.plugin

এখানে ডক্স রয়েছে

দাবি অস্বীকার : আমি গ্রাউন্ড ওয়ার্কের অন্যতম লেখক।


0

আমাদের বর্তমান স্বাস্থ্যসেবা পণ্যটিতে আমাদের ইন্টারফেস শ্রেণির সাথে একটি প্লাগইন আর্কিটেকচার প্রয়োগ করা হয়েছে। আমাদের টেক স্ট্যাকটি হ'ল এপিআইয়ের জন্য পাইথনের শীর্ষে জ্যাঙ্গো এবং সীমান্তের জন্য নোডেজের শীর্ষে নুস্টজস।

আমাদের প্রোডাক্টের জন্য একটি প্লাগইন ম্যানেজার অ্যাপ লিখিত রয়েছে যা মূলত জ্যাঙ্গো এবং নুস্টজসের সাথে সম্মতিতে পিপ এবং এনপিএম প্যাকেজ।

নতুন প্লাগইন বিকাশের জন্য (পিপ এবং এনএমপি) আমরা প্লাগইন ম্যানেজারকে নির্ভরতা হিসাবে তৈরি করেছি।

পাইপ প্যাকেজে: setup.py এর সাহায্যে আপনি প্লাগইন ব্যবস্থাপক (রেজিস্ট্রি, উদ্যোগ, ... ইত্যাদি) সহ কিছু করার জন্য প্লাগইনটির এন্ট্রিপয়েন্ট যুক্ত করতে পারেন https://setuptools.readthedocs.io/en/latest/setuptools .html # স্বয়ংক্রিয়-স্ক্রিপ্ট-সৃষ্টি

এনপিএম প্যাকেজে: পাইপের অনুরূপ ইনস্টলেশনটি পরিচালনা করতে এনপিএম স্ক্রিপ্টগুলিতে হুক রয়েছে। https://docs.npmjs.com/misc/scripts

আমাদের ইউজকেস:

প্লাগইন ডেভলপমেন্ট টিম এখন কোর ডিওপমেন্ট টিম থেকে আলাদা। প্লাগইন বিকাশের সুযোগটি তৃতীয় পক্ষের অ্যাপগুলির সাথে সংহত করার জন্য যা পণ্যগুলির যে কোনও বিভাগে সংজ্ঞায়িত। প্লাগইন ইন্টারফেসগুলি যেমন শ্রেণীবদ্ধ করা হয়েছে: - ফ্যাক্স, ফোন, ইমেল ... ইত্যাদি প্লাগইন ম্যানেজারকে নতুন বিভাগে উন্নত করা যেতে পারে।

আপনার ক্ষেত্রে: সম্ভবত আপনার একটি প্লাগইন লিখিত থাকতে পারে এবং স্টাফগুলি করার জন্য একই ব্যবহার করতে পারে।

প্লাগইন বিকাশকারীদের যদি পুনরায় ব্যবহারের মূল অবজেক্টগুলি ব্যবহার করতে হয় যা প্লাগইন ম্যানেজারের মধ্যে বিমূর্ততার একটি স্তর করে অবজেক্টটি ব্যবহার করা যেতে পারে যাতে কোনও প্লাগইন সেই পদ্ধতিগুলির উত্তরাধিকারী হতে পারে।

আমরা কীভাবে আমাদের পণ্যটিতে বাস্তবায়ন করেছি তা ভাগ করে নেওয়ার আশা করি এটি একটু ধারণা দেবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.