2012-04-06 11 views
11

के रूप में एक इस सवाल का ऊपर का पालन करें: Is there an easy way to pickle a python function (or otherwise serialize its code)?अपनी निर्भरताओं के साथ एक अजगर समारोह कैसे उठाया जाए?

मैं ऊपर पोस्ट से इस गोली का एक उदाहरण देखना चाहेंगे:

"यदि समारोह संदर्भ वैश्विक (आयातित मॉड्यूल, अन्य कार्यों आदि सहित) कि आपको लेने की जरूरत है, आपको इन्हें क्रमबद्ध करने की आवश्यकता होगी, या उन्हें दूरस्थ पक्ष पर फिर से बनाना होगा। मेरा उदाहरण सिर्फ इसे दूरस्थ प्रक्रिया का वैश्विक नामस्थान देता है। "

file = open('/tmp/f2.txt', 'r') 
code = marshal.loads(file.read()) 
func2 = types.FunctionType(code, globals(), "some_func_name"); 
func2('blah') 

इस में जो परिणाम:

def g(self,blah): 
    print blah 

def f(self): 
    for i in range(1,5): 
     print 'some function f' 
     g('some string used by g') 

data = marshal.dumps(f.func_code) 

file = open('/tmp/f2.txt', 'w') 
file.write(data) 

फिर एक ताजा अजगर उदाहरण मुझे क्या करना शुरू कर:

मैं एक साधारण परीक्षण के लिए जा रहा है, जहां मैं मार्शल का उपयोग कर एक फाइल करने के लिए एक कार्यों बाइट कोड लिख रहा हूँ है ए:

NameError: global name 'g' is not defined 

यह जी सहित विभिन्न दृष्टिकोणों से स्वतंत्र है। मैंने मूल रूप से एफ के रूप में जी भेजने के लिए एक ही दृष्टिकोण की कोशिश की है लेकिन एफ अभी भी जी नहीं देख सकता है। मैं ग्लोबल नेमस्पेस में जी कैसे प्राप्त करूं ताकि इसे प्राप्त करने की प्रक्रिया में एफ द्वारा उपयोग किया जा सके?

किसी ने भी इसे करने के उदाहरण के रूप में पाइरो को देखने की सिफारिश की। मैंने पहले ही डिस्को परियोजना में संबंधित कोड को समझने की कोशिश करने का प्रयास किया है। मैंने अपनी डीपीकल कक्षा ली और सफलता के बिना एक स्टैंडअलोन ऐप में अपने डिस्को/परीक्षण/test_pickle.py कार्यक्षमता को फिर से बनाने की कोशिश की। मेरे प्रयोग में डंप कॉल के साथ फ़ंक्शन मार्शलिंग करने में समस्याएं थीं। वैसे भी, शायद एक पाइरो अन्वेषण अगला है।

संक्षेप में, मूलभूत कार्यक्षमता मैं बाद में तार पर एक विधि भेजने में सक्षम हूं और इसके साथ भेजे गए सभी मूल "कार्यक्षेत्र" विधियों (जैसे जी) है। जवाब से परिवर्तन के साथ

उदाहरण:

कार्य function_writer:

import marshal, types 

def g(blah): 
    print blah 


def f(): 
    for i in range(1,5): 
     print 'some function f' 
     g('blah string used by g') 


f_data = marshal.dumps(f.func_code) 
g_data = marshal.dumps(g.func_code); 

f_file = open('/tmp/f.txt', 'w') 
f_file.write(f_data) 

g_file = open('/tmp/g.txt', 'w') 
g_file.write(g_data) 

कार्य function_reader:

import marshal, types 

f_file = open('/tmp/f.txt', 'r') 
g_file = open('/tmp/g.txt', 'r') 

f_code = marshal.loads(f_file.read()) 
g_code = marshal.loads(g_file.read()) 

f = types.FunctionType(f_code, globals(), 'f'); 
g = types.FunctionType(g_code, globals(), 'g'); 

f() 

उत्तर

3

मैं मूल रूप से के रूप में च लेकिन अधिक ग्राम भेजने के लिए एक ही दृष्टिकोण की कोशिश की है एफ अभी भी जी नहीं देख सकता है। मैं ग्लोबल नेमस्पेस में जी कैसे प्राप्त करूं ताकि इसे प्राप्त करने की प्रक्रिया में एफ द्वारा उपयोग किया जा सके?

इसे वैश्विक नाम g पर असाइन करें। (मुझे लगता है कि आप ffunc2 को f के बजाय असाइन कर रहे हैं। यदि आप g के साथ ऐसा कुछ कर रहे हैं, तो यह स्पष्ट है कि fg नहीं मिल सकता है। याद रखें कि नाम समाधान रनटाइम पर होता है - g नहीं देखा जाता है जब तक आप f पर कॉल नहीं करते हैं।)

बेशक, मैं अनुमान लगा रहा हूं क्योंकि आपने ऐसा करने के लिए उपयोग किए जा रहे कोड को नहीं दिखाया है।

उन कार्यों के लिए वैश्विक नामस्थान के लिए उपयोग करने के लिए एक अलग शब्दकोश बनाने के लिए सबसे अच्छा हो सकता है जो आप अनपिकलिंग कर रहे हैं - एक सैंडबॉक्स। इस तरह उनके सभी वैश्विक चर मॉड्यूल से अलग होंगे जो आप इसे कर रहे हैं।तो अगर आप कुछ इस तरह कर सकते हैं:

sandbox = {} 

with open("functions.pickle", "rb") as funcfile: 
    while True: 
     try: 
      code = marshal.load(funcfile) 
     except EOFError: 
      break 
     sandbox[code.co_name] = types.FunctionType(code, sandbox, code.co_name) 

इस उदाहरण में मुझे लगता है कि आप एक के बाद एक फ़ाइल, एक में अपने सभी कार्यों से कोड वस्तुओं डाल दिया, और जब उन में पढ़ना, मैं कोड ऑब्जेक्ट का नाम और इसे फ़ंक्शन ऑब्जेक्ट के नाम और उस नाम के आधार के रूप में उपयोग करें जिसके अंतर्गत यह सैंडबॉक्स शब्दकोश में संग्रहीत है।

unpickled कार्यों के अंदर, सैंडबॉक्स शब्दकोश उनके globals() और इतने f() अंदर, gsandbox["g"] से अपने मूल्य हो जाता है। f पर कॉल करने के लिए: sandbox["f"]("blah")

+0

ओह वाह, मुझे एहसास नहीं हुआ कि निर्दिष्ट संदर्भ में कोई फर्क पड़ता है! धन्यवाद! काम कोड पोस्ट करेंगे। –

+1

@RyanR। : कुछ कोड खुद को पोस्ट किया। – kindall

+0

ग्रेट, मुझे सैंडबॉक्स पसंद है। स्वचालित रूप से सभी कार्य निर्भरताओं को स्वचालित रूप से क्रमबद्ध करने के लिए अगले ऑटो का पता लगाना चाहते हैं। डिस्को modutil.find_modules विधि क्या करता है की तरह सॉर्ट करें। मदद की सराहना करें। –

2

प्रत्येक मॉड्यूल के अपने ग्लोबल्स हैं, कोई सार्वभौमिक ग्लोबल्स नहीं हैं। हम कुछ मॉड्यूल में पुनर्निर्मित कार्यों को "प्रत्यारोपित" कर सकते हैं और इसे सामान्य मॉड्यूल की तरह उपयोग कर सकते हैं।

- बचाने -

import marshal 
def f(x): 
    return x + 1 
def g(x): 
    return f(x) ** 2 
funcfile = open("functions.pickle", "wb") 
marshal.dump(f.func_code, funcfile) 
marshal.dump(g.func_code, funcfile) 
funcfile.close() 

- बहाल -

import marshal 
import types 
open('sandbox.py', 'w').write('') # create an empty module 'sandbox' 
import sandbox 
with open("functions.pickle", "rb") as funcfile: 
    while True: 
     try: 
      code = marshal.load(funcfile) 
     except EOFError: 
      break 
     func = types.FunctionType(code, sandbox.__dict__, code.co_name) 
     setattr(sandbox, code.co_name, func) # or sandbox.f = ... if the name is fixed 
assert sandbox.g(3) == 16 # f(3) ** 2 
# it is possible import them from other modules 
from sandbox import g 

संपादित:
तुम भी कर सकते हैं आयात कुछ मॉड्यूल .e.g।

sandbox.sys = __import__('sys') 

या एक ही:

exec 'import sys' in sandbox.__dict__ 
assert 'sys' in sandbox, 'Verify imported into sandbox' 

आपका मूल कोड काम करेगा अगर आप इसे IPython इंटरैक्टिव में लेकिन एक अजगर कार्यक्रम में या नहीं है बाहर से "सैंडबॉक्स" नाम स्थान के लिए "sys" सामान्य पायथन इंटरैक्टिव !!!

आईपीथॉन कुछ अजीब नेमस्पेस का उपयोग करता है जो sys.modules से किसी भी मॉड्यूल के dict नहीं है। सामान्य पायथन या कोई भी मुख्य प्रोग्राम ग्लोबल्स() के रूप में sys.modules['__main__'].__dict__ का उपयोग करता है। कोई भी मॉड्यूल that_module.__dict__ का उपयोग करता है जो ठीक है, केवल ipython इंटरैक्टिव एक समस्या है।

+0

धन्यवाद! +1 इसके बारे में उत्सुक था। –

+1

@RyanR। सामान्य पिथन का उपयोग ipython नहीं होने पर आपका मूल कोड काम करता है। – hynekcer

+0

'आयात x नहीं है; x.method() 'प्रकार रिमोट स्क्रिप्ट में एक समस्या का उपयोग करता है? जैसा कि: http: //stackoverflow.com/questions/10099326/how-to-do-an-embedded-python- मॉड्यूल-for-remote-sandbox-execution –

16

बादल पैकेज करता है - बस 'क्लाउड स्थापित पिप' और फिर:

import cloud, pickle 
def foo(x): 
    return x*3 
def bar(z): 
    return foo(z)+1 
x = cloud.serialization.cloudpickle.dumps(bar) 
del foo 
del bar 
f = pickle.loads(x) 
print f(3) # displays "10" 

दूसरे शब्दों में, बस cloudpickle.dump() या cloudpickle.dumps फोन() उसी तरह आप चाहते अचार का उपयोग करें। *, फिर बाद में देशी pickle.load() या pickle.loads() को thaw का उपयोग करें।

पिक्लोउड ने एलजीपीएल के तहत 'क्लाउड' पायथन पैकेज जारी किया, और अन्य ओपन-सोर्स प्रोजेक्ट पहले ही इसका उपयोग कर रहे हैं (कुछ देखने के लिए "cloudpickle.py" के लिए Google)। Picloud.com पर प्रलेखन आपको यह विचार देता है कि यह कोड कितना शक्तिशाली है, और क्यों उन्हें सामान्य उद्देश्य कोड पिकलिंग कार्य करने के प्रयास को प्रोत्साहित करने का प्रोत्साहन मिला - उनका पूरा व्यवसाय इसके चारों ओर बनाया गया है।

साथ
cpu_intensive_function(some, args) 

:

cloud.call(cpu_intensive_function, some, args) 

उत्तरार्द्ध का उपयोग करता है किसी भी निर्भर कोड ऊपर अचार को cloudpickle विचार यह है कि अगर आप cpu_intensive_function() है और अमेज़न के EC2 ग्रिड पर उसे चलाना चाहते हैं, तो आप सिर्फ की जगह है और डेटा, इसे EC2 पर भेजता है, इसे चलाता है, और जब आप क्लाउड.result() को कॉल करते हैं तो परिणाम आपको वापस कर देते हैं।(मिलीसेकंद वृद्धि में पिक्लोउड बिल, यह बिल्ली के रूप में सस्ता है, और मैं इसे मॉन्टे कार्लो सिमुलेशन और वित्तीय समय श्रृंखला विश्लेषण के लिए हर समय उपयोग करता हूं, जब मुझे सैकड़ों सीपीयू कोर की आवश्यकता होती है तो प्रत्येक कुछ सेकंड के लिए। मैं पर्याप्त अच्छा नहीं कह सकता इसके बारे में चीजें और मैं वहां भी काम नहीं करता हूं।)

+0

धन्यवाद श्रीमान :) मैं डिल के साथ संघर्ष कर रहा हूं कुछ घंटों के लिए, लेकिन क्लाउड सीधे आगे बढ़ता है मुझे विश्वास है कि यह स्वीकार्य उत्तर – NiCU

+2

होना चाहिए क्योंकि मूल PiCloud क्लाइंट एसडीके अब बनाए रखा नहीं गया है, क्लाउडपीकल सुविधाओं को बनाए रखने के लिए बस एक नई परियोजना शुरू की गई थी: http: // github.com/cloudpipe/cloudpickle: 'pip install cloudpickle' – ogrisel

+1

@stevegt: आपका उदाहरण सही ढंग से फ़ंक्शन में निर्मित सहेजने के लिए प्रतीत नहीं होता है :) – user2284570

3

__main__ आयात करके और उस मॉड्यूल में उपलब्ध विधियों का उपयोग करके आप वैश्विक वस्तुओं पर बेहतर संभाल सकते हैं। यह है कि dill पाइथन में लगभग कुछ भी क्रमबद्ध करने के लिए करता है। असल में, जब डिल एक इंटरैक्टिव रूप से परिभाषित फ़ंक्शन को क्रमबद्ध करता है, तो यह __main__ पर क्रमशः __main__ को वैध मॉड्यूल बनाता है जो कुछ पैरालाइजेशन और deserialization पक्ष पर कुछ नाम मैंगलिंग का उपयोग करता है।

>>> import dill 
>>> 
>>> def bar(x): 
... return foo(x) + x 
... 
>>> def foo(x): 
... return x**2 
... 
>>> bar(3) 
12 
>>> 
>>> _bar = dill.loads(dill.dumps(bar)) 
>>> _bar(3) 
12 

वास्तव में, डिल पंजीकृत करता है यह pickle रजिस्ट्री में प्रकार है, इसलिए यदि आप pickle का उपयोग करता है कुछ ब्लैक बॉक्स कोड है और आप वास्तव में इसे संपादित नहीं कर सकते, तो बस का आयात डिल जादुई यह monkeypatching के बिना काम कर सकते हैं तृतीय पक्ष कोड।

या, यदि आप पूरे दुभाषिया सत्र को "पायथन छवि" के रूप में भेजना चाहते हैं, तो डिल भी ऐसा कर सकता है।

>>> # continuing from above 
>>> dill.dump_session('foobar.pkl') 
>>> 
>>> ^D 
[email protected]>$ python 
Python 2.7.5 (default, Sep 30 2013, 20:15:49) 
[GCC 4.2.1 (Apple Inc. build 5566)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dill 
>>> dill.load_session('foobar.pkl') 
>>> _bar(3) 
12 

आप आसानी से किसी अन्य कंप्यूटर से ssh भर में छवि भेज सकते हैं और शुरू जहां वहाँ बंद जब तक वहाँ के रूप में अचार के संस्करण संगतता और अजगर बदल रहा है और चीजों को स्थापित किया जा रहा बारे में सामान्य चेतावनियां छोड़ सकते हैं।

+0

लेकिन फिर यदि कोई पाइथन प्रोग्राम foo और bar और pickles bar को फ़ाइल में उपयोग करता है (उपयोग कर रहा है डिल), और एक और पायथन प्रोग्राम मिक्स्ड फ़ाइल को _bar में लोड करता है और _bar (3) को कॉल करता है, यह foo को अपरिभाषित होने के साथ त्रुटियों से बाहर करता है। यह उस मामले में क्यों काम नहीं करता है? –

+0

मुझे यकीन नहीं है कि मैं देख रहा हूं कि आप वास्तव में क्या पूछ रहे हैं, क्या आप शायद अधिक जानकारी प्रदान कर सकते हैं (या तो अपने स्वयं के प्रश्न में, या 'डिल' के लिए github मुद्दों पृष्ठ पर)? –

+0

मैंने यहां एक नया मुद्दा खोला: https://github.com/uqfoundation/dill/issues/176 –

0

डिल (अन्य अचार प्रकारों, क्लाउडपिकल ​​इत्यादि के साथ) काम करने लगते हैं जब फ़ंक्शन (ओं) मसालेदार होते हैं तो पिकलिंग के साथ मुख्य मॉड्यूल में होते हैं। यदि आप किसी अन्य मॉड्यूल से फ़ंक्शन चुन रहे हैं, तो अनपिक्लिंग होने पर मॉड्यूल नाम मौजूद होना चाहिए। मुझे इस सीमा के चारों ओर एक रास्ता नहीं मिल रहा है।

+0

आप कर सकते हैं। देखें: http://stackoverflow.com/questions/26389981/serialize-a-python-function-with- निर्भरता –

संबंधित मुद्दे