简体   繁体   中英

Can I extend a python classmethod in multiple places?

I need to extend a classmethod in Python in multiple files.

Let's say, for the sake of decades of tradition, that we have a class Animal which has a method called Animal.eat

And let's imagine we have a bunch of different modules, eat , swallow and taste

# chew/__init__.py
import Animal

def eat():
    print('chewing')
    super(Animal, self).eat()


Animal.eat = eat <------------ This does not work


# swallow/__init__.py
import Animal

def eat():
    print('swallowing')
    super(Animal, self).eat()

Animal.eat = eat <------------ This does not work


# taste/__init__.py
import Animal

def eat():
    print('tasting')
    super(Animal, self).eat()

Animal.eat = eat <------------ This does not work

And then we have our main.py

import Animal
import chew
import swallow
import taste

animal = Animal()
animal.eat()

Calling animal.eat() should print out

chewing
swallowing
tasting

But the only thing that happens is that it prints out tasting

Can it be done?

There are different to go about this, personally I would use some sort of register classmethod to add to the Animal class from wherever.

class Animal(object):

    _EAT_ACTIONS = []

    def eat(self):
        for action in self._EAT_ACTIONS:
            action()

    @classmethod
    def register_eat_action(cls, action):
        cls._EAT_ACTIONS.append(action)


def chew():
    print('chewing')
Animal.register_eat_action(chew)


def swallow():
    print('swallowing')
Animal.register_eat_action(swallow)


def taste():
    print('tasting')
Animal.register_eat_action(taste)


Animal().eat()
# chewing
# swallowing
# tasting

With the way you were attempting to do in the question, the working version would be somewhat like this, but I'd suggest not do it as it's quite messy.

eat = Animal.eat
def chew(self):
    print('chewing')
    return eat(self)
Animal.eat = chew

Edit: Alternative idea with inheritance:

class Animal(object):
    Chews = False

    def eat(self):
        if self.Chews:
            print('chewing')

class Dog(Animal):
    Chews = True

To extend Animal you need to define a new class which inherits from Animal ... it seems like you want to define a base animal class and a bunch of mixins.

You can do this like:

from abc import ABC, abstractmethod

class BaseAnimal(ABC):
    @abstractmethod
    def eat(self):
        return NotImplemented


class Chews:
    def eat(self):
        print('chewing')
        super().eat()


class Swallows:
    def eat(self):
        print('swallowing')
        super().eat()


class Tastes:
    def eat(self):
        print('tasting')
        super().eat()


class Animal(Chews, Swallows, Tastes, BaseAnimal):
    pass

and it gives:

In [14]: Animal().eat()
chewing
swallowing
tasting

To be honest this is a bad use for mixins though, they should provide independent new functionality (eg chew() , swallow() , taste() methods) instead of extending existing functionality

So on balance I prefer @Peter's answer for your use case.

But I wanted to demonstrate how to do the kind of inheritance you appeared to be trying to do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM