Динамически обновляемый метод класса экземпляра выдает ошибку при вызове другим методом класса - PullRequest
3 голосов
/ 18 декабря 2011

Я думаю, мой пример облегчит это:

class x():
    def a(self):
        return "hello"
    def b(self):
        return self.a() + " world"

test = x()
print test.b()     # prints "hello world" as expected

test.a = lambda(self): "hola"
print test.b()     # throws error:
                   # Traceback (most recent call last):
                   #   File "<stdin>", line 1, in <module>
                   #   File "<stdin>", line 5, in b
                   # TypeError: <lambda>() takes exactly 1 argument (0 given)

Попытка обновить точку x (). A до другой функции, но когда x (). B вызывает ее, она не 'Кажется, я передаю себя в качестве первого аргумента.

Я ожидал получить "Привет мир".

Ответы [ 2 ]

1 голос
/ 18 декабря 2011

Вы можете увидеть проблему, если вы делаете

print type(test.a)  # <type 'function'>
print type(test.b)  # <type 'instancemethod'>

Если вы действительно хотите исправить a только на test (не во всех случаях x), вы можете сделать:

import types
test.a = types.MethodType((lambda self: "hola"), test, x)

Для создания объекта типа instancemethod.

0 голосов
/ 18 декабря 2011

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

Когда вам нужно это будет метод?Когда код обращается к частям экземпляра или класса.

В вашем простом примере код замены не обращается к экземпляру, и поэтому вы можете оставить ему функцию в экземпляре, например, так:

test.a = lambda: "hola"

и вот пример, который делает доступэкземпляр с кодом, хранящимся в классе (что обычно требуется):

x.c = lambda self: self.b().upper()

или сохраненный в экземпляре:

# using MethodType
import types
test.c = types.MethodType((lambda self: self.b().upper()), test)

# using partial
import functools
test.c = functools.partial((lambda self: self.b().upper()), test)

# just using the instance name, as Ryan did
test.c = lambda: test.some_attribute

Пока последний метод будет работатьБольшую часть времени у него есть одна ловушка:

oops = test
del oops
oops.c()

Traceback (most recent call last):
  File "test.py", line 42, in <module>
    oops.c()
  File "test.py", line 38, in <lambda>
    test.c = lambda: test.some_attribute
NameError: global name 'test' is not defined

Просто что-то, что нужно иметь в виду.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...