Седма задача

Краен срок
26.05.2011 17:00

Срокът за предаване на решения е отминал

Интерфейси

Интерфейсите са задължителни в статични типизираните езици. Duck typing-а значително намалява нуждата от тях. Въпреки това, те не съвсем безполезни в динамичен език.

Условие

Дефинирайте метаклас interface, който позволява дефинирането на интерфейс и може да проверява дали даден клас го имплементира. Един интерфейс е имплементиран от клас, ако класът има всички методи и аргументите съвпадат.

class stack(metaclass=interface):
    def push(self, item):
        """Pushes the item on the stack"""

    def pop(self):
        """Returns the last pushed item on the stack"""


@stack
class CoolStack:
    def push(self, item):
        ...

    def pop(self):
        ...

За всеки интерфейс важи следното:

  • Представлява клас, чиито метаклас е interface.
  • В интерфейса може да има само публични (незапочващи с _). Ако са дефинирани други атрибути (методи, започващи с _ или не-методи), трябва да се поражда грешка.
  • Методите могат да имат docstring.
  • Имплементацията на методите в интерфейсите няма значение.
  • Бонус точки, ако при метод, с код различен от (pass или docstring), пораждате грешка.
  • Ползвайки интерфейса като клас-декоратор указвате, че даден клас го имплементира

Един клас имплементира един интерфейс, когато има всички методи от интерфейса и за тях е вярно: Един клас klass имплементира интерфейс intf:

  • Имат едни и същи позиционни аргументи, в един и същи ред.
  • За всеки метод intf.method има klass.method.
  • Ако intf.method взема позиционни аргументи, klass.method трябва да взема същия брой позиционни аргументи и те трябва да имат същите имена.
  • Ако intf.method взема *args, то klass.method трябва задължително да взема *args.
  • Ако intf.method не взема *args, то klass.method трябва задължително да не взема *args.
  • Аналогично за **kwargs.
  • intf.method и klass.method могат да имат различни анотации.
  • Ако intf.method има keyword-only аргументи, то klass.method трябва да има същите. Не е задължително да са дефинирани в същия ред. klass.method(self, *, a, b) е валидна имплементация на intf.method(self, *, b, a).

И допълнително:

  • Ако klass.method няма docstring, трябва да го взема от intf.method.
  • Ако искаме от вас да пораждате грешка, пораждайте AssertionError

Ако искате да минете за баш майстори, направете интерфейса да поражда грешка, ако някой от методите в него има имплементация различна от docstring или pass.