পাইথনে ইভেন্ট সিস্টেম


195

পাইথনের জন্য আপনি কোন ইভেন্ট সিস্টেম ব্যবহার করেন? আমি পাইডিসপ্যাচার সম্পর্কে ইতিমধ্যে অবগত রয়েছি , তবে আমি ভাবছিলাম যে আর কী পাওয়া যাবে, বা সাধারণত ব্যবহৃত হয়?

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

উত্তর:


178

পাইপিআই প্যাকেজ

2020 সালের জুন পর্যন্ত, এটি পিপিআইতে ইভেন্ট সম্পর্কিত প্যাকেজগুলি উপলভ্য, সাম্প্রতিক প্রকাশের তারিখ দ্বারা আদেশ করা।

আরো আছে

এটি বিভিন্ন লাইব্রেরি থেকে বেছে নিতে বেছে বেছে খুব আলাদা আলাদা পরিভাষা ব্যবহার করে (ইভেন্টস, সিগন্যাল, হ্যান্ডলার, পদ্ধতি প্রেরণ, হুকস, ...)।

আমি উপরের প্যাকেজগুলির সাথে সংক্ষিপ্ত বিবরণ রাখার চেষ্টা করছি, সাথে সাথে উত্তরগুলিতে বর্ণিত কৌশলগুলি।

প্রথমত, কিছু পরিভাষা ...

পর্যবেক্ষক নিদর্শন

ইভেন্ট সিস্টেমের সর্বাধিক প্রাথমিক স্টাইলটি হ'ল ব্যাগগুলির 'হ্যান্ডলার পদ্ধতিগুলি' যা পর্যবেক্ষক প্যাটার্নটির একটি সাধারণ বাস্তবায়ন ।

মূলত, হ্যান্ডলার পদ্ধতিগুলি (কলযোগ্য) একটি অ্যারেতে সংরক্ষণ করা হয় এবং ইভেন্টটি 'অগ্নিকাণ্ডের' সময় প্রতিটি বলা হয়।

সাবস্ক্রাইব প্রকাশ

পর্যবেক্ষক ইভেন্ট সিস্টেমগুলির অসুবিধাটি হ'ল আপনি কেবল আসল ইভেন্ট অবজেক্টে (বা হ্যান্ডলারের তালিকায়) হ্যান্ডলারের নিবন্ধন করতে পারেন। সুতরাং নিবন্ধকরণের সময় ইভেন্টটি ইতিমধ্যে বিদ্যমান থাকা প্রয়োজন।

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

মধ্যস্থতাকারী প্যাটার্ন

পাশাপাশি আগ্রহী হতে পারে: মধ্যস্থতার প্যাটার্ন

আঙ্গুলসমূহ

একটি 'হুক' সিস্টেমটি সাধারণত অ্যাপ্লিকেশন প্লাগইনগুলির প্রসঙ্গে ব্যবহৃত হয়। অ্যাপ্লিকেশনটিতে স্থির ইন্টিগ্রেশন পয়েন্টস (হুকস) রয়েছে এবং প্রতিটি প্লাগইন সেই হুকের সাথে সংযুক্ত হয়ে কিছু নির্দিষ্ট ক্রিয়া সম্পাদন করতে পারে।

অন্যান্য 'ইভেন্ট'

দ্রষ্টব্য: থ্রেডিং.এভেন্ট উপরোক্ত অর্থে কোনও 'ইভেন্ট সিস্টেম' নয়। এটি একটি থ্রেড সিঙ্ক্রোনাইজেশন সিস্টেম যেখানে একটি থ্রেড অপেক্ষা করে অন্য থ্রেড ইভেন্ট অবজেক্টটির 'সংকেত' দেয়।

নেটওয়ার্ক বার্তা পাঠাগারগুলি প্রায়শই 'ইভেন্ট' শব্দটি ব্যবহার করে; কখনও কখনও এগুলি ধারণায় একই রকম হয়; কখনও না। তারা অবশ্যই আড়াআড়ি থ্রেড-, প্রক্রিয়া- এবং কম্পিউটারের সীমানা করতে পারে। যেমন দেখুন pyzmq , pymq , পাক , টর্নেডো , gevent , eventlet

দুর্বল রেফারেন্স

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

কিছু ইভেন্ট সিস্টেমগুলি এটিকে সমাধান করার জন্য নিয়মিত পরিবর্তে দুর্বল রেফারেন্স ব্যবহার করে।

বিভিন্ন গ্রন্থাগার সম্পর্কে কিছু শব্দ

পর্যবেক্ষক-শৈলীর ইভেন্ট সিস্টেমগুলি:

গ্রন্থাগারগুলি সাবস্ক্রাইব করুন:

  • ব্লিঙ্কারের কিছু নিফটি বৈশিষ্ট্য রয়েছে যেমন স্বয়ংক্রিয় সংযোগ বিচ্ছিন্নকরণ এবং প্রেরকের উপর ভিত্তি করে ফিল্টারিং।
  • পাইপবসব হ'ল একটি স্থিতিশীল প্যাকেজ, এবং "উন্নত বৈশিষ্ট্য যা ডিবাগিং এবং বিষয় এবং বার্তা বজায় রাখার সুবিধার্থে" প্রতিশ্রুতি দেয়।
  • পাইমিটারটি নোড.জেএস ইভেন্টইমিটার 2 এর পাইথন বন্দর এবং নামস্থান, ওয়াইল্ডকার্ড এবং টিটিএল অফার করে।
  • পাইডিসপ্যাচার মনে হয় বহু-থেকে-বহু প্রকাশনার ক্ষেত্রে নমনীয়তার উপর জোর দেওয়া হয়েছে দুর্বল উল্লেখগুলি সমর্থন করে।
  • লুই একটি পুনর্গঠিত পাইডিসপাচার এবং এটি "বিভিন্ন প্রসঙ্গে" কাজ করা উচিত।
  • পাইপাইডিসপ্যাচার ভিত্তিক (আপনি এটি অনুমান করেছিলেন ...) পাইডিসপ্যাচার এবং পিপাইতেও কাজ করে।
  • django.dispatch হ'ল একটি সীমাবদ্ধ ইন্টারফেস, তবে উচ্চতর পারফরম্যান্স সহ একটি লিখিত পাইডিসপ্যাচার।
  • পাইয়ান্টডিসপাচার পিএইচপি এর সিমফনি ফ্রেমওয়ার্কের ইভেন্ট-প্রেরণের উপর ভিত্তি করে।
  • প্রেরণকারীটি জ্যাঙ্গো.ডিস্পাচ থেকে নেওয়া হয়েছিল তবে বেশ পুরানো হচ্ছে।
  • ক্রিশ্চিয়ান গার্সিয়ার ইভেন্টম্যাঞ্জার সত্যিই একটি সংক্ষিপ্ত বাস্তবায়ন।

অন্যান্য:

  • প্লাগিটিতে একটি হুক সিস্টেম রয়েছে যা pytestপ্লাগইনগুলি ব্যবহার করে ।
  • আরএক্সপি 3 পর্যবেক্ষণযোগ্য প্যাটার্নটি প্রয়োগ করে এবং সংযুক্ত ইভেন্টগুলি, পুনরায় চেষ্টা করার অনুমতি দেয় etc.
  • কিউটি এর সিগন্যাল ও স্লট থেকে পাওয়া যায় PyQt বা PySide2 । একই থ্রেডে ব্যবহৃত হওয়ার সময় বা দুটি পৃথক থ্রেডের মধ্যে ইভেন্ট হিসাবে (ইভেন্ট লুপ ব্যবহার করে) কলব্যাক হিসাবে কাজ করে। সিগন্যাল এবং স্লটগুলির সীমাবদ্ধতা রয়েছে যে তারা কেবলমাত্র শ্রেণীর বস্তুগুলিতে কাজ করে যা থেকে প্রাপ্ত QObject

2
লুইও রয়েছে, যা পাইডিসপ্যাচারের উপর ভিত্তি করে: pypi.python.org/pypi/Louie/1.1
the979 কিড

@ the979kid লুইটি খারাপভাবে রক্ষণাবেক্ষণ করা হচ্ছে বলে মনে হচ্ছে, পাইপি পৃষ্ঠাগুলি 404s এর সাথে গিটহাবের লিঙ্ক করেছে: 11 craxt.github.io/louie ; github.com/gldnspud/louieGithub.com/11raft/louie হওয়া উচিত
ফ্লোরিস্টা

1
দুর্বল ইভেন্ট শোনার একটি সাধারণ প্রয়োজন। অন্যথায় বাস্তব বিশ্বের ব্যবহার কঠিন হয়ে পড়ে। একটি দ্রষ্টব্য যা সমাধান করতে পারে যা কার্যকর হতে পারে।
কেএক্সআর

পাইপসুব 4 টি বহু-থেকে-বহু, এবং বার্তাগুলির জন্য শক্তিশালী ডিবাগিং সরঞ্জাম এবং ম্যাসেজ পেলোডগুলি সীমাবদ্ধ করার বিভিন্ন উপায় রয়েছে যাতে আপনি অবৈধ ডেটা বা অনুপস্থিত ডেটা প্রেরণ করার আগে জানতে পারবেন। পাইপবসব 4 পাইথন 3 সমর্থন করে (এবং পাইপবসব 3.x পাইথন 2 সমর্থন করে)।
অলিভার

আমি সম্প্রতি পাইমকি github.com/thrau/pymq নামে একটি গ্রন্থাগার প্রকাশ করেছি যা এই তালিকার জন্য উপযুক্ত হতে পারে।
thrau

99

আমি এটি এইভাবে করছি:

class Event(list):
    """Event subscription.

    A list of callable objects. Calling an instance of this will cause a
    call to each item in the list in ascending order by index.

    Example Usage:
    >>> def f(x):
    ...     print 'f(%s)' % x
    >>> def g(x):
    ...     print 'g(%s)' % x
    >>> e = Event()
    >>> e()
    >>> e.append(f)
    >>> e(123)
    f(123)
    >>> e.remove(f)
    >>> e()
    >>> e += (f, g)
    >>> e(10)
    f(10)
    g(10)
    >>> del e[0]
    >>> e(2)
    g(2)

    """
    def __call__(self, *args, **kwargs):
        for f in self:
            f(*args, **kwargs)

    def __repr__(self):
        return "Event(%s)" % list.__repr__(self)

যাইহোক, আমি যা যা দেখেছি তার সবকিছুর মতো, এর জন্য কোনও অটো উত্পন্ন পাইডোক নেই, এবং কোনও স্বাক্ষর নেই যা সত্যই সফল হয়।


3
আমি এই শৈলী বরং আকর্ষণীয় মনে। এটি মিষ্টি খালি হাড়। আমি এটিকে পছন্দ করি যে এটির দ্বারা ইভেন্টগুলি এবং তাদের গ্রাহকদের স্বায়ত্তশাসিত ক্রিয়াকলাপ হিসাবে চালিত করার অনুমতি দেওয়া হয়েছে। আমি দেখব এটি কীভাবে বাস্তব প্রকল্পে ভাড়া নেয়।
রুডি লত্তে

2
খুব সুন্দর নমনীয় স্টাইল! সুপার!
ওরফেম

2
আমি এটিকে যথেষ্ট উত্সাহ দিতে পারি না, এটি সত্যই সোজা এবং সহজ।

2
বড় পক্ষপাত, কেউ কি আমার 10 বছরের মত এটি ব্যাখ্যা করতে পারে? এই শ্রেণিটি কি মূল বর্গ দ্বারা উত্তরাধিকার সূত্রে প্রাপ্ত হয়? আমি এমন কোনও ডিআইআই দেখছি না যাতে এত সুপার () ব্যবহার করা হত না। এটি কোনও কারণে আমার জন্য ক্লিক করছে না।
omgimdrunk

1
@omgimdrunk একটি সাধারণ ইভেন্ট হ্যান্ডলার যখনই কোনও ইভেন্ট চালিত হয় তখন এক বা একাধিক কলযোগ্য ফাংশন বন্ধ করে দেয়। আপনার জন্য এটি "পরিচালনা" করার জন্য একটি শ্রেণীর জন্য ন্যূনতম - অ্যাড এবং ফায়ার প্রয়োজন হবে require এই শ্রেণীর মধ্যে আপনাকে সম্পাদন করার জন্য হ্যান্ডলারের একটি তালিকা বজায় রাখতে হবে। আসুন চলুন যে উদাহরণে পরিবর্তনশীল _bag_of_handlersযা একটি তালিকা। ক্লাসের অ্যাড পদ্ধতিটি সহজভাবে হবে self._bag_of_handlers.append(some_callable)। শ্রেণীর অগ্নি পদ্ধতি হ্যান্ডলারের কাছে প্রদত্ত আর্গ এবং কাওয়ার্গগুলি পাস করে এবং প্রতিটি ক্রমানুসারে কার্যকর করা হবে `
গ্যাবে স্প্রেডলিন 16

68

মাইকেল ফোর্ডের পরামর্শ অনুসারে আমরা তার ইভেন্ট প্যাটার্নে একটি ইভেন্টহুক ব্যবহার করি :

আপনার ক্লাসে কেবল ইভেন্টহুকগুলি যুক্ত করুন এর সাথে:

class MyBroadcaster()
    def __init__():
        self.onChange = EventHook()

theBroadcaster = MyBroadcaster()

# add a listener to the event
theBroadcaster.onChange += myFunction

# remove listener from the event
theBroadcaster.onChange -= myFunction

# fire event
theBroadcaster.onChange.fire()

আমরা সমস্ত শ্রোতাকে একটি বস্তু থেকে মাইকেলস শ্রেণিতে সরানোর জন্য কার্যকারিতা যুক্ত করি এবং এটি দিয়ে শেষ করে:

class EventHook(object):

    def __init__(self):
        self.__handlers = []

    def __iadd__(self, handler):
        self.__handlers.append(handler)
        return self

    def __isub__(self, handler):
        self.__handlers.remove(handler)
        return self

    def fire(self, *args, **keywargs):
        for handler in self.__handlers:
            handler(*args, **keywargs)

    def clearObjectHandlers(self, inObject):
        for theHandler in self.__handlers:
            if theHandler.im_self == inObject:
                self -= theHandler

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

6
শেষ পদ্ধতিটি বাগড হয়েছে কারণ স্ব .__ হ্যান্ডলারগুলি পুনরাবৃত্তির সময় পরিবর্তিত হয়। ফিক্স: `স্ব .__ হ্যান্ডেলার = [স্ব মধ্যে .__ হ্যান্ডেলার জ যদি h.im_self জন্য H = obj!]`
সাইমন Bergot

1
@ সিমন সঠিক, তবে একটি বাগ প্রবর্তন করেছেন কারণ আমাদের নিজের মধ্যে আনবাউন্ড ফাংশন থাকতে পারে __ হ্যান্ডলাররা। স্থির করুন:self.__handlers = [h for h in self._handlers if getattr(h, 'im_self', False) != obj]
এরিক মার্কোস

20

আমি zope.event ব্যবহার করি । আপনি কল্পনা করতে পারেন এটি সবচেয়ে খালি হাড়। :-) আসলে, এখানে সম্পূর্ণ উত্স কোড:

subscribers = []

def notify(event):
    for subscriber in subscribers:
        subscriber(event)

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


17
pypi.python.org/pypi/zope.event ... দরিদ্র গুগল কিছু ব্যান্ডউইথ সংরক্ষণ করতে ;-)
বোল্ডউইন

আমি এখনও বার্তা পাঠাতে সক্ষম হতে চাই। আমি টিকিটারে নির্মিত অ্যাপ্লিকেশনটিতে ইভেন্ট সিস্টেমটি ব্যবহার করব। আমি এটি ইভেন্ট সিস্টেমটি ব্যবহার করছি না কারণ এটি বার্তাগুলি সমর্থন করে না।
জোসিপ

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

15

আমি এই ছোট স্ক্রিপ্টটি মূল্যবান পাঠে পেয়েছি । মনে হচ্ছে ঠিক পরে আছি ঠিক সরলতা / পাওয়ার অনুপাত after পিটার থ্যাচার নিম্নলিখিত কোডগুলির লেখক (কোনও লাইসেন্সের কথা উল্লেখ করা হয়নি)।

class Event:
    def __init__(self):
        self.handlers = set()

    def handle(self, handler):
        self.handlers.add(handler)
        return self

    def unhandle(self, handler):
        try:
            self.handlers.remove(handler)
        except:
            raise ValueError("Handler is not handling this event, so cannot unhandle it.")
        return self

    def fire(self, *args, **kargs):
        for handler in self.handlers:
            handler(*args, **kargs)

    def getHandlerCount(self):
        return len(self.handlers)

    __iadd__ = handle
    __isub__ = unhandle
    __call__ = fire
    __len__  = getHandlerCount

class MockFileWatcher:
    def __init__(self):
        self.fileChanged = Event()

    def watchFiles(self):
        source_path = "foo"
        self.fileChanged(source_path)

def log_file_change(source_path):
    print "%r changed." % (source_path,)

def log_file_change2(source_path):
    print "%r changed!" % (source_path,)

watcher              = MockFileWatcher()
watcher.fileChanged += log_file_change2
watcher.fileChanged += log_file_change
watcher.fileChanged -= log_file_change2
watcher.watchFiles()

1
তালিকার পরিবর্তে একটি সেট () ব্যবহার করা হ্যান্ডলারদের দু'বার নিবন্ধভুক্ত করা এড়ানো ভাল is এর একটি পরিণতি হ্যান্ডলারদের নিবন্ধিত করার ক্রমে ডাকা হচ্ছে না। অগত্যা কোনও খারাপ জিনিস হওয়ার দরকার নেই ...
ফ্লোরিসা

1
@ ফ্লোরিসালা যদি ইচ্ছা করে তবে অর্ডারসেটের জন্য পরিবর্তন আনতে পারে।
রবিনো

9

এখানে একটি ন্যূনতম ডিজাইন রয়েছে যা কাজ করতে হবে। আপনাকে যা করতে হবে তা হল কেবল Observerকোনও শ্রেণিতে উত্তরাধিকারী হওয়া এবং তারপরে observe(event_name, callback_fn)একটি নির্দিষ্ট ইভেন্ট শোনার জন্য ব্যবহার করা। যখনই এই নির্দিষ্ট ইভেন্টটি কোডের (যেমন। Event('USB connected')) কোথাও নিক্ষেপ করা হবে তখন সংশ্লিষ্ট কলব্যাকটি আগুনে ছোঁড়াবে।

class Observer():
    _observers = []
    def __init__(self):
        self._observers.append(self)
        self._observed_events = []
    def observe(self, event_name, callback_fn):
        self._observed_events.append({'event_name' : event_name, 'callback_fn' : callback_fn})


class Event():
    def __init__(self, event_name, *callback_args):
        for observer in Observer._observers:
            for observable in observer._observed_events:
                if observable['event_name'] == event_name:
                    observable['callback_fn'](*callback_args)

উদাহরণ:

class Room(Observer):
    def __init__(self):
        print("Room is ready.")
        Observer.__init__(self) # DON'T FORGET THIS
    def someone_arrived(self, who):
        print(who + " has arrived!")

# Observe for specific event
room = Room()
room.observe('someone arrived',  room.someone_arrived)

# Fire some events
Event('someone left',    'John')
Event('someone arrived', 'Lenard') # will output "Lenard has arrived!"
Event('someone Farted',  'Lenard')

আমি আপনার নকশা পছন্দ করি, এটি সর্বনিম্ন এবং বুঝতে সহজ। এবং কিছু মডিউল আমদানি না করে এটি হালকা হওয়া চাই be
আত্রেয়গৌরব

8

আমি একটি EventManagerক্লাস তৈরি করেছি (শেষে কোড)। বাক্য গঠনটি নিম্নলিখিত:

#Create an event with no listeners assigned to it
EventManager.addEvent( eventName = [] )

#Create an event with listeners assigned to it
EventManager.addEvent( eventName = [fun1, fun2,...] )

#Create any number event with listeners assigned to them
EventManager.addEvent( eventName1 = [e1fun1, e1fun2,...], eventName2 = [e2fun1, e2fun2,...], ... )

#Add or remove listener to an existing event
EventManager.eventName += extra_fun
EventManager.eventName -= removed_fun

#Delete an event
del EventManager.eventName

#Fire the event
EventManager.eventName()

এখানে একটি উদাহরণ:

def hello(name):
    print "Hello {}".format(name)
    
def greetings(name):
    print "Greetings {}".format(name)

EventManager.addEvent( salute = [greetings] )
EventManager.salute += hello

print "\nInitial salute"
EventManager.salute('Oscar')

print "\nNow remove greetings"
EventManager.salute -= greetings
EventManager.salute('Oscar')

আউটপুট:

প্রাথমিক সালাম
গ্রিটিংস অস্কারকে
হ্যালো অস্কারকে

এখন শুভেচ্ছা বার্তা
হ্যালো অস্কার

ইভেন্ট ম্যানেজার কোড:

class EventManager:
    
    class Event:
        def __init__(self,functions):
            if type(functions) is not list:
                raise ValueError("functions parameter has to be a list")
            self.functions = functions
            
        def __iadd__(self,func):
            self.functions.append(func)
            return self
            
        def __isub__(self,func):
            self.functions.remove(func)
            return self
            
        def __call__(self,*args,**kvargs):
            for func in self.functions : func(*args,**kvargs)
            
    @classmethod
    def addEvent(cls,**kvargs):
        """
        addEvent( event1 = [f1,f2,...], event2 = [g1,g2,...], ... )
        creates events using **kvargs to create any number of events. Each event recieves a list of functions,
        where every function in the list recieves the same parameters.
        
        Example:
        
        def hello(): print "Hello ",
        def world(): print "World"
        
        EventManager.addEvent( salute = [hello] )
        EventManager.salute += world
        
        EventManager.salute()
        
        Output:
        Hello World
        """
        for key in kvargs.keys():
            if type(kvargs[key]) is not list:
                raise ValueError("value has to be a list")
            else:
                kvargs[key] = cls.Event(kvargs[key])
        
        cls.__dict__.update(kvargs)

8

আপনি পাইমিটার ( পাইপাই) এর দিকে একবার নজর রাখতে পারেন ) । এটি একটি ছোট একক ফাইল (~ 250 লোক) যোগাযোগ করে "নেমস্পেস, ওয়াইল্ডকার্ড এবং টিটিএল সরবরাহ করে"।

এখানে একটি প্রাথমিক উদাহরণ:

from pymitter import EventEmitter

ee = EventEmitter()

# decorator usage
@ee.on("myevent")
def handler1(arg):
   print "handler1 called with", arg

# callback usage
def handler2(arg):
    print "handler2 called with", arg
ee.on("myotherevent", handler2)

# emit
ee.emit("myevent", "foo")
# -> "handler1 called with foo"

ee.emit("myotherevent", "bar")
# -> "handler2 called with bar"

6

আমি লংপোকের ন্যূনতম পদ্ধতির ভিন্নতা তৈরি করেছি যা কলি এবং কলার উভয়ের জন্য স্বাক্ষরগুলিও নিশ্চিত করে:

class EventHook(object):
    '''
    A simple implementation of the Observer-Pattern.
    The user can specify an event signature upon inizializazion,
    defined by kwargs in the form of argumentname=class (e.g. id=int).
    The arguments' types are not checked in this implementation though.
    Callables with a fitting signature can be added with += or removed with -=.
    All listeners can be notified by calling the EventHook class with fitting
    arguments.

    >>> event = EventHook(id=int, data=dict)
    >>> event += lambda id, data: print("%d %s" % (id, data))
    >>> event(id=5, data={"foo": "bar"})
    5 {'foo': 'bar'}

    >>> event = EventHook(id=int)
    >>> event += lambda wrong_name: None
    Traceback (most recent call last):
        ...
    ValueError: Listener must have these arguments: (id=int)

    >>> event = EventHook(id=int)
    >>> event += lambda id: None
    >>> event(wrong_name=0)
    Traceback (most recent call last):
        ...
    ValueError: This EventHook must be called with these arguments: (id=int)
    '''
    def __init__(self, **signature):
        self._signature = signature
        self._argnames = set(signature.keys())
        self._handlers = []

    def _kwargs_str(self):
        return ", ".join(k+"="+v.__name__ for k, v in self._signature.items())

    def __iadd__(self, handler):
        params = inspect.signature(handler).parameters
        valid = True
        argnames = set(n for n in params.keys())
        if argnames != self._argnames:
            valid = False
        for p in params.values():
            if p.kind == p.VAR_KEYWORD:
                valid = True
                break
            if p.kind not in (p.POSITIONAL_OR_KEYWORD, p.KEYWORD_ONLY):
                valid = False
                break
        if not valid:
            raise ValueError("Listener must have these arguments: (%s)"
                             % self._kwargs_str())
        self._handlers.append(handler)
        return self

    def __isub__(self, handler):
        self._handlers.remove(handler)
        return self

    def __call__(self, *args, **kwargs):
        if args or set(kwargs.keys()) != self._argnames:
            raise ValueError("This EventHook must be called with these " +
                             "keyword arguments: (%s)" % self._kwargs_str())
        for handler in self._handlers[:]:
            handler(**kwargs)

    def __repr__(self):
        return "EventHook(%s)" % self._kwargs_str()

3

যদি আমি পাইকিউটিতে কোড করি আমি কিউটি সকেট / সিগন্যাল দৃষ্টান্ত ব্যবহার করি তবে এটি জ্যাঙ্গোর জন্য

যদি আমি async করছি I / OI নেটিভ সিলেক্ট মডিউল ব্যবহার করে

যদি আমি একটি SAX পাইথন পার্সার ব্যবহার করি তবে আমি SAX এর সরবরাহকৃত ইভেন্ট API ব্যবহার করছি। সুতরাং দেখে মনে হচ্ছে যে আমি অন্তর্নিহিত এপিআইয়ের শিকার :-)

ইভেন্টের ফ্রেমওয়ার্ক / মডিউল থেকে আপনি কী আশা করছেন তা নিজেকে জিজ্ঞাসা করা উচিত। আমার ব্যক্তিগত পছন্দটি কিউটি থেকে সকেট / সিগন্যাল দৃষ্টান্ত ব্যবহার করা। যে সম্পর্কে আরও তথ্য এখানে পাওয়া যাবে


2

বিবেচনার জন্য এখানে আরও একটি মডিউল । এটি আরও চাহিদাযুক্ত অ্যাপ্লিকেশনগুলির পক্ষে একটি কার্যকর পছন্দ বলে মনে হচ্ছে।

পাই-বিজ্ঞপ্তি একটি পাইথন প্যাকেজ যা পর্যবেক্ষক প্রোগ্রামিং প্যাটার্ন বাস্তবায়নের জন্য সরঞ্জাম সরবরাহ করে। এই সরঞ্জামগুলির মধ্যে সংকেত, শর্ত এবং ভেরিয়েবল অন্তর্ভুক্ত রয়েছে।

সিগন্যাল হ্যান্ডলারের তালিকাগুলি যা সংকেত নির্গত হওয়ার সময় ডাকা হয়। কন্ডিশনগুলি মূলত বুলিয়ান ভেরিয়েবলগুলি এমন একটি সংকেত সহ হয় যা শর্তের অবস্থার পরিবর্তন হলে নির্গত হয়। এগুলি স্ট্যান্ডার্ড লজিকাল অপারেটরগুলি (যৌথ শর্তে নয়, এবং ইত্যাদি) ব্যবহার করে একত্রিত করা যেতে পারে। ভেরিয়েবলগুলি, শর্ত থেকে পৃথক, যে কোনও পাইথন অবজেক্ট ধরে রাখতে পারে, কেবল বুলিয়ান নয়, তবে সেগুলি একত্রিত করা যায় না।


1
হোম পৃষ্ঠাটি এটির জন্য কমিশনের বাইরে, সম্ভবত আর সমর্থন করা হচ্ছে না?
ডেভিড পার্ক

1

যদি আপনি ইভেন্টগুলি মার্জ করার মতো পুনরায় চেষ্টা বা পুনরায় চেষ্টা করার মতো আরও জটিল জিনিস করতে চান তবে আপনি পর্যবেক্ষণযোগ্য প্যাটার্ন এবং একটি পরিপক্ক লাইব্রেরি প্রয়োগ করতে পারেন যা এটি কার্যকর করে। https://github.com/ReactiveX/RxPY । জাভাস্ক্রিপ্ট এবং জাভাতে পর্যবেক্ষকগুলি খুব সাধারণ এবং কিছু অ্যাসিঙ্ক কাজের জন্য ব্যবহার করা খুব সুবিধাজনক।

from rx import Observable, Observer


def push_five_strings(observer):
        observer.on_next("Alpha")
        observer.on_next("Beta")
        observer.on_next("Gamma")
        observer.on_next("Delta")
        observer.on_next("Epsilon")
        observer.on_completed()


class PrintObserver(Observer):

    def on_next(self, value):
        print("Received {0}".format(value))

    def on_completed(self):
        print("Done!")

    def on_error(self, error):
        print("Error Occurred: {0}".format(error))

source = Observable.create(push_five_strings)

source.subscribe(PrintObserver())

আউটপুট :

Received Alpha
Received Beta
Received Gamma
Received Delta
Received Epsilon
Done!

1

আপনার যদি এমন ইভেন্টবাসের প্রয়োজন হয় যা প্রক্রিয়া বা নেটওয়ার্কের সীমানা জুড়ে কাজ করে তবে আপনি পাইএমকিউ চেষ্টা করতে পারেন । এটি বর্তমানে পাব / সাব, বার্তার সারি এবং সিঙ্ক্রোনাস আরপিসিকে সমর্থন করে। ডিফল্ট সংস্করণটি রেডিস ব্যাকএন্ডের উপরে কাজ করে, তাই আপনার চলমান রেডিস সার্ভারের প্রয়োজন। পরীক্ষার জন্য একটি ইন-মেমরি ব্যাকএন্ডও রয়েছে। আপনি নিজের ব্যাকএন্ডও লিখতে পারেন।

import pymq

# common code
class MyEvent:
    pass

# subscribe code
@pymq.subscriber
def on_event(event: MyEvent):
    print('event received')

# publisher code
pymq.publish(MyEvent())

# you can also customize channels
pymq.subscribe(on_event, channel='my_channel')
pymq.publish(MyEvent(), channel='my_channel')

সিস্টেমটি আরম্ভ করার জন্য:

from pymq.provider.redis import RedisConfig

# starts a new thread with a Redis event loop
pymq.init(RedisConfig())

# main application control loop

pymq.shutdown()

দাবি অস্বীকার: আমি এই গ্রন্থাগারের লেখক


0

আপনি buslaneমডিউল চেষ্টা করতে পারেন ।

এই গ্রন্থাগারটি বার্তা-ভিত্তিক সিস্টেমের প্রয়োগকে সহজ করে তোলে। এটি আদেশ (একক হ্যান্ডলার) এবং ইভেন্টগুলি (0 বা একাধিক হ্যান্ডলার) পদ্ধতির সমর্থন করে। হ্যান্ডলারকে সঠিকভাবে নিবন্ধ করার জন্য বুজলেন পাইথন ধরণের টিকা ব্যবহার করে।

সাধারণ উদাহরণ:

from dataclasses import dataclass

from buslane.commands import Command, CommandHandler, CommandBus


@dataclass(frozen=True)
class RegisterUserCommand(Command):
    email: str
    password: str


class RegisterUserCommandHandler(CommandHandler[RegisterUserCommand]):

    def handle(self, command: RegisterUserCommand) -> None:
        assert command == RegisterUserCommand(
            email='john@lennon.com',
            password='secret',
        )


command_bus = CommandBus()
command_bus.register(handler=RegisterUserCommandHandler())
command_bus.execute(command=RegisterUserCommand(
    email='john@lennon.com',
    password='secret',
))

বুসলেন ইনস্টল করতে, কেবল পিপ ব্যবহার করুন:

$ pip install buslane

0

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

from pyeventdispatcher import register

register("foo.bar", lambda event: print("second"))
register("foo.bar", lambda event: print("first "), -100)

dispatch(Event("foo.bar", {"id": 1}))
# first second

পাইউভেন্টডিসপাচার দেখুন a

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