2013-01-04 7 views
9

Potrzebuję klasy odpowiedzi żądania monkeypatch (wersja 1.0.4, aktualna na podstawie tego pytania), aby dodać dodatkowe metody.Python monkey transpching

mam ten kod:

import requests 

class Response(requests.models.Response): 
    def hmm(self): 
     return 'ok' 

requests.models.Response = Response 

r = requests.get('http://bbc.co.uk') 

print r 

on zawiedzie, gdy oryginalny Response nazywa super() - https://github.com/kennethreitz/requests/blob/master/requests/models.py#L391

Myślę, że to dlatego, że pogubi, bo zastąpiły klasę, czuję jak robię coś głupiego, jakieś pomysły? Z góry dziękuję.

+0

w [2]: wnioski .__ version__ Out [2]: '1.0.4' Czy to prawda również dla Ciebie? Ten kod pracował dla mnie ze starszą wersją żądań. – user964375

+0

Nie udało się ustalić, jaki błąd? – Eloff

+0

Plik "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/models.py", wiersz 391, w __init__ super (Response, self) .__ init __() TypeError: super (type, obj): obj musi być instancją lub podtypem typu – user964375

Odpowiedz

12

Byłbyś lepiej po prostu dodając swoją funkcję bezpośrednio do klasy:

def hmm(self): 
    return 'ok' 
requests.models.Response.hmm = hmm 

to działa dobrze:

>>> import requests 
>>> def hmm(self): 
...  return 'ok' 
... 
>>> requests.models.Response.hmm = hmm 
>>> r = requests.get('http://bbc.co.uk') 
>>> print r 
<Response [200]> 
>>> r.hmm() 
'ok' 
>>> requests.__version__ 
'1.0.4' 
+0

Wiem, że mamy Pythonistas __hate__ OOP, ale co powiesz na podklasę? – tenfishsticks

+0

@tenfishsticks: Wciąż będziesz musiał zastąpić klasę 'Response' tą podklasą, ponieważ API' requests' zwróci instancje tej klasy. Aby dodać metodę, prostszym rozwiązaniem jest dodanie metody do istniejącej klasy. –

4

Nie sądzę można małpa-łata, że ​​typ tak. Podczas importowania requests, wszystkie modułysą inicjowane. A ponieważ cała biblioteka używa wielokrotnie biblioteki from xy import Request, będzie ona zawierała dokładne odniesienie do rzeczywistego typu. Dopiero potem zastępujesz typ odpowiedzi w module modeli, więc wpływa to tylko na kolejne importowanie.

Jeśli nie przejdziesz przez wszystkie moduły i ręcznie zastąpisz odniesienie do odpowiedzi swoim nowym typem, nadal będą one używać oryginalnego, co sprawi, że twój patch będzie bezużyteczny.

Zamiast tego powinieneś zachować oryginalny typ, ale rozwinąć go bezpośrednio, jak sugerował Martijn.

+0

Dziękuję. Użyję inspect.getmembers, aby pobrać wszystkie metody z mojej klasy i przypisać je do oryginalnej klasy. Nieco mniej elegancki, ale zadziała. – user964375

1

Wystarczy szybkie ustalenie za pomocą setattr, ale to trochę brzydkie (ale semantycznie równoważne @Martijn answer):

def hmm(self): 
    return 'OK - %s' % self.status_code 

setattr(requests.models.Response, 'hmm', hmm) 

r = requests.get('http://bbc.co.uk') 
print r.hmm() 
# prints 
# OK - 200