Python добавляет к функции динамично

как я добавляю код к существующей функции, или прежде или после?

например, у меня есть класс:

 class A(object):
     def test(self):
         print "here"

как я редактирую метапрограммирование остроумия класса так, чтобы я сделал это

 class A(object):
     def test(self):
         print "here"

         print "and here"

возможно, некоторый способ добавить другую функцию для тестирования?

добавьте другую функцию такой как

 def test2(self):
      print "and here"

и измените оригинал на

 class A(object):
     def test(self):
         print "here"
         self.test2()

существует ли способ сделать это?

17
задан Timmy 7 May 2010 в 14:52
поделиться

5 ответов

Вы можете использовать декоратор для изменения функции, если хотите. Однако, поскольку это не декоратор, применяемый во время первоначального определения функции, вы не сможете использовать синтаксический сахар @ для его применения.

>>> class A(object):
...     def test(self):
...         print "orig"
...
>>> first_a = A()
>>> first_a.test()
orig
>>> def decorated_test(fn):
...     def new_test(*args, **kwargs):
...         fn(*args, **kwargs)
...         print "new"
...     return new_test
...
>>> A.test = decorated_test(A.test)
>>> new_a = A()
>>> new_a.test()
orig
new
>>> first_a.test()
orig
new

Обратите внимание, что это изменит метод и для существующих экземпляров.

EDIT: изменен список args для декоратора на лучшую версию с использованием args и kwargs

22
ответ дан 30 November 2019 в 11:17
поделиться

Выше было много действительно хороших предложений, но одно я не видел, это передача функции с вызовом. Это может выглядеть примерно так:

class A(object):
    def test(self, deep=lambda self: self):
        print "here"
        deep(self)
def test2(self):
    print "and here"

Используя это:

>>> a = A()
>>> a.test()
here
>>> a.test(test2)
here
and here
3
ответ дан 30 November 2019 в 11:17
поделиться

Если ваш класс A наследуется от объекта, вы можете сделать что-то вроде:

def test2():
    print "test"

class A(object):
    def test(self):
        setattr(self, "test2", test2)
        print self.test2
        self.test2()

def main():
    a = A()
    a.test()

if __name__ == '__main__':
    main()

Этот код не интересует, и вы не можете использовать self в своем новом добавленный вами метод. Мне этот код показался забавным, но я никогда не буду его использовать. Я не люблю динамически изменять сам объект.

Это самый быстрый и понятный способ.

0
ответ дан 30 November 2019 в 11:17
поделиться

Почему бы не использовать наследование?

class B(A):
    def test(self):
        super(B, self).test()
        print "and here"
2
ответ дан 30 November 2019 в 11:17
поделиться

Типичный способ добавить функциональность в функцию - использовать декоратор (используя функцию wraps):

from functools import wraps

def add_message(func):
    @wraps
    def with_additional_message(*args, **kwargs)
        try:
            return func(*args, **kwargs)
        finally:
            print "and here"
    return with_additional_message

class A:
    @add_message
    def test(self):
        print "here"

Конечно, все зависит от того, чего вы пытаетесь достичь. Я часто использую декораторы, но если бы я хотел выводить дополнительные сообщения, я бы сделал что-то вроде

class A:
    def __init__(self):
        self.messages = ["here"]

    def test(self):
        for message in self.messages:
            print message

a = A()
a.test()    # prints "here"

a.messages.append("and here")
a.test()    # prints "here" then "and here"

Это не требует мета-программирования, но опять же, ваш пример, вероятно, сильно упрощен по сравнению с тем, что вам нужно сделать на самом деле. Возможно, если вы опишите более подробно ваши конкретные потребности, мы сможем лучше определить, каким должен быть подход Pythonic.

EDIT: Поскольку похоже, что вы хотите вызывать функции, вы можете иметь список функций вместо списка сообщений. Например:

class A:
    def __init__(self):
        self.funcs = []

    def test(self):
        print "here"
        for func in self.funcs:
            func()

def test2():
    print "and here"

a = A()
a.funcs.append(test2)
a.test()    # prints "here" then "and here"

Обратите внимание, что если вы хотите добавить функции, которые будут вызываться всеми экземплярами A, то вам следует сделать funcs полем класса, а не полем экземпляра, например,

class A:
    funcs = []
    def test(self):
        print "here"
        for func in self.funcs:
            func()

def test2():
    print "and here"

A.funcs.append(test2)

a = A()
a.test()    # print "here" then "and here"
10
ответ дан 30 November 2019 в 11:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: