Девета задача

Краен срок
24.06.2011 23:59

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

Multi Dispatch - втори дубъл

Имплементирайте функционалността от задача 6 - мултиметоди, като използвате метакласове вместо декоратори.

Задание

Дефинирайте метаклас multidispatch, чиято употреба изглежда така:

class Asteroid: pass
class Spaceship: pass
class CollisionDetector(metaclass=multidispatch):

    def collide(self, a: Spaceship, b: Spaceship):
        print("Two spaceships")

    def collide(self, a: Spaceship, b: Asteroid):
        print("A spaceship and an asteroid")

    def collide(self, a: Asteroid, b: Spaceship):
        self.collide(b, a)

    def collide(self, a: Asteroid, b: Asteroid):
        print("Two asteroids")

a = Asteroid()
s = Spaceship()

detector = CollisionDetector()

detector.collide(a, a) # Two asteroids
detector.collide(s, a) # A spaceship and an asteroid
detector.collide(s, s) # Two spaceships

Правилата

... са идентични с правилата на 6-та задача. За справка:

Уловката

Един от начините да променяте класовете си е да дефинирате __new__ в метакласа им. Така получавате речника от атрибути на тялото на класа, който в последствие можете да променяте. Но речниците имат проблем - изобраяват име на атрибут в единствена стойност. В конкретния случай това означава, че губите информацията за всяка от дефинициите на даден мултиметод, освен последната.

За да решите този проблем ви се налага да подмените въпросния речник, още преди да е изпълнено тялото на класа. Това можете да направите с функцията __prepare__ на метакласа.

За щастие, дори да не сте виждали __prepare__ в действие, документацията е на ваша страна. А е важно за всеки програмист да може да работи с нея...