Я читал, что можно добавить метод к существующему объекту (то есть, не в определении класса) в Python.
Я понимаю, что это не всегда хорошо, чтобы сделать это. Но как можно это сделать?
Я читал, что можно добавить метод к существующему объекту (то есть, не в определении класса) в Python.
Я понимаю, что это не всегда хорошо, чтобы сделать это. Но как можно это сделать?
В Python, есть разница между функциями и связанными методами.
>>> def foo():
... print "foo"
...
>>> class A:
... def bar( self ):
... print "bar"
...
>>> a = A()
>>> foo
<function foo at 0x00A98D70>
>>> a.bar
<bound method A.bar of <__main__.A instance at 0x00A9BC88>>
>>>
Связанные методы были «связаны» (как описательный) к экземпляру, и этот экземпляр будет передан в качестве первого аргумента всякий раз, когда вызывается метод.
Вызываемые объекты которые атрибуты класса (в отличие от, например) все еще несвязанных, хотя, так что вы можете изменить определение класса всякий раз, когда вы хотите:
>>> def fooFighters( self ):
... print "fooFighters"
...
>>> A.fooFighters = fooFighters
>>> a2 = A()
>>> a2.fooFighters
<bound method A.fooFighters of <__main__.A instance at 0x00A9BEB8>>
>>> a2.fooFighters()
fooFighters
Ранее определенные экземпляры обновляются, а также (до тех пор, пока они не переопределены атрибуту себя):
>>> a.fooFighters()
fooFighters
Проблема возникает, когда вы хотите прикрепить метод к одному экземпляру:
>>> def barFighters( self ):
... print "barFighters"
...
>>> a.barFighters = barFighters
>>> a.barFighters()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: barFighters() takes exactly 1 argument (0 given)
Функция автоматически не обязана, когда он прикреплен непосредственно к экземпляру:
>>> a.barFighters
<function barFighters at 0x00A98EF0>
Для того, чтобы связать его, мы можем использовать функцию MethodType в модуле типов :
>>> import types
>>> a.barFighters = types.MethodType( barFighters, a )
>>> a.barFighters
<bound method ?.barFighters of <__main__.A instance at 0x00A9BC88>>
>>> a.barFighters()
barFighters
На этот раз другие экземпляры класса не были затронуты:
>>> a2.barFighters()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'barFighters'
Более подробную информацию можно найти, читая о дескрипторах и метаклассом программирования .
Модуль новый является устаревшим , поскольку Python 2.6 и удален в 3,0, использование типов
см http://docs.python.org/library/new.html
В приведенном ниже примере я намеренно удалены возвращаемого значения из patch_me()
функции. Я думаю , что дает возвращаемое значение может заставить поверить , что патч возвращает новый объект, который не является истинным - он изменяет поступающие один. Вероятно , это может способствовать более дисциплинированного использования monkeypatching.
import types
class A(object):#but seems to work for old style objects too
pass
def patch_me(target):
def method(target,x):
print "x=",x
print "called from", target
target.method = types.MethodType(method,target)
#add more if needed
a = A()
print a
#out: <__main__.A object at 0x2b73ac88bfd0>
patch_me(a) #patch instance
a.method(5)
#out: x= 5
#out: called from <__main__.A object at 0x2b73ac88bfd0>
patch_me(A)
A.method(6) #can patch class too
#out: x= 6
#out: called from <class '__main__.A'>
Добавление метода к существующему экземпляру объекта
Я читал, что можно добавить метод к существующему объекту (например, не в определении класса) в Python.
Я понимаю , что это не всегда хорошее решение , чтобы сделать это. Но, как может один сделать это?
Я не рекомендую это. Это плохая идея. Не делайте этого.
Вот несколько причин:
Таким образом, я полагаю , что вы не сделаете этого , если у вас есть действительно веские основания. Это гораздо лучше , чтобы определить правильный метод в определении класса или менее предпочтительно обезьяна повязки класса непосредственно, как это:
Foo.sample_method = sample_method
Так как это поучительно, однако, я собираюсь показать вам несколько способов сделать это.
Вот код установки. Нам нужно определение класса. Это может быть импортировано, но это действительно не имеет значения.
class Foo(object):
'''An empty class to demonstrate adding a method to an instance'''
Создание экземпляра:
foo = Foo()
Создать метод добавления к нему:
def sample_method(self, bar, baz):
print(bar + baz)
__get__
Пунктирные на поиски функций вызовите __get__
метод функции с экземпляром, привязка объекта к методу и , таким образом создавая «связанный метод.»
foo.sample_method = sample_method.__get__(foo)
и сейчас:
>>> foo.sample_method(1,2)
3
Во-первых, типы импорта, из которого мы получим конструктор метода:
import types
Теперь мы добавим метод экземпляра. Для этого нам понадобится конструктор MethodType из types
модуля (который мы импортировали выше).
Аргумент подписи для types.MethodType является (function, instance, class)
:
foo.sample_method = types.MethodType(sample_method, foo, Foo)
и использование:
>>> foo.sample_method(1,2)
3
Во-первых, мы создаем функцию-оболочку, которая связывает метод к примеру:
def bind(instance, method):
def binding_scope_fn(*args, **kwargs):
return method(instance, *args, **kwargs)
return binding_scope_fn
Применение:
>>> foo.sample_method = bind(foo, sample_method)
>>> foo.sample_method(1,2)
3
Частичная функция применяется первый аргумент (ы) на функцию (и, возможно, именованные аргументы), а в дальнейшем может быть вызвана с остальными аргументами (и первостепенными именованными аргументами). Таким образом:
>>> from functools import partial
>>> foo.sample_method = partial(sample_method, foo)
>>> foo.sample_method(1,2)
3
Это имеет смысл, если учесть, что связанные методы являются частичными функциями экземпляра.
Если попытаться добавить sample_method таким же образом, как мы могли бы добавить его к классу, это несвязанные от экземпляра, и не принимает неявную себя в качестве первого аргумента.
>>> foo.sample_method = sample_method
>>> foo.sample_method(1,2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: sample_method() takes exactly 3 arguments (2 given)
Мы можем сделать несвязанную работу функции, явно передавая экземпляр (или что - нибудь, так как этот метод не использовать self
переменный аргумент), но оно не будет соответствовать ожидаемой подписи других случаев (если мы обезьяна-латание этот экземпляр):
>>> foo.sample_method(foo, 1, 2)
3
Теперь вы знаете несколько способов , которыми Вы могли бы сделать это, но со всей серьезностью - не делайте этого.
Я думаю, что приведенные выше ответы пропустили ключевой момент.
Давайте есть класс с методом:
class A(object):
def m(self):
pass
Теперь, давайте играть с ним в IPython:
In [2]: A.m
Out[2]: <unbound method A.m>
Итак, м () какой - то образом становится несвязанным методом . Но действительно ли это так?
In [5]: A.__dict__['m']
Out[5]: <function m at 0xa66b8b4>
Оказывается, что м () это просто функция, ссылка на которую добавляется А словарь класса - нет никакой магии. Тогда почему Am дает нам несвязанный метод? Это потому , что точка не переводится на простой поиск в словаре. Это де - факто вызова A .__ класса __.__ GetAttribute __ (А, 'т'):
In [11]: class MetaA(type):
....: def __getattribute__(self, attr_name):
....: print str(self), '-', attr_name
In [12]: class A(object):
....: __metaclass__ = MetaA
In [23]: A.m
<class '__main__.A'> - m
<class '__main__.A'> - m
Теперь, я не уверен, что из верхней части моей головы, почему последняя строка печатается дважды, но все же ясно, что там происходит.
Теперь, что __getattribute__ по умолчанию делает то , что он проверяет , является ли атрибут так называемый дескриптор или нет, то есть , если он реализует специальный метод __get__. Если он реализует этот метод, то , что возвращается результат вызова этого метода __get__. Возвращаясь к первой версии нашего А класса, это то , что мы имеем:
In [28]: A.__dict__['m'].__get__(None, A)
Out[28]: <unbound method A.m>
А поскольку функции Python реализуют протокол дескриптора, если они называются по имени объекта, они связывают себя к этому объекту в их методе __get__.
Итак, как добавить метод к существующему объекту? Предполагая, что вы не возражаете зашивки класса, это так просто, как:
B.m = m
Тогда Bm «становится» несвязанный метод, благодаря дескриптору магии.
И если вы хотите, чтобы добавить метод только к одному объекту, то вы должны подражать машинное оборудование самостоятельно, с помощью types.MethodType:
b.m = types.MethodType(m, b)
Кстати:
In [2]: A.m
Out[2]: <unbound method A.m>
In [59]: type(A.m)
Out[59]: <type 'instancemethod'>
In [60]: type(b.m)
Out[60]: <type 'instancemethod'>
In [61]: types.MethodType
Out[61]: <type 'instancemethod'>
В Python обезьяна латание обычно работает путем переписывания класса или функции подписи с вашим собственным. Ниже приведен пример из Zope Wiki :
from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
return "ook ook eee eee eee!"
SomeClass.speak = speak
Этот код будет перезаписывать / создать метод , называемый говорить о классе. В Джефф Этвуд недавно пост на обезьяне заплат . Он показывает пример в C # 3.0 , который является текущим языком я использую для работы.
Есть по крайней мере два способа прикрепить метод к экземпляру без types.MethodType
:
>>> class A:
... def m(self):
... print 'im m, invoked with: ', self
>>> a = A()
>>> a.m()
im m, invoked with: <__main__.A instance at 0x973ec6c>
>>> a.m
<bound method A.m of <__main__.A instance at 0x973ec6c>>
>>>
>>> def foo(firstargument):
... print 'im foo, invoked with: ', firstargument
>>> foo
<function foo at 0x978548c>
1:
>>> a.foo = foo.__get__(a, A) # or foo.__get__(a, type(a))
>>> a.foo()
im foo, invoked with: <__main__.A instance at 0x973ec6c>
>>> a.foo
<bound method A.foo of <__main__.A instance at 0x973ec6c>>
2:
>>> instancemethod = type(A.m)
>>> instancemethod
<type 'instancemethod'>
>>> a.foo2 = instancemethod(foo, a, type(a))
>>> a.foo2()
im foo, invoked with: <__main__.A instance at 0x973ec6c>
>>> a.foo2
<bound method instance.foo of <__main__.A instance at 0x973ec6c>>
Полезные ссылки:
Модель данных - дескрипторы , призывающее
Руководство Descriptor HowTo - призывающие дескрипторы
Вы можете использовать лямбда связать метод экземпляра:
def run(self):
print self._instanceString
class A(object):
def __init__(self):
self._instanceString = "This is instance string"
a = A()
a.run = lambda: run(a)
a.run()
Это пример строки
Процесс закончил с кодом выхода 0
Поскольку этот вопрос, заданный для версий непитоновских, вот JavaScript:
a.methodname = function () { console.log("Yay, a new method!") }
То , что вы ищете, setattr
я считаю. Используйте это , чтобы установить атрибут объекта.
>>> def printme(s): print repr(s)
>>> class A: pass
>>> setattr(A,'printme',printme)
>>> a = A()
>>> a.printme() # s becomes the implicit 'self' variable
< __ main __ . A instance at 0xABCDEFG>
Хотя Jasons ответ работает, он работает только тогда, когда один хочет, чтобы добавить функцию к классу. Это не работает для меня, когда я попытался перезагрузить уже существующий метод из .py исходного кода файла.
Он взял меня на века, чтобы найти обходной путь, но трюк кажется простым ... 1.st импортировать код из файла исходного кода 2-ом принудительно использовать перезарядка 3-яя types.FunctionType (...), чтобы преобразовать импортирован и связанный метод к функции вы можете также перейти на текущих глобальных переменных, как перегружается метод будет в другом пространстве имен 4.th теперь вы можете продолжить как это было предложено «Джейсон Pratt», используя types.MethodType (... )
Пример:
# this class resides inside ReloadCodeDemo.py
class A:
def bar( self ):
print "bar1"
def reloadCode(self, methodName):
''' use this function to reload any function of class A'''
import types
import ReloadCodeDemo as ReloadMod # import the code as module
reload (ReloadMod) # force a reload of the module
myM = getattr(ReloadMod.A,methodName) #get reloaded Method
myTempFunc = types.FunctionType(# convert the method to a simple function
myM.im_func.func_code, #the methods code
globals(), # globals to use
argdefs=myM.im_func.func_defaults # default values for variables if any
)
myNewM = types.MethodType(myTempFunc,self,self.__class__) #convert the function to a method
setattr(self,methodName,myNewM) # add the method to the function
if __name__ == '__main__':
a = A()
a.bar()
# now change your code and save the file
a.reloadCode('bar') # reloads the file
a.bar() # now executes the reloaded code
Вы , ребята , должны реально смотреть на запретный плод , это библиотека Python , которая обеспечивает поддержку обезьяны Patching любого класса питона, даже строки.
Закрепление ответы Джейсон Пратта и сообщества вики, с видом на результаты различных методов связывания:
Особенно обратите внимание , как добавление функции связывания как метод класса работает , но ссылки сфера неверна.
#!/usr/bin/python -u
import types
import inspect
## dynamically adding methods to a unique instance of a class
# get a list of a class's method type attributes
def listattr(c):
for m in [(n, v) for n, v in inspect.getmembers(c, inspect.ismethod) if isinstance(v,types.MethodType)]:
print m[0], m[1]
# externally bind a function as a method of an instance of a class
def ADDMETHOD(c, method, name):
c.__dict__[name] = types.MethodType(method, c)
class C():
r = 10 # class attribute variable to test bound scope
def __init__(self):
pass
#internally bind a function as a method of self's class -- note that this one has issues!
def addmethod(self, method, name):
self.__dict__[name] = types.MethodType( method, self.__class__ )
# predfined function to compare with
def f0(self, x):
print 'f0\tx = %d\tr = %d' % ( x, self.r)
a = C() # created before modified instnace
b = C() # modified instnace
def f1(self, x): # bind internally
print 'f1\tx = %d\tr = %d' % ( x, self.r )
def f2( self, x): # add to class instance's .__dict__ as method type
print 'f2\tx = %d\tr = %d' % ( x, self.r )
def f3( self, x): # assign to class as method type
print 'f3\tx = %d\tr = %d' % ( x, self.r )
def f4( self, x): # add to class instance's .__dict__ using a general function
print 'f4\tx = %d\tr = %d' % ( x, self.r )
b.addmethod(f1, 'f1')
b.__dict__['f2'] = types.MethodType( f2, b)
b.f3 = types.MethodType( f3, b)
ADDMETHOD(b, f4, 'f4')
b.f0(0) # OUT: f0 x = 0 r = 10
b.f1(1) # OUT: f1 x = 1 r = 10
b.f2(2) # OUT: f2 x = 2 r = 10
b.f3(3) # OUT: f3 x = 3 r = 10
b.f4(4) # OUT: f4 x = 4 r = 10
k = 2
print 'changing b.r from {0} to {1}'.format(b.r, k)
b.r = k
print 'new b.r = {0}'.format(b.r)
b.f0(0) # OUT: f0 x = 0 r = 2
b.f1(1) # OUT: f1 x = 1 r = 10 !!!!!!!!!
b.f2(2) # OUT: f2 x = 2 r = 2
b.f3(3) # OUT: f3 x = 3 r = 2
b.f4(4) # OUT: f4 x = 4 r = 2
c = C() # created after modifying instance
# let's have a look at each instance's method type attributes
print '\nattributes of a:'
listattr(a)
# OUT:
# attributes of a:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FD88>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FD88>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FD88>>
print '\nattributes of b:'
listattr(b)
# OUT:
# attributes of b:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FE08>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FE08>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FE08>>
# f1 <bound method ?.f1 of <class __main__.C at 0x000000000237AB28>>
# f2 <bound method ?.f2 of <__main__.C instance at 0x000000000230FE08>>
# f3 <bound method ?.f3 of <__main__.C instance at 0x000000000230FE08>>
# f4 <bound method ?.f4 of <__main__.C instance at 0x000000000230FE08>>
print '\nattributes of c:'
listattr(c)
# OUT:
# attributes of c:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x0000000002313108>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002313108>>
# f0 <bound method C.f0 of <__main__.C instance at 0x0000000002313108>>
Лично я предпочитаю функцию внешнего ADDMETHOD маршрут, поскольку это позволяет мне динамически назначать новые имена методов в итераторе, а также.
def y(self, x):
pass
d = C()
for i in range(1,5):
ADDMETHOD(d, y, 'f%d' % i)
print '\nattributes of d:'
listattr(d)
# OUT:
# attributes of d:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x0000000002303508>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002303508>>
# f0 <bound method C.f0 of <__main__.C instance at 0x0000000002303508>>
# f1 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f2 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f3 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f4 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
Что Джейсон Pratt отвечал правильно.
>>> class Test(object):
... def a(self):
... pass
...
>>> def b(self):
... pass
...
>>> Test.b = b
>>> type(b)
<type 'function'>
>>> type(Test.a)
<type 'instancemethod'>
>>> type(Test.b)
<type 'instancemethod'>
Как вы можете видеть, Python не учитывает б () не отличается чем (). В Python все методы являются лишь переменные, которые происходят с функциями.
Если это может быть какой-либо помощи, я недавно выпустила библиотеку Python под названием Gorilla, чтобы сделать процесс обезьяны зашивки более удобным.
Использование функции needle()
пропатчить модуль с именем guineapig
выглядит следующим образом :
import gorilla
import guineapig
@gorilla.patch(guineapig)
def needle():
print("awesome")
Но он также заботится о более интересных случаев использования , как показано в FAQ от документации .
Код доступен на GitHub .
Я нахожу странным, что никто не отметил, что все методы, перечисленные выше создает ссылку цикла между дополнительным способом и, например, в результате чего объекта быть стойкими до сбора мусора. Был старый трюк добавить дескриптор, расширив класс объекта:
def addmethod(obj, name, func):
klass = obj.__class__
subclass = type(klass.__name__, (klass,), {})
setattr(subclass, name, func)
obj.__class__ = subclass
Этот вопрос был открыт год назад, но эй, есть простой способ, чтобы имитировать связывание функции к экземпляру класса, используя декораторы:
def binder (function, instance):
copy_of_function = type (function) (function.func_code, {})
copy_of_function.__bind_to__ = instance
def bound_function (*args, **kwargs):
return copy_of_function (copy_of_function.__bind_to__, *args, **kwargs)
return bound_function
class SupaClass (object):
def __init__ (self):
self.supaAttribute = 42
def new_method (self):
print self.supaAttribute
supaInstance = SupaClass ()
supaInstance.supMethod = binder (new_method, supaInstance)
otherInstance = SupaClass ()
otherInstance.supaAttribute = 72
otherInstance.supMethod = binder (new_method, otherInstance)
otherInstance.supMethod ()
supaInstance.supMethod ()
Там, когда вы передаете функцию и экземпляр связующего декоратор, он будет создавать новую функцию, с тем же кодом объекта , как и первый. Затем, данный экземпляр класса хранится в атрибуте вновь созданной функции. Декоратора возвращают (третью) вызывающую функцию автоматически скопированную функцию, давая экземпляр в качестве первого параметра.
В заключении вы получаете функцию , имитируя это привязкой к экземпляру класса. Позволить исходную функцию без изменений.
from types import MethodType
def method(self):
print 'hi!'
setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) )
При этом, вы можете использовать указатель собственного
Я не знаю синтаксис Python, но я знаю, что рубин может это сделать, и это довольно тривиально. Допустим, вы хотите добавить метод массив, который печатает длину на стандартный вывод:
class Array
def print_length
puts length
end
end
Если вы не хотите, чтобы изменить весь класс, вы можете просто добавить метод к одному экземпляру массива, и никакие другие массивы будут иметь метод:
array = [1, 2, 3]
def array.print_length
puts length
end
Просто быть в курсе вопросов , связанных с использованием этой функции. Джефф Этвуд на самом деле об этом писал не так давно.