Прежде всего: существует большая разница между понятиями , обеспечивающими и , реализующими интерфейс.
По сути, классы реализуют интерфейс, экземпляры этих классов предоставляют этот интерфейс. В конце концов, классы - это чертежи для экземпляров, детализирующие их реализации.
Теперь интерфейс описывает реализацию, предоставляемую экземплярами, но метод __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
.