'ইভাল' ব্যবহার করা কেন একটি খারাপ অভ্যাস?


138

আমি আমার গানের ডেটা সহজেই সঞ্চয় করতে নিম্নলিখিত ক্লাসটি ব্যবহার করছি।

class Song:
    """The class to store the details of each song"""
    attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
    def __init__(self):
        for att in self.attsToStore:
            exec 'self.%s=None'%(att.lower()) in locals()
    def setDetail(self, key, val):
        if key in self.attsToStore:
            exec 'self.%s=val'%(key.lower()) in locals()

আমি মনে করি যে এটি একটি if/elseব্লক লেখার চেয়ে অনেক বেশি এক্সটেনসিবল । তবে evalমনে হয় এটি একটি খারাপ অনুশীলন এবং ব্যবহারে অনিরাপদ considered যদি তা হয় তবে কেন কেউ আমাকে ব্যাখ্যা করতে এবং আমাকে উপরের বর্গটি সংজ্ঞায়নের আরও ভাল উপায় দেখাতে পারে?


40
আপনি কীভাবে শিখলেন exec/evalএবং এখনও জানেন না setattr?
u0b34a0f6ae

3
আমি বিশ্বাস করি যে এটি অয়েল এবং লিস্পের তুলনা করে একটি নিবন্ধ থেকে আমি ইওল সম্পর্কে শিখেছি।
নিকউইন

উত্তর:


194

হ্যাঁ, ইভাল ব্যবহার করা একটি খারাপ অভ্যাস। কেবল কয়েকটি কারণের নামকরণ করতে:

  1. এটি করার আরও প্রায়শই ভাল উপায় আছে
  2. খুব বিপজ্জনক এবং নিরাপত্তাহীন
  3. ডিবাগিংকে কঠিন করে তোলে
  4. ধীরে

আপনার ক্ষেত্রে আপনি পরিবর্তে সেটট্রটার ব্যবহার করতে পারেন :

class Song:
    """The class to store the details of each song"""
    attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
    def __init__(self):
        for att in self.attsToStore:
            setattr(self, att.lower(), None)
    def setDetail(self, key, val):
        if key in self.attsToStore:
            setattr(self, key.lower(), val)

সম্পাদনা করুন:

কিছু ক্ষেত্রে রয়েছে যেখানে আপনাকে ইওল বা নির্বাহ করতে হবে। তবে এগুলি বিরল। আপনার ক্ষেত্রে eval ব্যবহার নিশ্চিতভাবে খারাপ অভ্যাস। আমি খারাপ অভ্যাসের উপর জোর দিচ্ছি কারণ eval এবং exec প্রায়শই ভুল জায়গায় ব্যবহার করা হয়।

সম্পাদনা 2:

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

সম্পাদনা 3: পুনরায় সাজানো বিন্দু 1 এবং 4


22
-1: "খুব বিপজ্জনক এবং নিরাপত্তাহীন" মিথ্যা। অন্য তিনটি অসামান্যভাবে পরিষ্কার। দয়া করে এগুলিকে পুনরায় অর্ডার করুন যাতে 2 এবং 4 প্রথম দুটি হয়। এটি কেবল তখনই অনিরাপদ যদি আপনি চারপাশে অশুভ সোসিওপ্যাথ ঘিরে থাকেন যারা আপনার অ্যাপ্লিকেশনটি নষ্ট করার উপায় খুঁজছেন।
এস .লট

51
@ এস.লোট, সাধারণভাবে ইওল / এক্সিকিউট এড়ানোর জন্য নিরাপত্তাহীনতা একটি অত্যন্ত গুরুত্বপূর্ণ কারণ। ওয়েবসাইটের মতো অনেক অ্যাপ্লিকেশনের অতিরিক্ত যত্ন নেওয়া উচিত। এমন কোনও ওয়েবসাইটের ওপি উদাহরণটি ধরুন যা ব্যবহারকারীরা গানের নাম প্রবেশ করানোর প্রত্যাশা করে। তাড়াতাড়ি বা পরে এটি শোষণ করতে বাধ্য bound এমনকি একটি নির্দোষ ইনপুট যেমন: আসুন মজা করি। একটি সিনট্যাক্স ত্রুটি সৃষ্টি করবে এবং দুর্বলতা প্রকাশ করবে।
নাদিয়া আলরামলি 16

17
@ নাদিয়া আলরামলি: ব্যবহারকারী ইনপুট এবং evalএকে অপরের সাথে কিছুই করার নেই। মৌলিকভাবে ভুল-নকশাকৃত একটি অ্যাপ্লিকেশন মূলত ভুল-নকশা করা। evalশূন্য দ্বারা বিভাজন বা কোনও মডিউল আমদানির চেষ্টা করার চেয়ে খারাপ ডিজাইনের মূল কারণ আর নয় যা জানা নেই। evalঅনিরাপদ নয় অ্যাপ্লিকেশনগুলি নিরাপদ।
এস.লোট

17
@ জেফজোজ: প্রকৃতপক্ষে, এটি মূলত খারাপ / মন্দ কারণ এটি অপরিকল্পিত ডেটাটিকে কোড হিসাবে গণ্য করে (এই কারণেই এক্সএসএস, এসকিউএল ইঞ্জেকশন এবং স্ট্যাকের স্ম্যাশ বিদ্যমান)। @ এস.লোট: "এটি কেবল তখনই অনিরাপদ, যদি আপনি চারপাশে দুষ্ট সমাজবিদরা আপনার অ্যাপ্লিকেশনটি নষ্ট করার উপায় খুঁজছেন by" শীতল, সুতরাং আপনি একটি প্রোগ্রাম তৈরি করুন বলে নিন calcএবং এটি সম্পাদন করে print(eval("{} + {}".format(n1, n2)))এবং বেরিয়ে আসে এমন সংখ্যা যুক্ত করতে । এখন আপনি কিছু ওএস দিয়ে এই প্রোগ্রামটি বিতরণ করুন। তারপরে কেউ বাশ স্ক্রিপ্ট তৈরি করে যা স্টক সাইট থেকে কিছু নম্বর নেয় এবং সেগুলি ব্যবহার করে যুক্ত করে calc। বুম?
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

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

32

ব্যবহার evalদুর্বল, কোনও পরিষ্কার খারাপ অভ্যাস নয়।

  1. এটি "সফ্টওয়্যারের মূলনীতি" লঙ্ঘন করে। আপনার উত্স কার্যকর কার্যকর কিসের যোগফল নয়। আপনার উত্স ছাড়াও, যুক্তি রয়েছে eval, যা অবশ্যই স্পষ্টভাবে বুঝতে হবে। এই কারণে এটি সর্বশেষ অবলম্বনের হাতিয়ার।

  2. এটি সাধারণত নির্বোধ নকশার লক্ষণ। গতিশীল উত্স কোডের জন্য খুব কমই খুব ভাল কারণ আছে, ফ্লাইট অন ফ্লাইট built প্রতিনিধি এবং অন্যান্য ওও ডিজাইন কৌশলগুলির সাথে প্রায় কোনও কিছু করা যায়।

  3. এটি কোডের ছোট ছোট টুকরোগুলি তুলনায় তুলনামূলকভাবে ধীর গতিতে বাড়ে। একটি ওভারহেড যা আরও ভাল ডিজাইনের নিদর্শনগুলি ব্যবহার করে এড়ানো যায়।

পাদটীকা হিসাবে, বিকৃত সোশ্যোপ্যাথগুলির হাতে, এটি ভাল কাজ করতে পারে না। যাইহোক, যখন অস্বচ্ছল সামাজিক-চিকিত্সা ব্যবহারকারী বা প্রশাসকদের সাথে মুখোমুখি হন, তাদের প্রথমে পাইথনকে ব্যাখ্যা না করাই ভাল। সত্যিকারের দুষ্টের হাতে পাইথন দায় হতে পারে; evalঝুঁকি মোটেও বাড়ায় না


7
@ ওউন এস। কথাটি হ'ল ভাবেন আপনাকে বলবে যে evalএটি একরকম "সুরক্ষা দুর্বলতা"। যেন পাইথন - নিজেই - কেবল ব্যাখ্যা করা উত্স নয় যা যে কেউ পরিবর্তন করতে পারে। যখন "ইওল একটি সুরক্ষা গর্ত" এর মুখোমুখি হয়, আপনি কেবল ধরে নিতে পারেন যে এটি সোশিওপ্যাথের হাতে একটি সুরক্ষা গর্ত। সাধারণ প্রোগ্রামাররা কেবল বিদ্যমান পাইথন উত্সটি কেবলমাত্র সংশোধন করে এবং সরাসরি তাদের সমস্যার কারণ করে। পরোক্ষভাবে evalযাদু মাধ্যমে নয়।
এস .লট

14
ঠিক আছে, আমি আপনাকে ঠিক বলতে পারি কেন আমি বলব যে ওয়াল একটি সুরক্ষিত দুর্বলতা, এবং এটি ইনপুট হিসাবে দেওয়া স্ট্রিংয়ের বিশ্বাসযোগ্যতার সাথে করতে হবে। যদি সেই স্ট্রিংটি পুরো বা আংশিকভাবে বাইরের বিশ্ব থেকে আসে তবে আপনি যদি সতর্ক না হন তবে আপনার প্রোগ্রামে স্ক্রিপ্টিং আক্রমণের সম্ভাবনা রয়েছে। তবে এটি কোনও বহিরাগত আক্রমণকারীর ডিজেঞ্জমেন্ট, ব্যবহারকারী বা প্রশাসকের নয় not
ওভেন এস।

6
@ ওউইনস: "যদি সেই স্ট্রিংটি সম্পূর্ণ বা আংশিকভাবে বাইরে থেকে আসে তবে" প্রায়ই মিথ্যা। এটি কোনও "সাবধানী" জিনিস নয়। এটি কালো এবং সাদা। পাঠ্যটি যদি কোনও ব্যবহারকারীর কাছ থেকে আসে তবে এটি কখনই বিশ্বাস করা যায় না। যত্ন সত্যিই এটির অংশ নয়, এটি একেবারেই অবিশ্বাস্য। অন্যথায়, পাঠ্যটি বিকাশকারী, ইনস্টলার বা প্রশাসকের কাছ থেকে আসে এবং এটি বিশ্বাস করা যায়।
এস .লট

8
@ ওউইনস: অবিশ্বস্ত পাইথন কোডটির স্ট্রিংয়ের পক্ষে কোনও সম্ভাবনা নেই যে এটি বিশ্বাসযোগ্য করে তুলবে। "সাবধান" অংশ বাদে আপনি যা বলছেন তার বেশিরভাগের সাথে আমি একমত। এটি একটি খুব খাস্তা পার্থক্য। বাইরের বিশ্বের কোড অবিশ্বাস্য। আফাইক, পালানোর বা ফিল্টারিংয়ের পরিমাণ এটিকে পরিষ্কার করতে পারে না। আপনার যদি এমন কোনও প্রকারের পলায়ন ফাংশন থাকে যা কোড গ্রহণযোগ্য করে তোলে, দয়া করে ভাগ করুন। আমি ভাবিনি যে এ জাতীয় জিনিস সম্ভব হয়েছিল। উদাহরণস্বরূপ while True: passকিছুটা পালিয়ে যাওয়া দিয়ে পরিষ্কার করা শক্ত হবে।
এস .লট

2
@ ওউইনস: "একটি স্ট্রিং হিসাবে লক্ষ্য করা হয়েছে, স্বেচ্ছাচারিত কোড নয়"। এটি সম্পর্কিত নয়। এটি কেবল একটি স্ট্রিং মান, যা আপনি কখনই পাস করতে পারবেন না eval(), কারণ এটি একটি স্ট্রিং। "বাইরের বিশ্ব" থেকে কোড স্যানিটাইজ করা যায় না। বাইরের বিশ্বের স্ট্রিংগুলি কেবল স্ট্রিং। আপনি কী বলছেন তা সম্পর্কে আমি অস্পষ্ট। সম্ভবত আপনার এখানে আরও একটি সম্পূর্ণ ব্লগ পোস্ট এবং লিঙ্ক সরবরাহ করা উচিত link
এসলট

23

এই ক্ষেত্রে, হ্যাঁ। পরিবর্তে

exec 'self.Foo=val'

আপনার বিল্টিন ফাংশনটি ব্যবহার করা উচিত setattr:

setattr(self, 'Foo', val)

16

হ্যাঁ, এটি:

পাইথন ব্যবহার করে হ্যাক করুন:

>>> eval(input())
"__import__('os').listdir('.')"
...........
...........   #dir listing
...........

নীচের কোডটি একটি উইন্ডোজ মেশিনে চলমান সমস্ত কার্য তালিকাবদ্ধ করবে।

>>> eval(input())
"__import__('subprocess').Popen(['tasklist'],stdout=__import__('subprocess').PIPE).communicate()[0]"

লিনাক্সে:

>>> eval(input())
"__import__('subprocess').Popen(['ps', 'aux'],stdout=__import__('subprocess').PIPE).communicate()[0]"

7

এটি লক্ষণীয় যে প্রশ্নে নির্দিষ্ট সমস্যাটির জন্য ব্যবহারের বিভিন্ন বিকল্প রয়েছে eval:

সরল, যেমনটি উল্লেখ করা হয়েছে, তা ব্যবহার করছে setattr:

def __init__(self):
    for name in attsToStore:
        setattr(self, name, None)

একটি কম স্পষ্ট পদ্ধতির অবজেক্টের __dict__অবজেক্টটি সরাসরি আপডেট করা ating আপনি যদি যা করতে চান তার মধ্যে বৈশিষ্ট্যগুলি আরম্ভ করা হয় None, তবে এটি উপরের চেয়ে কম সোজা। তবে এটি বিবেচনা করুন:

def __init__(self, **kwargs):
    for name in self.attsToStore:
       self.__dict__[name] = kwargs.get(name, None)

এটি আপনাকে নির্মাণকারীর কাছে কী-ওয়ার্ড আর্গুমেন্টগুলি পাস করার অনুমতি দেয়, যেমন:

s = Song(name='History', artist='The Verve')

এটি আপনাকে locals()আরও স্পষ্টভাবে আপনার ব্যবহার করতে দেয় যেমন:

s = Song(**locals())

... এবং, যদি আপনি সত্যিই Noneসেই বৈশিষ্ট্যগুলিকে নির্দিষ্ট করতে চান তবে যার নাম পাওয়া যায় locals():

s = Song(**dict([(k, None) for k in locals().keys()]))

বৈশিষ্ট্যের তালিকার জন্য ডিফল্ট মান সহ কোনও বস্তু সরবরাহের জন্য আরেকটি পদ্ধতির শ্রেণীর __getattr__পদ্ধতিটি সংজ্ঞা দেওয়া:

def __getattr__(self, name):
    if name in self.attsToStore:
        return None
    raise NameError, name

যখন নামযুক্ত বৈশিষ্ট্যটি সাধারণ উপায়ে পাওয়া যায় না তখন এই পদ্ধতিটি কল হয়। এই পদ্ধতির সাথে কন্সট্রাক্টরের বৈশিষ্ট্যগুলি সেট করা বা আপডেট করার চেয়ে কিছুটা সহজ সরল __dict__, তবে এটি উপস্থিতি না থাকলে প্রকৃতপক্ষে বৈশিষ্ট্যটি তৈরি না করার যোগ্যতা রয়েছে যা শ্রেণীর স্মৃতি ব্যবহারকে যথেষ্ট পরিমাণে হ্রাস করতে পারে।

এই সমস্ত বিষয়: সাধারণত এড়ানোর জন্য প্রচুর কারণ রয়েছে eval - আপনি যে কোডটি নিয়ন্ত্রণ করেন না তা কার্যকর করার কোডের সুরক্ষা সমস্যা, কোডটির ব্যবহারিক সমস্যা যা আপনি ডিবাগ করতে পারবেন না ইত্যাদি etc. তবে আরও গুরুত্বপূর্ণ কারণ But এটি সাধারণভাবে, আপনার এটি ব্যবহার করার দরকার নেই। পাইথন এর অভ্যন্তরীণ প্রক্রিয়াগুলির প্রচুর পরিমাণ প্রোগ্রামারকে প্রকাশ করে যে আপনার কোডটি লিখতে খুব কমই প্রয়োজন।


1
যুক্তিযুক্ত আরও বেশি (বা কম) পাইথোনিক: অবজেক্টের __dict__সরাসরি ব্যবহার না করে , উত্তরাধিকারের মাধ্যমে বা কোনও বৈশিষ্ট্য হিসাবে বস্তুকে একটি আসল অভিধান অবজেক্ট দিন।
জোশ লি

1
"একটি স্বল্প স্পষ্ট পদ্ধতির মাধ্যমে অবজেক্টের ডিক অবজেক্টটি সরাসরি আপডেট করা হচ্ছে " => দ্রষ্টব্য যে এটি কোনও বর্ণনাকারী (সম্পত্তি বা অন্যান্য) বা __setattr__অতিক্রম করতে হবে, যা অপ্রত্যাশিত ফলাফলের দিকে নিয়ে যেতে পারে। setattr()এই সমস্যা নেই।
ব্রুনো desthuilliers

5

অন্যান্য ব্যবহারকারীরা নির্ভর করে যে কীভাবে আপনার কোডটির উপর নির্ভর না করে পরিবর্তন করা যেতে পারে eval; আমি ব্যবহারের জন্য একটি বৈধ ব্যবহারের কেস অফার করব eval, এটি সিপিথনেও পাওয়া যায়: টেস্টিং

এখানে আমি একটি উদাহরণ পেয়েছি test_unary.pyযেখানে একটি পরীক্ষা (+|-|~)b'a'একটি উত্থাপন করে কিনা তা পরীক্ষা TypeError:

def test_bad_types(self):
    for op in '+', '-', '~':
        self.assertRaises(TypeError, eval, op + "b'a'")
        self.assertRaises(TypeError, eval, op + "'a'")

ব্যবহার এখানে স্পষ্টত খারাপ অভ্যাস নয়; আপনি ইনপুট সংজ্ঞায়িত করেন এবং কেবল আচরণ পর্যবেক্ষণ করেন। evalপরীক্ষার জন্য কার্যকর।

এই অনুসন্ধান কটাক্ষপাত জন্য eval, CPython Git সংগ্রহস্থলের সম্পাদনা; Eval সঙ্গে পরীক্ষা ভারী ব্যবহৃত হয়।


2

যখন eval()ব্যবহারকারী-সরবরাহিত ইনপুট প্রক্রিয়া করতে ব্যবহৃত হয়, আপনি ব্যবহারকারীকে ড্রপ-টু-রিপ্লেতে এই জাতীয় কিছু সরবরাহ করে:

"__import__('code').InteractiveConsole(locals=globals()).interact()"

আপনি এটির সাথে দূরে সরে যেতে পারেন, তবে সাধারণত আপনি আপনার অ্যাপ্লিকেশনগুলিতে স্বেচ্ছাচারিত কোড প্রয়োগের জন্য ভেক্টর চান না ।


1

@ নদিয়া আলরামলি উত্তর ছাড়াও, যেহেতু আমি পাইথনে নতুন এবং আমি evalকীভাবে সময় ব্যবহার করতে পারি তা পরীক্ষা করতে আগ্রহী , তাই আমি একটি ছোট প্রোগ্রাম চেষ্টা করেছি এবং নীচে পর্যবেক্ষণগুলি ছিল:

#Difference while using print() with eval() and w/o eval() to print an int = 0.528969s per 100000 evals()

from datetime import datetime
def strOfNos():
    s = []
    for x in range(100000):
        s.append(str(x))
    return s

strOfNos()
print(datetime.now())
for x in strOfNos():
    print(x) #print(eval(x))
print(datetime.now())

#when using eval(int)
#2018-10-29 12:36:08.206022
#2018-10-29 12:36:10.407911
#diff = 2.201889 s

#when using int only
#2018-10-29 12:37:50.022753
#2018-10-29 12:37:51.090045
#diff = 1.67292
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.