를 추가하는 방법에는 기존의 객체를 인스턴스
-
08-06-2019 - |
문제
내가 읽는 것이 가능하다 추가하는 방법 기존 물체(즉,클래스에 정의)에서 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'
다른 팁
모듈 뉴 은 사용되지 않기 때문 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()모든 다른다().파이썬에서 모든 방법은 변수가 될 수 있는 기능입니다.
이 질문을 열었 년 전,하지만,거기에는 쉬운 방법을 시뮬레이션에 바인딩하는 기능을 클래스의 인스턴스를 사용하여 장식:
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)) )
이와 함께,사용할 수 있습니다 셀프 포인터