Может ли zope.interface определить, как должен выглядеть метод класса __init__? - PullRequest
3 голосов
/ 20 марта 2011

У меня есть несколько похожих классов, которые будут инициализированы одним и тем же кодом, и поэтому должны иметь одну и ту же «сигнатуру конструктора». (Есть ли действительно конструкторы и подписи в динамическом Python? Я отвлекся.)

Каков наилучший способ определения параметров классов __ init __ с помощью zope.interface?

Я вставлю код, который использовал для экспериментов с zope.interface, чтобы облегчить обсуждение:


from zope.interface import Interface, Attribute, implements, verify

class ITest(Interface):
    required_attribute = Attribute(
        """A required attribute for classes implementing this interface.""")
    def required_method():
        """A required method for classes implementing this interface."""

class Test(object):
    implements(ITest)
    required_attribute = None
    def required_method():
        pass

print verify.verifyObject(ITest, Test())
print verify.verifyClass(ITest, Test)

Я не могу просто определить функцию __ init __ в ITest, потому что она будет обрабатываться специально интерпретатором Python - я думаю? В любом случае, это не похоже на работу. Итак, еще раз, как лучше всего определить «конструктор класса» с использованием zope.interface?

Ответы [ 3 ]

8 голосов
/ 20 марта 2011

Прежде всего: существует большая разница между понятиями , обеспечивающими и , реализующими интерфейс.

По сути, классы реализуют интерфейс, экземпляры этих классов предоставляют этот интерфейс. В конце концов, классы - это чертежи для экземпляров, детализирующие их реализации.

Теперь интерфейс описывает реализацию, предоставляемую экземплярами, но метод __init__ не является частью экземпляров! Вместо этого он является частью интерфейса, предоставляемого непосредственно классами (метод класса в терминологии Python). Если вы должны определить метод __init__ в своем интерфейсе, вы заявите, что ваши экземпляры имеют (, обеспечивают ) __init__ метод , а также (как метод экземпляра).

Итак, интерфейсы описывают, какие экземпляры вы получаете, а не как вы их получаете.

Теперь интерфейсы можно использовать не только для описания функций, предоставляемых экземпляром. Вы также можете использовать интерфейсы для любого вида объектов в Python, включая модули и классы. Вам нужно будет использовать метод directlyProvides, чтобы назначить им интерфейс, поскольку вы не будете вызывать их для создания экземпляра. Вы также можете использовать декоратор класса @provider() или функции classProvides или moduleProvides из объявления класса или модуля, чтобы получить те же результаты.

В данном случае вы хотите получить фабричное определение; классы - это фабрики, которые при вызове создают экземпляр, поэтому интерфейс фабрики должен предоставить метод __call__, чтобы указать, что они могут быть вызваны. Вот ваш пример с заводским интерфейсом:

from zope import interface

class ITest(interface.Interface):
    required_attribute = interface.Attribute(
        """A required attribute for classes implementing this interface.""")
    def required_method():
        """A required method for classes implementing this interface."""

class ITestFactory(interface.Interface):
    """Creates objects providing the ITest interface"""
    def __call__(a, b):
        """Takes two parameters"""

@interface.implementer(ITest)
@interface.provider(ITestFactory)
class Test(object):
    def __init__(self, a, b):
        self.required_attribute = a*b

    def required_method():
        return self.required_attribute

Пакет zope.component предоставляет вам удобный класс и интерфейс для фабрик , добавляя метод getInterfaces, а также заголовок и описание, чтобы немного упростить обнаружение и самоанализ , Затем вы можете просто создать подкласс интерфейса IFactory, чтобы немного лучше документировать параметры __init__:

from zope import component

class ITestFactory(component.interfaces.IFactory):
    """Creates objects providing the ITest interface"""
    def __call__(a, b):
        """Takes two parameters"""

testFactory = component.Factory(Test, 'ITest Factory', ITestFactory.__doc__)
interface.directlyProvides(testFactory, ITestFactory)

Теперь вы можете зарегистрировать эту фабрику как утилиту zope.component, например, позволяющую другому коду найти всех поставщиков ITestFactory.

Я использовал zope.interface.directlyProvides здесь, чтобы пометить экземпляр фабрики вашим подклассным интерфейсом ITestFactory, поскольку экземпляры zope.component.Factory обычно предоставляют только интерфейс IFactory.

2 голосов
/ 20 марта 2011

Нет, __init__ не обрабатывается по-другому:

from zope.interface import Interface, Attribute, implements, verify

class ITest(Interface):
    required_attribute = Attribute(
        """A required attribute for classes implementing this interface.""")
    def __init__(a,b):
        """Takes two parameters"""
    def required_method():
        """A required method for classes implementing this interface."""

class Test(object):
    implements(ITest)
    def __init__(self, a, b):
        self.required_attribute = a*b
    def required_method():
        return self.required_attribute

print verify.verifyClass(ITest, Test)
print verify.verifyObject(ITest, Test(2,3))

Я не уверен на 100%, что вы спрашиваете.Если вы хотите иметь одинаковую сигнатуру конструктора в нескольких классах Python, единственный способ сделать это - на самом деле иметь одинаковую сигнатуру конструктора в этих классах.:-) Если вы делаете это путем создания подклассов или с разными __init__ для каждого класса, это не имеет значения, если они имеют одинаковую подпись.

zope.interface не об определении методов, а об объявлении подписей,Таким образом, вы можете определить интерфейс, который имеет определенную сигнатуру, также на __init__, но это просто говорит: «Этот объект реализует сигнатуру IMyFace», но говорит, что класс реализует интерфейс, фактически не заставит класс реализовать интерфейс,Вам все еще нужно это реализовать.

0 голосов
/ 20 марта 2011

Не имеет большого смысла, что вы спрашиваете.Предполагается, что файл интерфейса должен содержать описание интерфейса, но не какую-либо конкретную реализацию, которая будет вызываться откуда-либо в любой точке.Что вы, что наследовать.из общего базового класса.zope.interface НЕ о наследовании.

...