हमेशा सच का मूल्यांकन करने के लिए `ए == बी या सी या डी` क्यों करता है?


108

मैं एक सुरक्षा प्रणाली लिख रहा हूं जो अनधिकृत उपयोगकर्ताओं तक पहुंच से इनकार करती है।

import sys

print("Hello. Please enter your name:")
name = sys.stdin.readline().strip()
if name == "Kevin" or "Jon" or "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

यह अपेक्षित उपयोगकर्ताओं तक पहुँच प्रदान करता है, लेकिन यह अनधिकृत उपयोगकर्ताओं को भी सुविधा देता है!

Hello. Please enter your name:
Bob
Access granted.

ऐसा क्यों होता है? मैंने स्पष्ट रूप से केवल तभी पहुंच प्रदान करने के लिए कहा है जब nameकेविन, जॉन या इनबार के बराबर होता है। मैंने विपरीत तर्क की भी कोशिश की है if "Kevin" or "Jon" or "Inbar" == name, लेकिन परिणाम वही है।


1
@ जीन-फ्रांस्वा FYI में इस सवाल के बारे में कुछ चर्चा की गई थी और अजगर के कमरे में पहले इसका लक्ष्य रखा गया था, यहाँ चर्चा शुरू होती है । मैं समझता हूं कि यदि आप इसे बंद करना चाहते हैं, लेकिन मुझे लगा कि आप उन कारणों के बारे में जानना चाहते हैं जिनके लिए हाल ही में पोस्ट को फिर से खोला गया था। पूर्ण प्रकटीकरण: मार्टिज़न, द्वैध लक्ष्य पर उत्तर के लेखक को अभी तक मामले पर झंकार करने का समय नहीं है।
एंड्रास डीक

मार्टिज़न का उत्तर केवल "प्राकृतिक भाषा का उपयोग न करना" के साथ इसे समझाने में उत्कृष्ट है, अन्य, ठीक है, ... वे शानदार उत्थान के समय थे ... नीचे दिया गया उत्तर बस इसे दोहराता है। मेरे लिए यह एक डुप्लिकेट है। लेकिन अगर मार्टिज़न को फिर से खोलने के लिए चुनता है, ठीक है, मुझे कोई आपत्ति नहीं है।
जीन फ़्राँस्वा Fabre

4
इस समस्या के बदलावों को शामिल x or y in z, x and y in z, x != y and zकुछ अन्य लोगों और। जबकि इस प्रश्न के समान नहीं, मूल कारण उन सभी के लिए समान है। केवल यह इंगित करना चाहता था कि अगर किसी को उनका प्रश्न इस के डुप्लिकेट के रूप में बंद हो गया और यह सुनिश्चित नहीं हुआ कि यह उनके लिए कैसे प्रासंगिक है।
अरन-फे

जवाबों:


153

कई मामलों में, पायथन प्राकृतिक अंग्रेजी की तरह दिखता है और व्यवहार करता है, लेकिन यह एक ऐसा मामला है जहां यह अमूर्तता विफल हो जाती है। लोग यह निर्धारित करने के लिए संदर्भ सुराग का उपयोग कर सकते हैं कि "जॉन" और "इनबार" वस्तुएं क्रिया "बराबरी" में शामिल हो गई हैं, लेकिन पायथन दुभाषिया अधिक शाब्दिक दिमाग है।

if name == "Kevin" or "Jon" or "Inbar":

तार्किक रूप से इसके समकक्ष है:

if (name == "Kevin") or ("Jon") or ("Inbar"):

उपयोगकर्ता बॉब के लिए, जो इसके बराबर है:

if (False) or ("Jon") or ("Inbar"):

orऑपरेटर एक सकारात्मक के साथ पहला तर्क चुनता सच्चाई मूल्य :

if ("Jon"):

और जब से "जॉन" का एक सकारात्मक सत्य मूल्य है, द if ब्लॉक निष्पादित होता है। यही कारण है कि दिए गए नाम की परवाह किए बिना "एक्सेस दी गई" मुद्रित किया जाता है।

इस तर्क के सभी अभिव्यक्ति पर भी लागू होते हैं if "Kevin" or "Jon" or "Inbar" == name। पहला मान, "Kevin"सत्य है, इसलिए ifब्लॉक निष्पादित करता है।


इस सशर्त को ठीक से बनाने के दो सामान्य तरीके हैं।

  1. ==प्रत्येक मान के विरुद्ध स्पष्ट रूप से जांच करने के लिए कई ऑपरेटरों का उपयोग करें :
    if name == "Kevin" or name == "Jon" or name == "Inbar":

  2. मान्य मानों का एक क्रम लिखें, और inसदस्यता के लिए परीक्षण करने के लिए ऑपरेटर का उपयोग करें :
    if name in {"Kevin", "Jon", "Inbar"}:

दो के सामान्य में दूसरे को प्राथमिकता दी जानी चाहिए क्योंकि यह पढ़ना आसान है और तेजी से भी:

>>> import timeit
>>> timeit.timeit('name == "Kevin" or name == "Jon" or name == "Inbar"', setup="name='Inbar'")
0.4247764749999945
>>> timeit.timeit('name in {"Kevin", "Jon", "Inbar"}', setup="name='Inbar'")
0.18493307199999265

उन लोगों के लिए जो सबूत चाहते हैं कि if a == b or c or d or e: ...वास्तव में इस तरह से पार्स किया गया है। अंतर्निहित astमॉड्यूल एक उत्तर प्रदान करता है:

>>> import ast
>>> ast.parse("if a == b or c or d or e: ...")
<_ast.Module object at 0x1031ae6a0>
>>> ast.dump(_)
"Module(body=[If(test=BoolOp(op=Or(), values=[Compare(left=Name(id='a', ctx=Load()), ops=[Eq()], comparators=[Name(id='b', ctx=Load())]), Name(id='c', ctx=Load()), Name(id='d', ctx=Load()), Name(id='e', ctx=Load())]), body=[Expr(value=Ellipsis())], orelse=[])])"
>>>

तो testके ifइस तरह के बयान दिखता है:

BoolOp(
 op=Or(),
 values=[
  Compare(
   left=Name(id='a', ctx=Load()),
   ops=[Eq()],
   comparators=[Name(id='b', ctx=Load())]
  ),
  Name(id='c', ctx=Load()),
  Name(id='d', ctx=Load()),
  Name(id='e', ctx=Load())
 ]
)

एक देख सकते हैं, यह बूलियन ऑपरेटर है orकरने के लिए कई आवेदन किया valuesहै, अर्थात्, a == bऔर c, d, और e


क्या ("Kevin", "Jon", "Inbar")सेट के बजाय टपल चुनने का कोई विशेष कारण है {"Kevin", "Jon", "Inbar"} ?
मानव

2
वास्तव में नहीं, क्योंकि दोनों काम करते हैं यदि मूल्य सभी धोने योग्य हैं। सेट सदस्यता परीक्षण में ट्यूपल सदस्यता परीक्षण की तुलना में बेहतर बिग-ओ जटिलता है, लेकिन एक सेट का निर्माण एक ट्यूपल के निर्माण की तुलना में थोड़ा अधिक महंगा है। मुझे लगता है कि यह काफी हद तक इन जैसे छोटे संग्रह के लिए एक धोने है। समय के साथ खेलना, मेरी मशीन पर a in {b, c, d}लगभग दोगुना है a in (b, c, d)। कुछ सोचने के लिए कि क्या यह कोड का प्रदर्शन-महत्वपूर्ण टुकड़ा है।
केविन

3
यदि एक 'यदि' खंड में 'में' का उपयोग करते समय ट्यूपल या सूची? सदस्यता परीक्षण के लिए निर्धारित शाब्दिक अनुशंसा करता है। मैं अपनी पोस्ट को अपडेट करूंगा।
केविन

आधुनिक पायथन में, यह पहचानता है कि सेट एक स्थिर है और इसे frozensetइसके बजाय बनाता है , इसलिए निर्माण सेट ओवरहेड नहीं है। dis.dis(compile("1 in {1, 2, 3}", '<stdin>', 'eval'))
एंडोलिथ

1

सरल इंजीनियरिंग समस्या, बस इसे थोड़ा और आगे बढ़ाएं।

In [1]: a,b,c,d=1,2,3,4
In [2]: a==b
Out[2]: False

लेकिन, भाषा सी से विरासत में मिली, पायथन गैर शून्य पूर्णांक के तार्किक मान को सही मानती है।

In [11]: if 3:
    ...:     print ("yey")
    ...:
yey

अब, पायथन उस तर्क पर बनाता है और आपको तर्क शाब्दिक का उपयोग करता है जैसे कि या पूर्णांक पर, और इसी तरह

In [9]: False or 3
Out[9]: 3

आखिरकार

In [4]: a==b or c or d
Out[4]: 3

इसे लिखने का उचित तरीका होगा:

In [13]: if a in (b,c,d):
    ...:     print('Access granted')

सुरक्षा के लिए मैं आपको हार्ड कोड पासवर्ड नहीं सुझाता हूं।


1

में 3 स्थिति जाँचें हैं if name == "Kevin" or "Jon" or "Inbar":

  • नाम == "केविन"
  • "जॉन"
  • "बार में"

और यह यदि कथन के बराबर है

if name == "Kevin":
    print("Access granted.")
elif "Jon":
    print("Access granted.")
elif "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

जबसे elif "Jon" हमेशा सही रहेगा, इसलिए किसी भी उपयोगकर्ता तक पहुंच प्रदान की जाती है

उपाय


आप नीचे किसी भी एक विधि का उपयोग कर सकते हैं

तेज

if name in ["Kevin", "Jon", "Inbar"]:
    print("Access granted.")
else:
    print("Access denied.")

धीरे

if name == "Kevin" or name == "Jon" or name == "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

धीमा + अनावश्यक कोड

if name == "Kevin":
    print("Access granted.")
elif name == "Jon":
    print("Access granted.")
elif name == "Inbar":
    print("Access granted.")
else:
    print("Access denied.")
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.