How to write OOP code with a duck set?

I am having trouble resolving the issue of placing a method in a python program, where it seems the approach used for duck input, which I'm used to relying on, contradicts my OOP instincts.

To illustrate, suppose we have three classes: Hero, Sword, and Apple. A hero can equip a sword, and a hero can eat an apple.

If I were following my OOP gut, I think the code would look like this:

duckless.py

class Hero:
    def __init__(self):
        self.weapon = None
        self.inTummy = None

    def equip(self, weapon):
        weapon.define()
        print("I shall equip it.")
        self.weapon = weapon

    def eat(self, food):
        food.define()
        print("I shall consume it.")
        self.inTummy = food

class Sword:
    def define(self):
        print("'tis a shiny sword")

class Apple:
    def define(self):
        print("'tis a plump apple")

hero = Hero()
swd = Sword()
apl = Apple()

hero.equip(swd)
hero.eat(apl)

Which feels very intuitive and readable.

If I were a duck-type, it seemed to me that the code would look something like this:

duckfull.py

class Hero:
    def __init__(self):
        self.weapon = None
        self.inTummy = None

    def onEquip(self):
        print("I shall equip it.")

    def onEat(self):
        print("I shall eat it.")

class Sword:
    def define(self):
        print("'tis a shiny sword")

    def equip(self, hero):
        self.define()
        hero.onEquip()
        hero.weapon = self


class Apple:
    def define(self):
        print("'tis a plump apple")

    def eat(self, hero):
        self.define()
        hero.onEat()
        hero.inTummy = self

hero = Hero()
swd = Sword()
apl = Apple()

swd.equip(hero)
apl.eat(hero)

Duck code has a clear advantage in that I can execute try-except at any time to determine if I am performing a “legitimate” action:

try:
    apl.equip()
except AttributeError:
    print("I can't equip that!")

pythonic, .

, , , . , , , .

def eat(self, hero):
    self.define()
    hero.onEat()
    hero.inTummy = self

.

? ? ?

.

+4
1

; , . isinstance(weapon, Weapon) Hero.equip, , . , , , Hero:

class Hero:
    def __init__(self):
        self.weapon = None
        self.inTummy = None

    def equip(self, weapon):
        print("I shall equip it.")
        self.weapon = weapon

class Sword:
    def equip(self, hero):
        hero.equip(self)

, , ( sword.equip Hero.equip), Hero.equip weapon.equip() weapon.ready() - , , .

, , , , - . - :

hero.equip(apple)  # no error
hero.weapon.calculateDamage() # AttributeError: Apple object has no attribute `damage`

, , . , : , - , , .

, , , - , . , - . , , , "", , , ; , .

+4

Source: https://habr.com/ru/post/1612318/


All Articles