পাইথনের ইওল () বনাম অ্যাস্ট.লাইটার_এভাল () ব্যবহার করছেন?


176

আমার এমন কিছু কোডের পরিস্থিতি রয়েছে যেখানে eval()সম্ভাব্য সমাধান হিসাবে উপস্থিত হয়েছিল। এখন আমাকে এর eval()আগে কখনও ব্যবহার করতে হয়নি তবে, এটির সম্ভাব্য বিপদ সম্পর্কে আমি প্রচুর তথ্য পেয়েছি। এটি বলেছিল, আমি এটি ব্যবহার সম্পর্কে খুব সতর্ক।

আমার পরিস্থিতিটি হ'ল কোনও ব্যবহারকারী আমার কাছে ইনপুট দিচ্ছেন:

datamap = raw_input('Provide some data here: ')

যেখানে datamapঅভিধান হওয়া দরকার। আমি চারপাশে অনুসন্ধান করে দেখেছি যে এটি কার্যকর eval()হতে পারে। আমি ভেবেছিলাম যে ডেটা ব্যবহারের চেষ্টা করার আগে আমি ইনপুটটির ধরণটি পরীক্ষা করতে সক্ষম হতে পারি এবং এটি একটি কার্যকর সুরক্ষা সতর্কতা হবে।

datamap = eval(raw_input('Provide some data here: ')
if not isinstance(datamap, dict):
    return

আমি দস্তাবেজগুলির মাধ্যমে পড়েছি এবং এটি এখনও নিরাপদ কিনা তা আমি এখনও পরিষ্কার। ডেটা প্রবেশের সাথে সাথে বা datamapভেরিয়েবল বলা হওয়ার পরে কি ডেটা মূল্যায়ন করে ?

কি astমডিউল এর .literal_eval()শুধুমাত্র নিরাপদ বিকল্প?

উত্তর:


190

datamap = eval(raw_input('Provide some data here: '))এর অর্থ হ'ল আপনি কোডটি অনিরাপদ বা না হওয়ার কথা বলার আগে আপনি বাস্তবে মূল্যায়ন করেন । এটি ফাংশন বলা হওয়ার সাথে সাথে কোডটি মূল্যায়ন করে। এর বিপদগুলিওeval দেখুন ।

ast.literal_eval ইনপুটটি বৈধ পাইথন ডেটাটাইপ না হলে একটি ব্যতিক্রম উত্থাপন করে, তাই কোডটি না থাকলে কার্যকর করা হবে না won't

ast.literal_evalযখনই আপনার প্রয়োজন হবে ব্যবহার করুন eval। আপনার সাধারণত আক্ষরিক পাইথন বিবৃতি মূল্যায়ন করা উচিত নয়।


20
এটি কোনও 100% সঠিক পরামর্শ নয় যেহেতু কোনও বিটওয়াইজ অপারেটর (বা ওভারলোডেড অপারেটর) ব্যর্থ হবে। যেমন। ast.literal_eval("1 & 1")একটি ত্রুটি নিক্ষেপ করবে কিন্তু eval("1 & 1")করবে না।
ড্যানিয়েল ভ্যান ফ্লাইম্যান 22'17

1
উৎসুক. আমরা যদি "1 & 1" এর মতো কিছু আশা করি তবে কি আমরা এক্সপ্রেশন পার্সার বা কিছু ব্যবহার করব না?
thelinuxer

@ স্টিলিনক্সার এখনও আপনার উচিত, হ্যাঁ; আপনি কেবল এর ast.literal_evalমতো কোনও কিছুর জন্য ব্যবহার করতে সক্ষম হবেন না (যেমন আপনি নিজেই কোনও পার্সার প্রয়োগ করতে পারেন)।
অস্থিরতা

104

ast.literal_eval() পাইথনের সিনট্যাক্সের একটি ছোট উপসেটটি কেবল বৈধ হিসাবে বিবেচনা করে:

সরবরাহ করা স্ট্রিং বা নোডে কেবলমাত্র পাইথনের আক্ষরিক কাঠামোগুলি থাকতে পারে: স্ট্রিং, সংখ্যা, টিপলস, তালিকা, ডিকটস, বুলিয়ান এবং কোনও নয়।

পাসিং __import__('os').system('rm -rf /a-path-you-really-care-about')মধ্যে ast.literal_eval()একটি ত্রুটি বাড়াতে হবে, কিন্তু eval()আনন্দের সাথে আপনার ড্রাইভ মুছা হবে।

যেহেতু দেখে মনে হচ্ছে আপনি কেবল ব্যবহারকারীকে একটি সরল অভিধান দিচ্ছেন, ব্যবহার করুন ast.literal_eval()। এটি আপনি যা চান নিরাপদে তা করে এবং আরও কিছু না।


বাইট-স্ট্রিং (ক্লাস বাইট) পাশাপাশি সমর্থন করে। যেমন। বি'হেলো ওয়ার্ল্ড '
এক্সচিকাক্স

52

স্পষ্ট : এটি খুব শক্তিশালী, তবে আপনি যদি অবিশ্বস্ত ইনপুট থেকে মূল্যায়ন করতে স্ট্রিং গ্রহণ করেন তবে এটি খুব বিপজ্জনক। মনে করুন স্ট্রিংটি মূল্যায়ন করা হচ্ছে "os.system ('rm -rf /')"? এটি সত্যিই আপনার কম্পিউটারের সমস্ত ফাইল মুছতে শুরু করবে।

ast.literal_eval: একটি এক্সপ্রেশন নোড বা পাইথন আক্ষরিক বা ধারক প্রদর্শনযুক্ত একটি স্ট্রিং নিরাপদে মূল্যায়ন করুন। সরবরাহ করা স্ট্রিং বা নোডে কেবলমাত্র পাইথনের আক্ষরিক কাঠামো থাকতে পারে: স্ট্রিং, বাইটস, সংখ্যা, টিপলস, তালিকা, ডিক্টস, সেটস, বুলিয়ানস, কোনওটি নয়, বাইটস এবং সেটগুলি।

বাক্য গঠন:

eval(expression, globals=None, locals=None)
import ast
ast.literal_eval(node_or_string)

উদাহরণ:

# python 2.x - doesn't accept operators in string format
import ast
ast.literal_eval('[1, 2, 3]')  # output: [1, 2, 3]
ast.literal_eval('1+1') # output: ValueError: malformed string


# python 3.0 -3.6
import ast
ast.literal_eval("1+1") # output : 2
ast.literal_eval("{'a': 2, 'b': 3, 3:'xyz'}") # output : {'a': 2, 'b': 3, 3:'xyz'}
# type dictionary
ast.literal_eval("",{}) # output : Syntax Error required only one parameter
ast.literal_eval("__import__('os').system('rm -rf /')") # output : error

eval("__import__('os').system('rm -rf /')") 
# output : start deleting all the files on your computer.
# restricting using global and local variables
eval("__import__('os').system('rm -rf /')",{'__builtins__':{}},{})
# output : Error due to blocked imports by passing  '__builtins__':{} in global

# But still eval is not safe. we can access and break the code as given below
s = """
(lambda fc=(
lambda n: [
    c for c in 
        ().__class__.__bases__[0].__subclasses__() 
        if c.__name__ == n
    ][0]
):
fc("function")(
    fc("code")(
        0,0,0,0,"KABOOM",(),(),(),"","",0,""
    ),{}
)()
)()
"""
eval(s, {'__builtins__':{}})

উপরের কোডে ().__class__.__bases__[0]নিজের আপত্তি ছাড়া আর কিছুই নয়। এখন আমরা সমস্ত উপশ্রেণী ইনস্ট্যান্ট করেছিলাম , এখানে আমাদের মূল enter code hereলক্ষ্য এটি থেকে এন নামের একটি শ্রেণি খুঁজে পাওয়া।

আমাদের তাত্ক্ষণিক সাবক্লাসগুলি থেকে codeআপত্তি করা এবং functionআপত্তি করা দরকার । এটি CPythonঅবজেক্টের সাবক্লাস অ্যাক্সেস এবং সিস্টেমটি সংযুক্ত করার বিকল্প উপায় ।

পাইথন থেকে ৩.7 অ্যাস্ট.লাইটারাল_ওয়াল () এখন আরও কঠোর। স্বেচ্ছাসেবী সংখ্যার যোগ এবং বিয়োগের অনুমতি দেওয়া হয় না। লিংক


1
আমি পাইথন ২.7 ব্যবহার করছি এবং আমি পাইথন ৩.x এ এটির কাজ ঠিক করে দেখেছি। আমার খারাপ আমি অজগর ২.7 এ চেষ্টা করে
চলেছি

3
ast.literal_eval("1+1")পাইথন ৩.7-তে কাজ করে না এবং যেমনটি আগেই বলেছিল, আক্ষরিক_ভালটি কয়েকটি কয়েকটি ডাটা স্ট্রাকচারের আক্ষরিক মধ্যে সীমাবদ্ধ হওয়া উচিত। এটি একটি বাইনারি অপারেশনকে বিশ্লেষণ করতে সক্ষম হবে না।
সেশেহু

আপনি আপনার KABOOMকোড ব্যাখ্যা করতে পারেন , দয়া করে? এটি এখানে খুঁজে KABOOM
পেয়েছে

2
@Winklerrr KABOOMএখানে খুব সুন্দরভাবে ব্যাখ্যা করা হয়েছে: nedbatchelder.com/blog/201206/eval_really_is_dan
जर.

41

পাইথন এর মূল্যায়নে আগ্রহী তাই eval(raw_input(...))ব্যবহারকারীর ইনপুটটি যত তাড়াতাড়ি হিট হবে ততক্ষণ তা মূল্যায়ন করবে eval, পরে আপনি ডেটা দিয়ে যা করেন তা নির্বিশেষে। সুতরাং, এটি নিরাপদ নয় , বিশেষত যখন আপনি evalইনপুট ব্যবহার করেন।

ব্যবহার ast.literal_eval


উদাহরণস্বরূপ, প্রম্পটে এটি প্রবেশ করা আপনার পক্ষে খুব খারাপ হবে:

__import__('os').system('rm -rf /a-path-you-really-care-about')

3

আপনার যা যা প্রয়োজন তা হ'ল একটি ব্যবহারকারী সরবরাহিত অভিধান, সম্ভাব্য আরও ভাল সমাধান json.loads। মূল সীমাবদ্ধতা হ'ল জসন ডিক্টসের জন্য স্ট্রিং কীগুলি দরকার। এছাড়াও আপনি কেবল আক্ষরিক ডেটা সরবরাহ করতে পারেন তবে এটি ক্ষেত্রেও literal_eval


1

আমি আটকে ছিলাম ast.literal_eval()। আমি এটি ইন্টেলিজ আইডিইএ ডিবাগারে চেষ্টা করছিলাম এবং এটি Noneডিবাগার আউটপুটটিতে ফিরে আসছিল ।

তবে পরে যখন আমি এর আউটপুটটি একটি ভেরিয়েবলের কাছে নির্ধারিত করে কোডে মুদ্রণ করি। এটা ভাল কাজ করে। ভাগ করে নেওয়ার কোড উদাহরণ:

import ast
sample_string = '[{"id":"XYZ_GTTC_TYR", "name":"Suction"}]'
output_value = ast.literal_eval(sample_string)
print(output_value)

এর অজগর সংস্করণ 3.6।

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