यहाँ यह ऐसा करने का एक ही रास्ता है के रूप में यह में पारित कर सकते हैं, एक नया foo कि समारोह internals हैकिंग से "सही काम करता है" का निर्माण। (जैसा कि @DSM द्वारा उल्लिखित है)। दुर्भाग्यवश हम foo
फ़ंक्शन और गड़बड़ी में अपने आंतरिक के साथ कूद नहीं सकते हैं, क्योंकि उन्हें अधिकतर केवल पढ़ने के लिए चिह्नित किया जाता है, इसलिए हमें जो करना है वह उस प्रतिलिपि को संशोधित करता है जिसे हम हाथ से बनाते हैं।
# Here's the original function
def foo():
def bar():
print(" In bar orig")
def baz():
print(" Calling bar from baz")
bar()
print("Foo calling bar:")
bar()
print("Foo calling baz:")
baz()
# Here's using it
foo()
# Now lets override the bar function
import types
# This is our replacement function
def my_bar():
print(" Woo hoo I'm the bar override")
# This creates a new code object used by our new foo function
# based on the old foo functions code object.
foocode = types.CodeType(
foo.func_code.co_argcount,
foo.func_code.co_nlocals,
foo.func_code.co_stacksize,
foo.func_code.co_flags,
foo.func_code.co_code,
# This tuple is a new version of foo.func_code.co_consts
# NOTE: Don't get this wrong or you will crash python.
(
foo.func_code.co_consts[0],
my_bar.func_code,
foo.func_code.co_consts[2],
foo.func_code.co_consts[3],
foo.func_code.co_consts[4]
),
foo.func_code.co_names,
foo.func_code.co_varnames,
foo.func_code.co_filename,
foo.func_code.co_name,
foo.func_code.co_firstlineno,
foo.func_code.co_lnotab,
foo.func_code.co_freevars,
foo.func_code.co_cellvars)
# This is the new function we're replacing foo with
# using our new code.
foo = types.FunctionType(foocode , {})
# Now use it
foo()
मुझे पूरा यकीन है कि यह सभी मामलों को पकड़ने वाला नहीं है।
- विशाल तर्क सूची CodeType को पारित किया जा रहा
- : लेकिन यह
बदसूरत बिट्स है कि कुछ साफ कर रहे हैं के साथ कर सकता (एक पुराने अजगर 2.5.1 पर मेरे लिए) उदाहरण के लिए काम करता है बदसूरत tuple co_consts
से केवल एक सदस्य ओवरराइडिंग से बनाया गया। सभी जानकारी को बदलने के लिए co_consts में है - ताकि एक स्मार्ट फ़ंक्शन ऐसा कर सके। मैंने print(foo.func_code.co_consts)
का उपयोग करके हाथों से आंतरिक में खोद दिया।
आप दुभाषिया आदेश help(types.CodeType)
का उपयोग करके CodeType
और FunctionType
बारे में कुछ जानकारी पा सकते हैं।
अद्यतन: मैंने सोचा कि यह बहुत बदसूरत था इसलिए मैंने इसे सुंदर बनाने के लिए एक सहायक कार्य बनाया। सहायक के साथ आप लिख सकते हैं:
# Returns a copy of original_fn with its internal function
# called name replaced with new_fn.
def monkey_patch_fn(original_fn, name, new_fn):
#Little helper function to pick out the correct constant
def fix_consts(x):
if x==None: return None
try:
if x.co_name == name:
return new_fn.func_code
except AttributeError, e:
pass
return x
original_code = original_fn.func_code
new_consts = tuple(map(fix_consts, original_code.co_consts))
code_type_args = [
"co_argcount", "co_nlocals", "co_stacksize", "co_flags", "co_code",
"co_consts", "co_names", "co_varnames", "co_filename", "co_name",
"co_firstlineno", "co_lnotab", "co_freevars", "co_cellvars" ]
new_code = types.CodeType(
*[ (getattr(original_code,x) if x!="co_consts" else new_consts)
for x in code_type_args ])
return types.FunctionType(new_code, {})
'bar' कहाँ प्रयोग किया जाता है:
यहाँ
monkey_patch_fn
के कार्यान्वयन है? क्या यह बाद के कार्यों में उपयोग किया जाता है (जैसे 'बाज़'?) आप * उन मामलों में इसे बदलना चाहते हैं, है ना? –बिल्कुल। ऐसा करने का कोई तरीका? – Paolo
आप फ़ंक्शन के विभिन्न आंतरिक विवरणों तक पहुंच सकते हैं, क्योंकि वे केवल ऑब्जेक्ट्स हैं। अधिक जानने के लिए डीआईआर फ़ंक्शन और भाषा संदर्भ का उपयोग करें। – Marcin