La prima cosa è ottenere i nomi correttamente:
>>> def increment(obj):
... obj.count += 1
...
>>> class A(object):
... def __init__(self):
... self.count = 0
...
>>> o = A()
>>> o.__init__
<bound method A.__init__ of <__main__.A object at 0x0000000002766EF0>>
>>> increment
<function increment at 0x00000000027797C8>
nomi propri sono Così funzioni e metodi legati. Ora si può guardare per come Bind an Unbound Method e probabilmente finirà per leggere su descriptors:
In generale, un descrittore è un attributo oggetto con "vincolante comportamento", uno il cui accesso attributo è stata sostituita con metodi nel protocollo descrittore. Questi metodi sono __get__
, __set__
e __delete__
. Se uno di questi metodi è definito per un oggetto, si dice che sia un descrittore.
Si può facilmente trasformare la funzione per il metodo da solo utilizzando invocazione diverso di __get__
>>> increment.__get__(None, type(None))
<function increment at 0x00000000027797C8>
>>> increment.__get__(o, type(o))
<bound method A.increment of <__main__.A object at 0x00000000027669B0>>
e funziona come un fascino:
>>> o = A()
>>> increment.__get__(None, type(None))(o)
>>> o.count
1
>>> increment.__get__(o, type(o))()
>>> o.count
2
Si può facilmente aggiungere questi metodi di recente delimitate agli oggetti:
def increment(obj):
obj.count += 1
def addition(obj, number):
obj.count += number
class A(object):
def __init__(self):
self.count = 0
o = A()
o.inc = increment.__get__(o)
o.add = addition.__get__(o)
print(o.count) # 0
o.inc()
print(o.count) # 1
o.add(5)
print(o.count) # 6
Oppure creare il proprio descrittore che vi permette di convertire funzione-metodo vincolato:
class BoundMethod(object):
def __init__(self, function):
self.function = function
def __get__(self, obj, objtype=None):
print('Getting', obj, objtype)
return self.function.__get__(obj, objtype)
class B(object):
def __init__(self):
self.count = 0
inc = BoundMethod(increment)
add = BoundMethod(addition)
o = B()
print(o.count) # 0
o.inc()
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 1
o.add(5)
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 6
E si può anche vedere che questo è ben coerente con function/bound method principles:
Classe i dizionari memorizzano i metodi come funzioni. In una definizione di classe, i metodi vengono scritti utilizzando def e lambda, i soliti strumenti per creare funzioni. L'unica differenza rispetto alle normali funzioni è che il primo argomento è riservato all'istanza dell'oggetto. Con la convenzione Python, il riferimento all'istanza viene chiamato self ma può essere chiamato questo o qualsiasi altro nome di variabile.
Per supportare le chiamate di metodo, le funzioni includono il metodo __get__()
per i metodi di associazione durante l'accesso agli attributi. Ciò significa che tutte le funzioni sono descrittori non di dati che restituiscono metodi associati o non associati a seconda che siano invocati da un oggetto o una classe.
E funzioni diventa metodo vincolato durante l'inizializzazione esempio:
>>> B.add
# Getting None <class '__main__.B'>
<function addition at 0x00000000025859C8>
>>> o.add
# Getting <__main__.B object at 0x00000000030B1128> <class '__main__.B'>
<bound method B.addition of <__main__.B object at 0x00000000030B1128>>
Ho avuto questo problema cercando di costruire una classe Heapq utilizzando il brutto 'modulo di heapq'. La tua soluzione è buona. Può essere fatto in una riga, ma ha la stessa efficienza: 'def method_wraper (f): restituisce functools.wraps (f) (lambda * a, ** kw: f (* a, ** kw))' – JBernardo
. .. Interessante, l'assegnazione sembra funzionare correttamente se la funzione è definita all'interno dello stesso modulo (metodo non associato che viene assegnato a una classe e associato a un'istanza). Quindi è solo un problema con le estensioni C, o con funzioni in diversi moduli? Ad ogni modo, potresti voler controllare http://stackoverflow.com/questions/7490879/python3-bind-method-to-class-instance-with-get-it-works-but-why, che potrebbe aiutarti un po ' anche. – JAB
Inoltre, http://docs.python.org/py3k/howto/descriptor.html#functions-and-methods "l'effettiva implementazione C di PyMethod_Type in Objects/classobject.c è un singolo oggetto con due diverse rappresentazioni a seconda che il campo im_self è impostato o è NULL (l'equivalente C di None). " Il che fa sembrare che questo problema non si verifichi affatto, a meno che Python in qualche modo non aggiorni quel campo direttamente per i metodi di un oggetto durante l'istanziazione dell'oggetto. – JAB