অজগর ফাংশন বাছাই করার কোনও সহজ উপায় আছে (বা অন্যথায় এর কোডটি সিরিয়ালাইজ করা)?


103

আমি একটি নেটওয়ার্ক সংযোগ জুড়ে একটি ক্রিয়াকলাপ স্থানান্তর করার চেষ্টা করছি (asyncore ব্যবহার করে)। অজগর ফাংশনকে সিরিয়ালিয়াল করার কী সহজ উপায় আছে (এই ক্ষেত্রে, এটির অন্তত কোনও দিকই প্রভাব ফেলবে না) এই জাতীয় স্থানান্তরের জন্য?

আমি আদর্শভাবে এইগুলির মতো এক জোড়া ফাংশন রাখতে চাই:

def transmit(func):
    obj = pickle.dumps(func)
    [send obj across the network]

def receive():
    [receive obj from the network]
    func = pickle.loads(s)
    func()

এটি
আরএসটি-

উত্তর:


121

আপনি ফাংশনটি বাইকোডকে সিরিয়ালিয়াস করতে পারেন এবং তারপরে এটি কলারের উপরে পুনর্গঠন করতে পারেন। মার্শাল মডিউল serialise কোড বস্তু, যা পরে একটি ফাংশন মধ্যে reassembled যাবে ব্যবহার করা যাবে। অর্থাত:

import marshal
def foo(x): return x*x
code_string = marshal.dumps(foo.func_code)

তারপরে রিমোট প্রক্রিয়াতে (কোড_স্ট্রিং স্থানান্তর করার পরে):

import marshal, types

code = marshal.loads(code_string)
func = types.FunctionType(code, globals(), "some_func_name")

func(10)  # gives 100

কয়েকটি সতর্কতা:

  • মার্শালের ফর্ম্যাট (সেই বিষয়ে কোনও পাইথন বাইটকোড) বড় পাইথন সংস্করণগুলির মধ্যে তুলনীয় নাও হতে পারে।

  • কেবল সিপিথন বাস্তবায়নের জন্য কাজ করবে।

  • যদি ফাংশনটি গ্লোবালগুলি উল্লেখ করে (আমদানি করা মডিউলগুলি সহ অন্যান্য ফাংশন ইত্যাদির) যা আপনাকে বাছাই করতে হবে, আপনাকে এগুলিও সিরিয়াল করাতে হবে, বা সেগুলি দূরবর্তী দিকে পুনরায় তৈরি করতে হবে। আমার উদাহরণ কেবল এটিকে দূরবর্তী প্রক্রিয়াটির গ্লোবাল নেমস্পেস দেয়।

  • ক্লোজার বা জেনারেটর ফাংশনগুলির মতো আরও জটিল ক্ষেত্রে সমর্থন করার জন্য আপনার সম্ভবত আরও কিছু করা দরকার।


4
পাইথন 2.5 তে, "নতুন" মডিউলটি অবচয় করা হয়েছে। 'new.function' কে 'type.FunctionType' দ্বারা প্রতিস্থাপন করা উচিত, "আমদানির ধরণের" পরে, আমি বিশ্বাস করি।
এরিক হে লেবিগোট

4
ধন্যবাদ আমি ঠিক এটিই খুঁজছিলাম। কিছু কার্সারি পরীক্ষার ভিত্তিতে, এটি জেনারেটরগুলির মতো কাজ করে।
মাইকেল ফেয়ারলি

4
আপনি যদি মার্শাল মডিউলটিতে প্রথম দুটি অনুচ্ছেদ পড়েন তবে দেখবেন এটি পরিবর্তে আচার ব্যবহারের পরামর্শ দেয়? আচার পাতার জন্য একই। docs.python.org/2/library/marshal.html
dgorissen

4
আমি marshalপ্রাথমিক হিসাবে অভিধানের একটি অভিধান ক্রমিকায়িত করতে মডিউলটি প্রয়োগ করার চেষ্টা করছি defaultdict(lambda : defaultdict(int))। তবে এটি ত্রুটি ফিরিয়ে দেয় ValueError: unmarshallable object। দ্রষ্টব্য আমি পাইথন 2.7। কোন ধারণা? ধন্যবাদ
user17375

4
পাইথন 3.5.3 এ foo.func_codeউত্থাপিত হয় AttributeError। ফাংশন কোড পাওয়ার অন্য কোনও উপায় আছে?
AlQuemist

41

ডিল পরীক্ষা করে দেখুন , যা বিভিন্ন ধরণের ফাংশন সহ বিভিন্ন ধরণের সমর্থন করতে পাইথনের আচার লাইব্রেরি প্রসারিত করে:

>>> import dill as pickle
>>> def f(x): return x + 1
...
>>> g = pickle.dumps(f)
>>> f(1)
2
>>> pickle.loads(g)(1)
2

এটি ফাংশনটির সমাপ্তিতে অবজেক্টগুলির রেফারেন্সকে সমর্থন করে:

>>> def plusTwo(x): return f(f(x))
...
>>> pickle.loads(pickle.dumps(plusTwo))(1)
3

4
ডিল এছাড়াও ফাংশন এবং ল্যাম্বডাস থেকে উত্স কোড পাওয়ার এবং ডিস্কে সেভ করার জন্য খুব ভাল কাজ করে, যদি আপনি এটি পছন্দ করে না বস্তু বাছাই।
মাইক ম্যাকার্নস 4

14

পাইরো করতে সক্ষম হয় আপনার জন্য এমনটি


এই বিশেষ প্রকল্পের জন্য আমার স্ট্যান্ডার্ড লাইব্রেরিটি থাকা উচিত।
মাইকেল ফেয়ারলি

21
কিন্তু যে আপনি করতে পারবেন না মানে এই নয় চেহারা পাইরো কোড এ কিভাবে সম্পন্ন করা হয় :) দেখতে
হারুন Digulla

4
@ অ্যারোনডিগুল্লা- সত্য, তবে এটি উল্লেখযোগ্য যে অন্য কারও প্রকাশিত কোডের একক লাইন পড়ার আগে আপনার সফ্টওয়্যারটির লাইসেন্সটি সর্বদা পরীক্ষা করা উচিত। অন্যের কোড পড়া এবং উত্সটি উদ্ধৃত না করে লাইসেন্সের অনুলিপি / অনুলিপি অনুসরণ না করে ধারণাগুলি পুনরায় ব্যবহার করা অনেক ক্ষেত্রে চৌর্যবৃত্তি এবং / অথবা কপিরাইট লঙ্ঘন হিসাবে বিবেচিত হতে পারে।
mdscruggs

12

সর্বাধিক সহজ উপায় সম্ভবত inspect.getsource(object)( পরিদর্শন মডিউলটি দেখুন ) যা কোনও ফাংশন বা কোনও পদ্ধতির জন্য সোর্স কোড সহ একটি স্ট্রিং প্রদান করে returns


এটি দেখতে দুর্দান্ত দেখাচ্ছে, ফাংশনের নামটি কোডে স্পষ্টভাবে সংজ্ঞায়িত করা হয়েছে যা কিছুটা সমস্যাযুক্ত। আমি কোডটির প্রথম লাইনটি কেটে ফেলতে পারি, তবে 'ডিফ \ / এন ফানক ():' এর মতো কিছু করে তা ব্রেকিংযোগ্য। আমি নিজেই ফাংশনটির সাথে ফাংশনটির নামটি আনতে পারতাম, তবে নামটি সংঘটিত হবে না এমন আমার কোনও গ্যারান্টি নেই, বা আমার একটি কার্যটি একটি মোড়কের মধ্যে রাখতে হবে, যা এখনও পরিষ্কার সমাধান নয় but এটা করতে হতে পারে।
মাইকেল ফেয়ারলি

4
নোট করুন যে পরিদর্শন মডিউলটি আসলে এটি কোথায় সংজ্ঞায়িত হয়েছিল সেই ফাংশনটি জিজ্ঞাসা করছে এবং তারপরে উত্স কোড ফাইল থেকে সেই লাইনে পড়া - খুব পরিশীলিত।
খুব বেশি পিএইচপি

4
আপনি ফাংশনের নামটি .__ নাম__ গুণাবলী ব্যবহার করে এটি জানতে পারেন। আপনি ^ Def \ s * {নাম} \ s * এ একটি রেজেক্স প্রতিস্থাপন করতে পারেন (এবং আপনার পছন্দের নামটি দিন fool এটি নির্বোধ নয়, তবে এটি বেশিরভাগ ক্ষেত্রে কার্যকর হবে
খুব বেশি পিএইচপি

6

আপনি রানটাইমে ফাংশনটি জেনারেট করেছেন কিনা তা এ সবের উপর নির্ভর করে:

যদি আপনি এটি করেন - ফাইলটি inspect.getsource(object)থেকে বস্তুর উত্স পাওয়ার সাথে সাথে গতিশীলভাবে উত্পন্ন ফাংশনগুলির জন্য কাজ করবে না .py, সুতরাং মৃত্যুদন্ড কার্যকর করার আগে সংজ্ঞায়িত ফাংশনগুলি কেবল উত্স হিসাবে পুনরুদ্ধার করতে পারে।

এবং যদি আপনার ফাংশনগুলি যাইহোক ফাইলগুলিতে স্থাপন করা হয় তবে কেন সেগুলিতে রিসিভার অ্যাক্সেস দেয় না এবং কেবল মডিউল এবং ফাংশন নামগুলি দিয়ে যায়।

গতিশীলভাবে তৈরি ফাংশনগুলির একমাত্র সমাধান যা আমি ভাবতে পারি তা হ'ল সঞ্চালনের আগে একটি স্ট্রিং হিসাবে ফাংশন তৈরি করা, উত্স সঞ্চারিত করা, এবং তারপরে eval()এটি রিসিভারের দিকে।

সম্পাদনা করুন: marshalসমাধানটি বেশ স্মার্ট দেখায়, আপনি জানতেন না যে আপনি অন্য কিছু বিল্ট-ইনগুলি সিরিয়াল করতে পারবেন



2
কোড_ স্ট্রিং = '' '
ডিফ ফু (এক্স):
    এক্স x 2 2
ডিএফ বার (এক্স):
    এক্স x ** 2
'' '

আপত্তি = আচার.ডম্পস (কোড_ স্ট্রিং)

এখন

এক্সিকিউটিভ (pickle.loads (obj))

ফু (1)
> 2
বার (3)
> 9

2

তুমি এটি করতে পারো:

def fn_generator():
    def fn(x, y):
        return x + y
    return fn

এখন, মডিউল নামের উল্লেখের পরিবর্তে transmit(fn_generator())প্রকৃত সংজ্ঞা পাঠাবে fn(x,y)

নেটওয়ার্ক জুড়ে ক্লাস পাঠাতে আপনি একই কৌশল ব্যবহার করতে পারেন।


1

এই মডিউলটির জন্য ব্যবহৃত বুনিয়াদি ফাংশনগুলি আপনার ক্যোয়ারীটি কভার করে, আপনি তারের চেয়ে সেরা সংকোচনের সুযোগ পান; শিক্ষামূলক উত্স কোড দেখুন:

y_serial.py মডিউল :: এসকিউএলাইটের সাথে গুদাম পাইথন অবজেক্ট

"সিরিয়ালাইজেশন + দৃistance়তা :: কোডের কয়েকটি লাইনে পাইথন অবজেক্টগুলি এসকিউএলাইটে সংকুচিত করে এবং এনেটেট করুন; পরে কোনও এসকিউএল ছাড়াই কীওয়ার্ড দ্বারা ক্রমানুসারে এগুলি পুনরুদ্ধার করুন sche স্কিমা-কম ডেটা সঞ্চয় করার জন্য একটি ডাটাবেসের জন্য সর্বাধিক দরকারী" স্ট্যান্ডার্ড "মডিউল।"

http://yserial.sourceforge.net


1

ক্লাউডপিকল সম্ভবত আপনি যা খুঁজছেন তা। ক্লাউডপিকল নীচে বর্ণিত:

ক্লাউডপিকেল বিশেষত ক্লাস্টার কম্পিউটিংয়ের জন্য দরকারী যেখানে পাইথন কোডটি নেটওয়ার্কের মাধ্যমে দূরবর্তী হোস্টগুলিতে চালিত করার জন্য সম্ভবত ডেটার কাছাকাছি হয়।

ব্যবহারের উদাহরণ:

def add_one(n):
  return n + 1

pickled_function = cloudpickle.dumps(add_one)
pickle.loads(pickled_function)(42)

0

এখানে একটি সহায়ক শ্রেণি রয়েছে যা আপনি ফাংশনগুলিকে পিকলেবল করার জন্য গুটিয়ে রাখতে ব্যবহার করতে পারেন। ইতিমধ্যে উল্লিখিত গুহাগুলি marshalপ্রয়োগ হবে তবে যখনই সম্ভব সম্ভব আচার ব্যবহার করার চেষ্টা করা হবে। সিরিয়ালাইজেশন জুড়ে গ্লোবাল বা বন্ধগুলি সংরক্ষণ করার জন্য কোনও প্রচেষ্টা করা হয় না।

    class PicklableFunction:
        def __init__(self, fun):
            self._fun = fun

        def __call__(self, *args, **kwargs):
            return self._fun(*args, **kwargs)

        def __getstate__(self):
            try:
                return pickle.dumps(self._fun)
            except Exception:
                return marshal.dumps((self._fun.__code__, self._fun.__name__))

        def __setstate__(self, state):
            try:
                self._fun = pickle.loads(state)
            except Exception:
                code, name = marshal.loads(state)
                self._fun = types.FunctionType(code, {}, name)

0

আধুনিক পাইথনে আপনি ফাংশন এবং অনেকগুলি বৈকল্পিক আচার করতে পারেন। এই বিবেচনা

import pickle, time
def foobar(a,b):
    print("%r %r"%(a,b))

আপনি এটি আচার করতে পারেন

p = pickle.dumps(foobar)
q = pickle.loads(p)
q(2,3)

আপনি ক্লোজার আচার করতে পারেন

import functools
foobar_closed = functools.partial(foobar,'locked')
p = pickle.dumps(foobar_closed)
q = pickle.loads(p)
q(2)

এমনকি যদি ক্লোজারটি স্থানীয় ভেরিয়েবল ব্যবহার করে

def closer():
    z = time.time()
    return functools.partial(foobar,z)
p = pickle.dumps(closer())
q = pickle.loads(p)
q(2)

তবে আপনি যদি এটি কোনও অভ্যন্তরীণ ফাংশন ব্যবহার করে বন্ধ করেন তবে এটি ব্যর্থ হবে

def builder():
    z = 'internal'
    def mypartial(b):
        return foobar(z,b)
    return mypartial
p = pickle.dumps(builder())
q = pickle.loads(p)
q(2)

ত্রুটি সহ

পিকিং.পিকলিংএরআরআর: 0x7f3b6c885a50> <ফাংশন মাইপারটিয়াল আচার করতে পারছেন না: এটি __ প্রধান __ হিসাবে পাওয়া যায় নি my

পাইথন 2.7 এবং 3.6 দিয়ে পরীক্ষিত ested

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.