В питоне нет понятия интерфейса как такового, но начиная с 2.6 появилось понятие ABC. Понятие довольно интересное, но как оказалось, оно имеет ряд ограничений.Как вы знаете, понятие интерфейсов пришло из статически типизированных языков, таких, как Java и C#. Там интерфейсы — это некоторые абстрактные декларации, которые не могут иметь инстанса. Они так же могут наследоваться, как и обычные классы.
ABC в питоне — это абстрактный класс. Абстрактные классы так же не могут иметь инстанса, но в отличие от интерфейсов абстрактные классы могут иметь дефолтные реализации для наследников (в последних версиях java, начиная с 2014г, и C#, начиная с 8-й версии, интерфейсы так же могут содержать дефолтные реализации). Рассмотрим его на примере на класса IMovable:
from abc import ABCMeta, abstractmethod, abstractproperty class IMovable(): __metaclass__=ABCMeta @abstractmethod def move(): pass @abstractproperty def speed(): pass m = IMovable()
И не могу создать экземпляр абстрактного класса — то что надо! Но попытавшись унаследовать от IMovable другой интерфейс я терплю неудачу:
class IJmper(IMovable): __metaclass__=ABCMeta def move(self): pass def speed(self): pass m = IJmper()
Экземпляр IJmper создается! Не помогло даже принудительное указание метакласса на ABCMeta. Увы. И тогда я решил реализовать свой вариант интерфейса для питона:
За протокол для интерфейса я взял условие, что интерфейс должен начинаться с заглавной буквы I и вторая буква так же должна быть заглавной. Итак, приступим:
Так как интерфейс мне нужен был для джанго, то я назвал его DjangoInterface:
class DjangoInterface(object): @classmethod def isInterface(cls): return cls.__name__[0] == 'I' and cls.__name__[1].isupper() isInterface = False def __init__(self): print self.isInterface def __new__(cls, *args, **kwargs): obj = super(DjangoInterface, cls).__new__(cls) name = cls.__name__ if (len(name) < 2): return obj if cls.__name__[0] == 'I' and cls.__name__[1].isupper(): raise Exception(cls.__name__ + ' is abstract class or interface') #obj.isInterface = True return obj
Переопределив метод __new__ я проверяю имя класса, и если это имя начинается с заглавной I и второй заглавной, то вызываю исключение. ок
В принципе, задача достигнута. Но видите, среди атрибутов DjangoInterface атрибут isInterface — он как будто бы не задействован. А мне бы хотелось знать, является ли класс интерфейсом до того, как будет создан — в общем, реализовать что-то вроде статического конструктора для класса, который бы назначал этому атрибуту значение- да или нет.
Для этого мне пришлось переопределять метакласс и вот что получилось:
class InterfaceMetaclass(type): def __new__(i_metaclass, class_name, class_parents, class_attr): class_attr['isInterface'] = False if class_name[0] == 'I' and class_name[1].isupper(): class_attr['isInterface'] = True return type(class_name, class_parents, class_attr) class Interface(object): __metaclass__ = InterfaceMetaclass print Interface.isInterface
Можете скопировать и поиграться с именами в своем редакторе!
На этом все. Всем удачи