Как зайти в Даркнет?!
25th January, 01:11
8
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
899
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
952
0
Очень долго работает Update запрос Oracle
27th January, 09:58
916
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
907
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
942
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1727
0
период по дням
25th October, 10:44
3957
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3722
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4614
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4382
0
Помогите пожалуйста решить задачи
24th November, 23:53
6088
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4352
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4400
0
Метода Крамера С++
23rd October, 11:55
4309
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2599
0
Добавление метода к существующему экземпляру объекта
Я читал, что можно добавить метод к существующему объекту (т. е. не в определении класса) в 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>>
>>>
Привязанные методы были "bound" (как описательные) к экземпляру, и этот экземпляр будет передаваться в качестве первого аргумента при каждом вызове метода.
Вызываемые объекты, являющиеся атрибутами класса (в отличие от экземпляра), по-прежнему не связаны, поэтому вы можете изменять определение класса в любое время:
>>> 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 в модуле types :
>>> 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() .
Я думаю, что предоставление возвращаемого значения может заставить человека поверить, что патч возвращает новый объект, который не является истинным - он изменяет входящий объект. Вероятно, это может способствовать более дисциплинированному использованию обезьяньей охоты.
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 2 - этот ответ должен отлично работать в Python 2 и 3. Если вы пишете только Python 3 , Вы можете оставить явное наследование от object, но в противном случае код должен оставаться тем же самым.
Добавление метода к существующему экземпляру объекта
Я читал, что можно добавить метод к существующему объекту (например, не в определении класса) в 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)
Метод nought (0) - используйте метод дескриптора, __get__
Точечные поиски функций вызывают метод __get__ функции с экземпляром, привязывая объект к методу и таким образом создавая "bound method."
foo.sample_method = sample_method.__get__(foo)
а теперь ... :
>>> foo.sample_method(1,2)
3
Способ первый-types.MethodType
Во-первых, импортируйте типы, из которых мы получим конструктор метода:
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
Метод третий: functools.partial
Частичная функция применяет первый аргумент(ы) к функции (и необязательно аргументы ключевых слов), а затем может быть вызвана с остальными аргументами (и переопределяющими аргументами ключевых слов). Таким образом:
>>> 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>
Итак, m() каким-то образом становится несвязанным методом A . Но так ли это на самом деле?
In [5]: A.__dict__['m']
Out[5]: <function m at 0xa66b8b4>
Получается, что m() -это всего лишь функция, ссылка на которую добавляется в словарь класса - никакой магии тут нет. Тогда почему A.m дает нам несвязанный метод? Это потому, что точка не переводится в простой поиск по словарю. Это де-факто вызов A.__class__.__getattribute__(A, 'm'):
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
Теперь я не совсем понимаю, почему последняя строка напечатана дважды, но все равно ясно, что там происходит.
Теперь, что делает default _ _ getattribute__, так это проверяет, является ли атрибут так называемым дескриптором или нет, т. е. реализует ли он специальный метод __get__. Если он реализует этот метод,то возвращается результат вызова этого метода__ get__. Возвращаясь к первой версии нашего класса А, вот что мы имеем:
In [28]: A.__dict__['m'].__get__(None, A)
Out[28]: <unbound method A.m>
И поскольку функции Python реализуют протокол дескриптора, если они вызываются от имени объекта,они связывают себя с этим объектом в своем методе__ get__.
Итак, как добавить метод к существующему объекту? Предполагая, что вы не возражаете против исправления класса, это так же просто, как:
B.m = m
Затем B.m "becomes" несвязанный метод, благодаря магии дескриптора.
А если вы хотите добавить метод только к одному объекту, то вам придется эмулировать механизм самостоятельно, используя 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 monkey patching обычно работает путем перезаписи сигнатуры класса или функции своей собственной. Ниже приведен пример из Zope Wiki :
from SomeOtherProduct.SomeModule import SomeClass
def speak(self):
return "ook ook eee eee eee!"
SomeClass.speak = 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>
Один:
>>> 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>>
Два:
>>> 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>>
Полезные ссылки:
Модель данных-вызывающие дескрипторы
Дескриптор HowTo руководство-вызов дескрипторов
Консолидация ответов Джейсона Пратта и сообщества wiki, с учетом результатов различных методов привязки:
Особенно обратите внимание на то , как работает добавление функции привязки в качестве метода класса, но область ссылки неверна.
#!/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>>
Вам, ребята, действительно стоит посмотреть на запретный плод , это библиотека python, которая обеспечивает поддержку класса monkey patching ANY python, даже строк.
Это фактически аддон к ответу "Jason Pratt"
Хотя ответ Jasons работает, он работает только в том случае, если кто-то хочет добавить функцию в класс. Это не сработало для меня, когда я попытался перезагрузить уже существующий метод из файла исходного кода .py.
Мне потребовалась целая вечность, чтобы найти обходной путь, но трюк кажется простым... 1.st импорт кода из файла исходного кода 2.nd принудительная перезарядка 3.rd используйте types.FunctionType(...) для преобразования импортированного и связанного метода в функцию вы также можете передать текущие глобальные переменные, так как перегруженный метод будет находиться в другом пространстве имен 4.th теперь вы можете продолжить, как предложил "Jason 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
То, что написал Джейсон Пратт, совершенно верно.
>>> 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 не считает b() чем-то отличным от a(). В Python все методы - это просто переменные, которые случайно оказываются функциями.
Если это может быть чем-то полезным, я недавно выпустил библиотеку Python под названием Gorilla, чтобы сделать процесс исправления обезьян более удобным.
Использование функции needle() для исправления модуля с именем guineapig происходит следующим образом:
import gorilla
import guineapig
@gorilla.patch(guineapig)
def needle():
print("awesome")
Но он также заботится о более интересных случаях использования, как показано в FAQ из документации .
Код доступен на GitHub .
Этот вопрос был открыт много лет назад, но есть простой способ имитировать привязку функции к экземпляру класса с помощью декораторов:
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 ()
Там, когда вы передадите функцию и экземпляр декоратору binder, он создаст новую функцию с тем же объектом кода, что и первый. Затем данный экземпляр класса сохраняется в атрибуте вновь созданной функции. Декоратор возвращает (третью) функцию, Автоматически вызывающую скопированную функцию, предоставляя экземпляр в качестве первого параметра.
В заключение вы получаете функцию, имитирующую ее привязку к экземпляру класса. Пусть исходная функция остается неизменной.
Я нахожу странным, что никто не упомянул, что все перечисленные выше методы создают циклическую ссылку между добавленным методом и экземпляром, заставляя объект быть постоянным до сборки мусора. Был старый трюк добавление дескриптора путем расширения класса объекта:
def addmethod(obj, name, func):
klass = obj.__class__
subclass = type(klass.__name__, (klass,), {})
setattr(subclass, name, func)
obj.__class__ = subclass