Как передать `self` в методоподобный объект в Python - PullRequest
1 голос
/ 04 апреля 2019

Если я исправлю метод класса с помощью функции , функция будет вести себя как метод, и self будет передано как первый из args.

class Spam:
    pass

def eggs( *args ):
    return args

Spam.eggs = eggs
spam = Spam()
print( spam.eggs() ) # ---> (<Spam>, )
                     #      all good!

Однако, если я исправлю с использованием экземпляра object .__call__), то self больше не будет передан в качестве аргумента:

class Spam:
    pass

class Beans:
    def __call__( *args ):
        return args

Spam.beans = Beans()
spam = Spam()
print( spam.beans() ) # ---> (<Beans>, )
                      #      - not good, I'd expect this to be
                      #        (<Beans>, <Spam>, )
  • В приведенном выше примере, почему Python решил, что Spam self будет дольше передаваться?
  • Как я могу получить Spam self для прохождения?

Обоснование: В целях кэширования возвращаемых значений я хотел бы изменить функции моего класса (на самом деле, используя декораторы, а не обезьяньи патчи - но это выходит за рамки этого вопроса). Вместо того, чтобы заменять методы моего класса на функции, я хотел бы использовать объекты класса, потому что это делает код более приятным, позволяя мне сохранять состояние в объектах вместо того, чтобы пытаться исправить все замыкания, используя lambda s.

1 Ответ

0 голосов
/ 04 апреля 2019

Это потому, что это функциональные объекты, которые вызываются как методы, и просто определение __call__ делает класс "вызываемым", но не функциональным объектом (см. https://docs.python.org/3/reference/datamodel.html).

Чтобы исправить это, вы можете сделать класс дескриптором:

class Spam:
    pass

class Beans:
    def __call__( *args ):
        return args

    def __get__(self, instance, owner):
        from functools import partial
        return partial(self.__call__, instance)

Spam.beans = Beans()
spam = Spam()
print(spam.beans())

получает

(<__main__.Beans object at 0x00000179F17664E0>, <__main__.Spam object at 0x00000179F1757F98>)
...