문제

내가 읽는 것이 가능하다 추가하는 방법 기존 물체(즉,클래스에 정의)에서 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>>
>>>

바인딩 방법"바"(는 방법을 설명하)인스턴스,그리고 해당 인스턴스로 전달할 수 있는 첫 번째 인수할 때마다 메소드가 호출됩니다.

Callables 있는 클래스의 특성(반대하는 인스턴스)는 여전히적 분야에 기재된 사항 외에는 약속 안 하지만,그래서 당신은 수정할 수 있습니다 클래스 정의할 때마다:

>>> 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'

더 많은 정보를 찾을 수 있습니다에 대해 읽어 설명metaclass 프로그래밍.

다른 팁

모듈 은 사용되지 않기 때문 python2.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'>

서문-에 주 compatibility:다른 답변을 수 있습니다만 작품에서는 Python2-이 대답을 완벽하게 작동해야에서 잘 Python2and3.는 경우 쓰기 Python3 만,당신은 당신을 떠날 수도 있습 명시적으로 상속서 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)

방법을 폐하리라 하였으(0)사용 설명 방법 __get__

점 검색에 함수를 호출 __get__ 방법 함수의 인스턴스와 결합,개체의 방법을 따라 만들기"바인딩 방법입니다."

foo.sample_method = sample_method.__get__(foo)

지금:

>>> foo.sample_method(1,2)
3

방법 중 하나-유형입니다.MethodType

먼저,가져오기 유형에서는 우리는 것을 얻는 방법을 생성자:

import types

지금 우리가 추가하는 방법은 인스턴스입니다.이를 위해,우리가 필요 MethodType 에서 생성자 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.부분

부분적인 기능이 적용되는 첫 번째 인수(s)함수(선택적으로 키워드를 인수),그리고 나라와 나머지 인수(과 재정의하는 키워드를 인수).따라서:

>>> 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

지금하자,플레이에서 그만큼:

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 사전 등 없 마법입니다.그 이유 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

지금,나는 확실하지 않 밖으로 내 머리 위로 왜 마지막 줄은 인쇄 두 번 있지만,아직 그것은 맑은 무엇이 진행되고있다.

자,무엇을 기본__getattribute__가 확인된 경우 특성입니다 그래서 소위 설명 나지 않는,즉는 경우를 구현하는 특별한__얻__방법입니다.는 경우를 구현하는 방법은 무엇 후,반환의 결과를 호출하는__얻__방법입니다.로 돌아가 첫 번째 버전 A 클래스,이것은 우리가 무엇:

In [28]: A.__dict__['m'].__get__(None, A)
Out[28]: <unbound method A.m>

기 때문에 Python 기능을 구현하는 설명자로토콜,그들은 경우에 호출신의 개체,그들은 그들이 그 개체들__얻__방법입니다.

그래,그래서 어떻게 추가하는 방법 기존의가?당신이하지 않는 가정은 마음을 패치 등,그것은 간단하다:

B.m = m

다음 B.m "된다"는 약속 안함 방법 덕분에,설명자 마법입니다.

고 당신이 원하는 경우를 추가하는 방법을 하나의 개체,당신을 에뮬레이트 기계,자신을 사용하여 형식입니다.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'>

파이썬에서 원숭이가 패치를 표시하는 것은 일반적으로 덮어써서 클래스 또는 기능의 서명니다.아래 예에서 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>>

유용한 링크:
데이터 모델을 호출하는 설명
설명 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()

출력:

This is instance string

무엇을 찾고 계신가 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>

이 질문에 대한 비 Python 버전이 여기에 자바스크립트:

a.methodname = function () { console.log("Yay, a new method!") }

통합 Jason 프랫 그리고 커뮤니티 wiki 답변을 보는 것으로 결과는 다른 방법 binding:

특히 참고 어떻게 추가하는 바인딩 기능으로 클래스 메소드 , 지만,참조 범위가 잘못되었습니다.

#!/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 라이브러리 지원을 제공하는 원숭이가 패치 python 등에도,문자열입니다.

이것은 실제로는 애드온을의 대답은"제이슨 Pratt"

지만 Jasons 대답을 작품,그것은 경우에만 작동 하나하고 싶어하는 기능을 추가한 클래스입니다.그것은 작동하지 않았다 나를 위해 시도했을 때 다시는 이미 기존의 방법에서.py 소스 코드 파일이 있습니다.

그것은 내게 세에 대한 해결 방법을 찾아,하지만 속이 간단해 보이...1.st 가져오는 코드의 소스 코드에서 파일 2.nd 을 강제로드 3.rd 사용 유형입니다.FunctionType(...)로 변환하의 수입과에 바인딩하는 방법 기능 를 전달할 수도 있습니다에서 현재 전역 변수로드 방법을 것 다른 네임스페이스 4.th 지금 당신은 당신을 계속할 수 있으로 제안하여"제이슨 Pratt" 를 사용하는 유형입니다.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

어떤 제이슨 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 을 고려하지 않 b()모든 다른다().파이썬에서 모든 방법은 변수가 될 수 있는 기능입니다.

될 수 있는 경우,어떤 도움을 나는 최근에 발표했는 파이썬 라이브러리된 고릴라의 프로세스를 만드는 원숭이가 패치를 더 편리합니다.

를 사용하여 기능 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 ()

이,당신이 통과 할 때 기능 및 인스턴스 바인더의 장식,그것이 만들 새로운 기능과 같은 코드 개체가 처음으로 하나입니다.그런 다음,지정된 클래스의 인스턴스에 저장되는 특성의 새로 생성된 기능이다.식 반환(번째)함수를 호출하면 자동으로 복사 기능을 제공,인스턴스로 첫 번째 매개 변수입니다.

에서 결론을 얻는 기능을 시뮬레이션 그것은 바인딩하는 클래스의 인스턴스입니다.시키는 원래 기능을 변경되지 않습니다.

내가 찾는 것이 이상 아무도 언급된 모든 방법들을 통해 위에 나열된 생성주기에 참조 사이에 추가 방법 및 인스턴스를 일으키는 개체의 지속적인 것을 때까지 쓰레기 컬렉션입니다.이 있었는 오래된 속임수를 추가하는 설명자에 의해 확장 클래스의 객체:

def addmethod(obj, name, func):
    klass = obj.__class__
    subclass = type(klass.__name__, (klass,), {})
    setattr(subclass, name, func)
    obj.__class__ = subclass
from types import MethodType

def method(self):
   print 'hi!'


setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) )

이와 함께,사용할 수 있습니다 셀프 포인터

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top