سؤال

لقد بدأت في استخدام واجهات Zope في الكود الخاص بي ، وحتى الآن ، فهي في الحقيقة وثائق فقط. أستخدمها لتحديد السمات التي يجب أن تمتلكها الفصل ، وتنفيذها بشكل صريح في الفئات المناسبة والتحقق منها صراحةً حيث أتوقع واحدة. هذا أمر جيد ، لكنني أود منهم أن يفعلوا المزيد إن أمكن ، مثل التحقق بالفعل من أن الفصل قد نفذ الواجهة ، بدلاً من التحقق من أنني قلت إن الفصل ينفذ الواجهة. لقد قرأت Zope Wiki عدة مرات ، لكن ما زلت لا أستطيع أن أرى استخدامًا أكبر بكثير للواجهات مما أقوم به حاليًا. لذا ، سؤالي هو ماذا يمكنك استخدام هذه الواجهات ، وكيف تستخدمها للمزيد.

هل كانت مفيدة؟

المحلول

يمكنك بالفعل اختبار ما إذا كان الكائن أو الفصل الخاص بك ينفذ الواجهة الخاصة بك. لذلك يمكنك استخدامه verify الوحدة النمطية (عادة ما تستخدمها في اختباراتك):

>>> from zope.interface import Interface, Attribute, implements
>>> class IFoo(Interface):
...     x = Attribute("The X attribute")
...     y = Attribute("The Y attribute")

>>> class Foo(object):
...     implements(IFoo)
...     x = 1
...     def __init__(self):
...         self.y = 2

>>> from zope.interface.verify import verifyObject
>>> verifyObject(IFoo, Foo())
True

>>> from zope.interface.verify import verifyClass
>>> verifyClass(IFoo, Foo)
True

يمكن أيضًا استخدام واجهات لإعداد واختبار الثوابات. يمكنك العثور على مزيد من المعلومات هنا:

http://www.muthukadan.net/docs/zca.html#interfaces

نصائح أخرى

حيث أعمل ، نستخدم واجهات حتى نتمكن من استخدام ZCA ، أو بنية مكون Zope, ، وهو إطار كامل لصنع المكونات التي يمكن تبديلها وقابل للتبديل باستخدام Interfaceس. نحن نستخدم ZCA حتى نتمكن من التعامل مع جميع أنواع التخصيصات لكل العميل دون الحاجة بالضرورة إلى توتر برامجنا أو الحصول على جميع الأجزاء العديدة لكل عميل تعبث الشجرة الرئيسية. غالبًا ما يكون Zope Wiki غير مكتمل تمامًا ، لسوء الحظ. هناك شرح جيد ولكنه يرتفع لمعظم ميزات ZCA على صفحة pypi من ZCA.

أنا لا أستخدم InterfaceS لأي شيء مثل التحقق من أن الفئة تنفذ جميع طرق المعطى Interface. من الناحية النظرية ، قد يكون ذلك مفيدًا عند إضافة طريقة أخرى إلى واجهة ، للتحقق من أنك تذكرت إضافة الطريقة الجديدة إلى جميع الفئات التي تنفذ الواجهة. أنا شخصياً أفضل إنشاء جديد Interface على تعديل واحد قديم. تعديل القديم Interfaces عادة ما تكون فكرة سيئة للغاية بمجرد أن تكون في البيض تم إصدارها إلى PYPI أو إلى بقية مؤسستك.

ملاحظة سريعة على المصطلحات: الفصول ينفذ Interfaces ، والأشياء (مثيلات الفصول) تزود Interfaceس. إذا كنت تريد التحقق من الحصول على Interface, ، إما أن تكتب ISomething.implementedBy(SomeClass) أو ISomething.providedBy(some_object).

لذلك ، وصولاً إلى أمثلة على مكان ZCA مفيد. دعنا ندعي أننا نكتب مدونة ، نستخدم ZCA لجعلها معيارية. سيكون لدينا BlogPost كائن لكل منشور ، والذي سيوفر IBlogPost الواجهة ، كلها محددة في هويتنا المفيدة my.blog بيضة. سنقوم أيضًا بتخزين تكوين المدونة في BlogConfiguration الكائنات التي توفر IBlogConfiguration. باستخدام هذا كنقطة انطلاق ، يمكننا تنفيذ ميزات جديدة دون الحاجة بالضرورة إلى لمسها my.blog على الاطلاق.

فيما يلي قائمة بأمثلة للأشياء التي يمكننا القيام بها باستخدام ZCA ، دون الحاجة إلى تغيير القاعدة my.blog بيضة. لقد قمت أنا أو زملائي في العمل بكل هذه الأشياء (ووجدتها مفيدة) في مشاريع حقيقية من أجل العميل ، على الرغم من أننا لم ننفذ المدونات في ذلك الوقت. :) يمكن حل بعض حالات الاستخدام هنا بشكل أفضل بوسائل أخرى ، مثل ملف CSS طباعة.

  1. إضافة طرق عرض إضافية (BrowserViewS ، عادة مسجلة في ZCML مع ال browser:page التوجيه) لجميع الكائنات التي توفر IBlogPost. يمكنني جعل ملف my.blog.printable بيضة. أن البيضة ستسجل لعبة Browserview print ل IBlogPost, ، مما يجعل منشور المدونة من خلال قالب صفحة Zope مصمم لإنتاج HTML الذي يطبع بشكل جيد. الذي - التي BrowserView سوف تظهر بعد ذلك في عنوان URL /path/to/blogpost/@@print.

  2. آلية الاشتراك في الحدث في Zope. لنفترض أنني أريد نشر خلاصات RSS ، وأريد إنشاءها مقدمًا بدلاً من الطلب. يمكنني إنشاء ملف my.blog.rss بيضة. في تلك البيضة ، سأقوم بتسجيل مشترك في الأحداث التي توفر iobjectmodified (zope.lifecycleevent.interfaces.IObjectModified) ، على الأشياء التي توفر IBlogPost. سيتم استدعاء هذا المشترك في كل مرة تتغير فيها سمة على أي شيء توفير IBlogPost, ، ويمكنني استخدامه لتحديث جميع خلاصات RSS التي يجب أن تظهر فيها منشور المدونة.

    في هذه الحالة ، قد يكون من الأفضل الحصول على IBlogPostModified الحدث الذي يتم إرساله في نهاية كل من BrowserViewS التي تعدل منشورات المدونة ، منذ ذلك الحين IObjectModified يتم إرسالها مرة واحدة على كل تغيير سمة واحدة - والتي قد تكون في كثير من الأحيان من أجل الأداء.

  3. المحولات. المحولات هي "يلقي" بشكل فعال من واجهة إلى أخرى. بالنسبة إلى مهامو لغة البرمجة: تنفذ محولات Zope "مفتوحة" متعددة في Python (عن طريق "Open" أعني "يمكنك إضافة المزيد من الحالات من أي بيضة") ، مع تولي واجهة أكثر تحديدًا الأولوية على المباريات الأقل خصوصية (Interface يمكن أن تكون الفصول الدراسية فئات فرعية لبعضها البعض ، وهذا يفعل بالضبط ما تريد أن يفعله.)

    محولات من واحد Interface يمكن استدعاؤها مع بناء جملة لطيف للغاية ، ISomething(object_to_adapt), ، أو يمكن البحث عنها عبر الوظيفة zope.component.getAdapter. محولات من متعددة Interfaceيجب أن يتم البحث عن الوظيفة عبر الوظيفة zope.component.getMultiAdapter, ، وهو أقل قليلا جميلة.

    يمكنك الحصول على أكثر من محول واحد لمجموعة معينة من InterfaceS ، متباينة بسلسلة name التي تقدمها عند تسجيل المحول. الاسم الافتراضي ل "". علي سبيل المثال، BrowserViewS هي في الواقع محولات تتكيف من الواجهة التي يتم تسجيلها عليها وواجهة تنفذها فئة HTTPrequest. يمكنك أيضا البحث الكل من المحولات المسجلة من تسلسل واحد Interfaceلآخر Interface, ، استخدام zope.component.getAdapters( (IAdaptFrom,), IAdaptTo ), ، الذي يعيد سلسلة من أزواج (الاسم ، المحول). يمكن استخدام ذلك كوسيلة لطيفة للغاية لتوفير السنانير للإضافات لإرفاقها بها.

    لنفترض أنني أردت حفظ جميع منشورات مدونتي وتكوينها كملف XML كبير واحد. أنا إنشاء my.blog.xmldump البيض الذي يحدد IXMLSegment, ويسجل محول من IBlogPost ل IXMLSegment ومحول من IBlogConfiguration ل IXMLSegment. يمكنني الآن استدعاء أي محول مناسب لبعض الأشياء التي أرغب في التسلسل بها عن طريق الكتابة IXMLSegment(object_to_serialize).

    يمكنني حتى إضافة المزيد من المحولات من أشياء أخرى مختلفة إلى IXMLSegment من البيض بخلاف my.blog.xmldump. يحتوي ZCML على ميزة حيث يمكنها تشغيل توجيه معين إذا وفقط إذا تم تثبيت بعض البيض. يمكنني استخدام هذا ل my.blog.rss تسجيل محول من IRSSFeed ل IXMLSegment IFF my.blog.xmldump يحدث أن يتم تثبيته ، دون صنع my.blog.rss يعتمد على my.blog.xmldump.

  4. ViewletS مثل القليل BrowserViewS يمكن أن يكون لديك "الاشتراك" في بقعة معينة داخل صفحة. لا أستطيع أن أتذكر كل التفاصيل في الوقت الحالي ، لكن هذه جيدة جدًا لأشياء مثل الإضافات التي تريد الظهور في الشريط الجانبي.

    لا أستطيع أن أتذكر ما إذا كانت جزءًا من القاعدة Zope أو Plone. أود أن أوصي بعدم استخدام PLONE ما لم تكن المشكلة التي تحاول حلها تحتاج فعليًا إلى CMS حقيقي ، لأنها جزء كبير ومعقد من البرامج وتميل إلى أن تكون بطيئة نوعًا ما.

    أنت لا تحتاج بالضرورة في الواقع ViewletS على أي حال ، منذ ذلك الحين BrowserViewيمكن أن يتصل s ببعضهم البعض ، إما باستخدام "Object/some_browser_view" في تعبير TAL ، أو باستخدام queryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' ), ، لكنها لطيفة جدا بغض النظر.

  5. علامة Interfaceس. علامة Interface هو Interface التي لا توفر أي طرق ولا سمات. يمكنك إضافة علامة Interface أي كائن في وقت التشغيل باستخدام ISomething.alsoProvidedBy. يتيح لك ذلك ، على سبيل المثال ، تغيير المحولات التي سيتم استخدامها على كائن معين وأيها BrowserViewسيتم تعريف S على ذلك.

أعتذر أنني لم أخوض في التفاصيل الكافية لأتمكن من تنفيذ كل من هذه الأمثلة على الفور ، لكنهم كانوا يأخذون نشرًا تقريبًا لكل مدونة.

يمكن أن توفر واجهات Zope طريقة مفيدة لفصل قطعتين من التعليمات البرمجية التي لا ينبغي أن تعتمد على بعضها البعض.

قل أن لدينا مكونًا يعرف كيفية طباعة تحية في الوحدة النمطية:

>>> class Greeter(object):
...     def greet(self):
...         print 'Hello'

وبعض التعليمات البرمجية التي تحتاج إلى طباعة تحية في الوحدة النمطية B.Py:

>>> Greeter().greet()
'Hello'

هذا الترتيب يجعل من الصعب تبديل الكود الذي يتولى التحية دون لمس B.Py (والذي يمكن توزيعه في حزمة منفصلة). بدلاً من ذلك ، يمكننا تقديم وحدة ثالثة C.Py التي تحدد واجهة Igreeter:

>>> from zope.interface import Interface
>>> class IGreeter(Interface):
...     def greet():
...         """ Gives a greeting. """

الآن يمكننا استخدام هذا لفصل A.Py و B.Py. بدلاً من إنشاء فئة تحية ، سيطلب B.Py الآن فائدة توفر واجهة Igreeter. وسيعلن A.Py أن فئة الترحيب تنفذ تلك الواجهة:

(a.py)
>>> from zope.interface import implementer
>>> from zope.component import provideUtility
>>> from c import IGreeter

>>> @implementer(IGreeter)
... class Greeter(object):
...     def greet(self):
...         print 'Hello'
>>> provideUtility(Greeter(), IGreeter)

(b.py)
>>> from zope.component import getUtility
>>> from c import IGreeter

>>> greeter = getUtility(IGreeter)
>>> greeter.greet()
'Hello'

لم أستخدم واجهات Zope مطلقًا ، ولكن قد تفكر في كتابة ملف metaclass, ، الذي يتحقق من التهيئة من أعضاء الفصل ضد الواجهة ، ويثير استثناء وقت التشغيل إذا لم يتم تنفيذ الطريقة.

مع Python ليس لديك خيارات أخرى. إما أن لديها خطوة "ترجمة" تفقد الكود الخاص بك ، أو فحصه ديناميكيًا في وقت التشغيل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top