Python Language
आम नुकसान
खोज…
परिचय
अजगर एक ऐसी भाषा है जिसका मतलब बिना किसी अस्पष्टता और अप्रत्याशित व्यवहार के स्पष्ट और पठनीय है। दुर्भाग्य से, ये लक्ष्य सभी मामलों में प्राप्त करने योग्य नहीं हैं, और यही कारण है कि पाइथन के पास कुछ कोने वाले मामले हैं जहां यह उस चीज़ से अलग हो सकता है जो आप उम्मीद कर रहे थे।
यह खंड आपको कुछ मुद्दों को दिखाएगा, जिन्हें आप पायथन कोड लिखते समय सामना कर सकते हैं।
इस क्रम को बदलते हुए आप इससे अधिक परेशान हो रहे हैं
लूप के for
एक अनुक्रम पर पुनरावृत्ति होती है, इसलिए लूप के अंदर इस क्रम को बदलने से अप्रत्याशित परिणाम हो सकते हैं (विशेषकर तत्वों को जोड़ने या निकालने पर):
alist = [0, 1, 2]
for index, value in enumerate(alist):
alist.pop(index)
print(alist)
# Out: [1]
नोट: list.pop()
का उपयोग सूची से तत्वों को निकालने के लिए किया जा रहा है।
दूसरा तत्व हटाया नहीं गया था क्योंकि पुनरावृत्ति क्रम में सूचकांकों के माध्यम से जाती है। उपरोक्त लूप दो बार पुनरावृत्त करता है, निम्न परिणाम के साथ:
# Iteration #1
index = 0
alist = [0, 1, 2]
alist.pop(0) # removes '0'
# Iteration #2
index = 1
alist = [1, 2]
alist.pop(1) # removes '2'
# loop terminates, but alist is not empty:
alist = [1]
यह समस्या इसलिए पैदा होती है क्योंकि सूचकांक बढ़ने की दिशा में चलने के दौरान सूचकांक बदल रहे हैं। इस समस्या से बचने के लिए, आप पीछे की ओर लूप के माध्यम से पुनरावृति कर सकते हैं :
alist = [1,2,3,4,5,6,7]
for index, item in reversed(list(enumerate(alist))):
# delete all even items
if item % 2 == 0:
alist.pop(index)
print(alist)
# Out: [1, 3, 5, 7]
अंत में शुरू होने वाले लूप के माध्यम से पुनरावृत्ति करके, चूंकि आइटम हटा दिए जाते हैं (या जोड़ दिए जाते हैं), यह सूची में पहले से वस्तुओं के सूचकांक को प्रभावित नहीं करता है। तो यह उदाहरण उन सभी वस्तुओं को ठीक से हटा देगा जो कि alist
से भी हैं।
एक सूची में तत्वों को सम्मिलित या जोड़ते समय एक समान समस्या उत्पन्न होती है, जिसे आप इससे अधिक पुनरावृत्त होते हैं , जिसके परिणामस्वरूप एक अनंत लूप हो सकता है:
alist = [0, 1, 2]
for index, value in enumerate(alist):
# break to avoid infinite loop:
if index == 20:
break
alist.insert(index, 'a')
print(alist)
# Out (abbreviated): ['a', 'a', ..., 'a', 'a', 0, 1, 2]
break
स्थिति के बिना लूप 'a'
जब तक कि कंप्यूटर मेमोरी से बाहर नहीं चला जाता है और प्रोग्राम को जारी रखने की अनुमति है। इस तरह की स्थिति में, आमतौर पर एक नई सूची बनाना पसंद किया जाता है, और मूल सूची के माध्यम से लूप के रूप में नई सूची में आइटम जोड़ना होता है।
लूप के for
उपयोग करते समय, आप सूची तत्वों को प्लेसहोल्डर चर के साथ संशोधित नहीं कर सकते हैं :
alist = [1,2,3,4]
for item in alist:
if item % 2 == 0:
item = 'even'
print(alist)
# Out: [1,2,3,4]
उपरोक्त उदाहरण में, item
बदलना वास्तव में मूल सूची में कुछ भी नहीं बदलता है । आपको सूची अनुक्रमणिका ( alist[2]
) का उपयोग करने की आवश्यकता है, और इसके लिए enumerate()
अच्छी तरह से काम करता है:
alist = [1,2,3,4]
for index, item in enumerate(alist):
if item % 2 == 0:
alist[index] = 'even'
print(alist)
# Out: [1, 'even', 3, 'even']
एक while
पाश कुछ मामलों में एक बेहतर विकल्प हो सकता है:
यदि आप सूची में सभी आइटम हटाने जा रहे हैं:
zlist = [0, 1, 2]
while zlist:
print(zlist[0])
zlist.pop(0)
print('After: zlist =', zlist)
# Out: 0
# 1
# 2
# After: zlist = []
हालाँकि बस zlist
को रीसेट करने से समान परिणाम प्राप्त होगा;
zlist = []
उपरोक्त उदाहरण को एक निश्चित बिंदु के बाद बंद करने के लिए len()
के साथ जोड़ा जा सकता है, या सूची में सभी लेकिन x
आइटम को हटाने के लिए:
zlist = [0, 1, 2]
x = 1
while len(zlist) > x:
print(zlist[0])
zlist.pop(0)
print('After: zlist =', zlist)
# Out: 0
# 1
# After: zlist = [2]
या किसी निश्चित स्थिति को पूरा करने वाले तत्वों को हटाते हुए एक सूची के माध्यम से लूप करना (इस मामले में सभी तत्वों को हटाना)
zlist = [1,2,3,4,5]
i = 0
while i < len(zlist):
if zlist[i] % 2 == 0:
zlist.pop(i)
else:
i += 1
print(zlist)
# Out: [1, 3, 5]
ध्यान दें कि आप एक तत्व को हटाने के बाद i
वेतन वृद्धि नहीं करते हैं। zlist[i]
पर तत्व को हटाने से, अगले आइटम का सूचकांक एक से कम हो गया है, इसलिए अगले पुनरावृत्ति पर i
लिए समान मूल्य के साथ zlist[i]
जाँच करके, आप सूची में अगले आइटम की सही जाँच करेंगे ।
एक सूची से अवांछित वस्तुओं को हटाने के बारे में सोचने का एक विपरीत तरीका है, वांछित वस्तुओं को एक नई सूची में जोड़ना । निम्न उदाहरण उत्तरार्द्ध के लिए एक विकल्प है while
पाश उदाहरण:
zlist = [1,2,3,4,5]
z_temp = []
for item in zlist:
if item % 2 != 0:
z_temp.append(item)
zlist = z_temp
print(zlist)
# Out: [1, 3, 5]
यहां हम एक नई सूची में वांछित परिणामों की फ़नलिंग कर रहे हैं। फिर हम वैकल्पिक रूप से अस्थायी सूची को मूल चर पर फिर से असाइन कर सकते हैं।
सोचने की इस प्रवृत्ति के साथ, आप पायथन की सबसे सुरुचिपूर्ण और शक्तिशाली विशेषताओं, सूची समझ को आमंत्रित कर सकते हैं, जो पहले से चर्चा की गई सूची / सूचकांक उत्परिवर्तन विचारधारा से अस्थायी सूची और विचलन को समाप्त करता है।
zlist = [1,2,3,4,5]
[item for item in zlist if item % 2 != 0]
# Out: [1, 3, 5]
पारस्परिक डिफ़ॉल्ट तर्क
def foo(li=[]):
li.append(1)
print(li)
foo([2])
# Out: [2, 1]
foo([3])
# Out: [3, 1]
यह कोड अपेक्षा के अनुरूप व्यवहार करता है, लेकिन क्या होगा यदि हम एक तर्क पारित नहीं करते हैं?
foo()
# Out: [1] As expected...
foo()
# Out: [1, 1] Not as expected...
ऐसा इसलिए है क्योंकि फ़ंक्शन और विधियों के डिफ़ॉल्ट तर्क का मूल्यांकन रन टाइम के बजाय परिभाषा समय पर किया जाता है। इसलिए हमारे पास केवल li
सूची का एक ही उदाहरण है।
इसके चारों ओर जाने का तरीका डिफ़ॉल्ट तर्कों के लिए केवल अपरिवर्तनीय प्रकारों का उपयोग करना है:
def foo(li=None):
if not li:
li = []
li.append(1)
print(li)
foo()
# Out: [1]
foo()
# Out: [1]
हालांकि एक सुधार और यद्यपि if not li
False
तरीके से मूल्यांकन if not li
करते हैं, तो कई अन्य ऑब्जेक्ट शून्य लंबाई के अनुक्रम जैसे भी करते हैं। निम्नलिखित उदाहरण के तर्क अनपेक्षित परिणाम दे सकते हैं:
x = []
foo(li=x)
# Out: [1]
foo(li="")
# Out: [1]
foo(li=0)
# Out: [1]
मुहावरेदार दृष्टिकोण सीधे किसी None
वस्तु के खिलाफ तर्क की जांच करना है:
def foo(li=None):
if li is None:
li = []
li.append(1)
print(li)
foo()
# Out: [1]
सूची गुणा और सामान्य संदर्भ
एक नेस्टेड सूची संरचना बनाने के मामले पर विचार करके गुणा करें:
li = [[]] * 3
print(li)
# Out: [[], [], []]
पहली नज़र में हमें लगता है कि हमारे पास 3 अलग-अलग नेस्टेड सूची वाली सूची होगी। पहले 1
को जोड़ने की कोशिश करते हैं:
li[0].append(1)
print(li)
# Out: [[1], [1], [1]]
1
li
में सभी सूचियों से जुड़ गया।
कारण यह है कि है [[]] * 3
एक का निर्माण नहीं करता list
के 3 अलग अलग list
है। बल्कि, यह एक ही list
ऑब्जेक्ट के लिए 3 संदर्भ रखने वाली एक list
बनाता है। जैसे, जब हम li[0]
लिए li[0]
तो परिवर्तन li
सभी उप-तत्वों में दिखाई देता है। यह इसके बराबर है:
li = []
element = [[]]
li = element + element + element
print(li)
# Out: [[], [], []]
element.append(1)
print(li)
# Out: [[1], [1], [1]]
यदि हम id
का उपयोग करके निहित list
के मेमोरी पतों को प्रिंट करते हैं, तो इसे और पुष्टि की जा सकती है:
li = [[]] * 3
print([id(inner_list) for inner_list in li])
# Out: [6830760, 6830760, 6830760]
समाधान एक लूप के साथ आंतरिक सूची बनाने के लिए है:
li = [[] for _ in range(3)]
एक एकल list
बनाने और उसके बाद 3 संदर्भ बनाने के बजाय, अब हम 3 अलग-अलग सूचियाँ बनाते हैं। यह, फिर से, id
फ़ंक्शन का उपयोग करके सत्यापित किया जा सकता है:
print([id(inner_list) for inner_list in li])
# Out: [6331048, 6331528, 6331488]
आप भी ऐसा कर सकते हैं। यह प्रत्येक append
कॉल में एक नई खाली सूची बनाने का कारण बनता है।
>>> li = []
>>> li.append([])
>>> li.append([])
>>> li.append([])
>>> for k in li: print(id(k))
...
4315469256
4315564552
4315564808
अनुक्रम पर लूप का उपयोग न करें।
मत करो:
for i in range(len(tab)):
print(tab[i])
करें :
for elem in tab:
print(elem)
for
अधिकांश पुनरावृति कार्यों को स्वचालित करेगा।
यदि आपको वास्तव में सूचकांक और तत्व दोनों की आवश्यकता है, तो एन्यूमरेट का उपयोग करें ।
for i, elem in enumerate(tab):
print((i, elem))
ट्रू या गलत के खिलाफ जांच करने के लिए "==" का उपयोग करते समय सावधान रहें
if (var == True):
# this will execute if var is True or 1, 1.0, 1L
if (var != True):
# this will execute if var is neither True nor 1
if (var == False):
# this will execute if var is False or 0 (or 0.0, 0L, 0j)
if (var == None):
# only execute if var is None
if var:
# execute if var is a non-empty string/list/dictionary/tuple, non-0, etc
if not var:
# execute if var is "", {}, [], (), 0, None, etc.
if var is True:
# only execute if var is boolean True, not 1
if var is False:
# only execute if var is boolean False, not 0
if var is None:
# same as var == None
यदि आप कर सकते हैं तो जांच न करें, बस इसे करें और त्रुटि को संभालें
पाइथोनिस्टस आमतौर पर कहते हैं "अनुमति की तुलना में माफी मांगना आसान है"।
मत करो:
if os.path.isfile(file_path):
file = open(file_path)
else:
# do something
कर:
try:
file = open(file_path)
except OSError as e:
# do something
या Python 2.6+
साथ भी बेहतर:
with open(file_path) as file:
यह बहुत बेहतर है क्योंकि यह बहुत अधिक सामान्य है। आप try/except
कर सकते हैं try/except
लगभग कुछ भी try/except
। आपको इसे रोकने के लिए क्या करना है, इसकी परवाह करने की जरूरत नहीं है, बस उस त्रुटि की परवाह करें जो आप जोखिम में डाल रहे हैं।
प्रकार के खिलाफ जाँच न करें
पायथन गतिशील रूप से टाइप किया गया है, इसलिए प्रकार की जाँच करने से आप लचीलापन खो देते हैं। इसके बजाय, व्यवहार की जाँच करके बतख टाइपिंग का उपयोग करें । यदि आप किसी फ़ंक्शन में स्ट्रिंग की अपेक्षा करते हैं, तो किसी भी ऑब्जेक्ट को स्ट्रिंग में बदलने के लिए str()
का उपयोग करें। यदि आप एक सूची की अपेक्षा करते हैं, तो list()
के किसी भी चलने योग्य को बदलने के लिए list()
का उपयोग करें।
मत करो:
def foo(name):
if isinstance(name, str):
print(name.lower())
def bar(listing):
if isinstance(listing, list):
listing.extend((1, 2, 3))
return ", ".join(listing)
कर:
def foo(name) :
print(str(name).lower())
def bar(listing) :
l = list(listing)
l.extend((1, 2, 3))
return ", ".join(l)
अंतिम तरीके का उपयोग करके, foo
किसी भी वस्तु को स्वीकार करेगा। bar
स्ट्रिंग्स, ट्यूपल्स, सेट्स, सूचियों और बहुत कुछ स्वीकार करेगा। सस्ते DRY।
रिक्त स्थान और टैब न मिलाएं
पहले माता-पिता के रूप में ऑब्जेक्ट का उपयोग करें
यह मुश्किल है, लेकिन यह आपके कार्यक्रम के बढ़ने पर आपको काटेगा। Python 2.x
में पुराने और नए वर्ग हैं। पुराने हैं, ठीक है, पुराने हैं। उनके पास कुछ विशेषताओं की कमी है, और विरासत के साथ अजीब व्यवहार हो सकता है। प्रयोग करने योग्य होने के लिए, आपकी किसी भी कक्षा को "नई शैली" का होना चाहिए। ऐसा करने के लिए, इसे object
से इनहेरिट करें।
मत करो:
class Father:
pass
class Child(Father):
pass
कर:
class Father(object):
pass
class Child(Father):
pass
Python 3.x
सभी वर्ग नई शैली के हैं, इसलिए आपको ऐसा करने की आवश्यकता नहीं है।
Init विधि के बाहर वर्ग विशेषताओं को इनिशियलाइज़ न करें
अन्य भाषाओं से आने वाले लोगों को यह लुभावना लगता है क्योंकि आप जावा या पीएचपी में ऐसा करते हैं। आप वर्ग का नाम लिखते हैं, फिर अपनी विशेषताओं को सूचीबद्ध करते हैं और उन्हें एक डिफ़ॉल्ट मान देते हैं। यह पायथन में काम करने लगता है, हालांकि, यह आपके सोचने के तरीके पर काम नहीं करता है। ऐसा करने से क्लास की विशेषताओं (स्थैतिक विशेषताओं) को सेटअप किया जाएगा, फिर जब आप ऑब्जेक्ट विशेषता प्राप्त करने का प्रयास करेंगे, तो यह आपको इसका मूल्य देगा जब तक कि यह खाली न हो। उस स्थिति में यह वर्ग के गुणों को लौटाएगा। इसका तात्पर्य दो बड़े खतरों से है:
यदि वर्ग विशेषता को बदल दिया जाता है, तो प्रारंभिक मूल्य बदल जाता है।
यदि आप एक परिवर्तनशील वस्तु को डिफ़ॉल्ट मान के रूप में सेट करते हैं, तो आपको उसी वस्तु को उदाहरणों में साझा किया जाएगा।
(जब तक आप स्थिर नहीं चाहते) न करें:
class Car(object):
color = "red"
wheels = [Wheel(), Wheel(), Wheel(), Wheel()]
कर :
class Car(object):
def __init__(self):
self.color = "red"
self.wheels = [Wheel(), Wheel(), Wheel(), Wheel()]
पूर्णांक और स्ट्रिंग पहचान
पायथन अपने दोहराया निर्माण से अनावश्यक ओवरहेड को कम करने के लिए पूर्णांकों की एक श्रृंखला के लिए आंतरिक कैशिंग का उपयोग करता है।
वास्तव में, यह पूर्णांक पहचान की तुलना करते समय भ्रामक व्यवहार को जन्म दे सकता है:
>>> -8 is (-7 - 1)
False
>>> -3 is (-2 - 1)
True
और, एक और उदाहरण का उपयोग कर:
>>> (255 + 1) is (255 + 1)
True
>>> (256 + 1) is (256 + 1)
False
रुको क्या?
हम देख सकते हैं कि पहचान आपरेशन is
पैदावार True
कुछ पूर्णांक (के लिए -3
, 256
), लेकिन कोई दूसरों (के लिए -8
, 257
)।
अधिक विशिष्ट होने के लिए, [-5, 256]
रेंज में पूर्णांक इंटरप्रेटर स्टार्टअप के दौरान आंतरिक रूप से कैश किए जाते हैं और केवल एक बार बनाए जाते हैं। जैसे, वे समान हैं और साथ अपनी पहचान की तुलना is
पैदावार True
; इस श्रेणी के बाहर पूर्णांक (आमतौर पर) ऑन-द-फ्लाई बनाए जाते हैं और उनकी पहचान False
तुलना होती है।
यह परीक्षण के लिए एक सामान्य सीमा है, लेकिन अक्सर पर्याप्त होता है, कोड विकास में पूरी तरह से काम करने के बाद कोई स्पष्ट कारण के साथ बाद के मंचन प्रक्रिया (या बदतर - उत्पादन) में विफल रहता है।
समाधान समानता (का उपयोग करते हुए हमेशा तुलना मूल्यों के लिए है ==
) ऑपरेटर और नहीं पहचान ( is
) ऑपरेटर।
पायथन आमतौर पर इस्तेमाल किए जाने वाले तार के संदर्भ भी रखता है और इसी तरह के भ्रामक व्यवहार का परिणाम तब हो सकता है जब पहचान की तुलना (यानी का उपयोग कर रहा is
)।
>>> 'python' is 'py' + 'thon'
True
स्ट्रिंग 'python'
का आमतौर पर उपयोग किया जाता है, इसलिए पायथन की एक वस्तु है जो स्ट्रिंग 'python'
सभी संदर्भों का उपयोग करती है।
असामान्य तार के लिए, पहचान की तुलना तब भी विफल रहती है जब तार बराबर होते हैं।
>>> 'this is not a common string' is 'this is not' + ' a common string'
False
>>> 'this is not a common string' == 'this is not' + ' a common string'
True
इसलिए, इंटेगर के लिए नियम की तरह, हमेशा समानता ( ==
) ऑपरेटर का उपयोग करके स्ट्रिंग मानों की तुलना करें , न कि पहचान ( is
) ऑपरेटर।
अंतरंग शाब्दिक विशेषताओं तक पहुँचना
आपने सुना होगा कि पायथन में सब कुछ एक वस्तु है, यहां तक कि शाब्दिक भी। इसका मतलब है, उदाहरण के लिए, 7
एक वस्तु के रूप में अच्छी तरह से है, जिसका अर्थ है कि इसमें विशेषताएं हैं। उदाहरण के लिए, इनमें से एक विशेषता bit_length
। यह उस मूल्य का प्रतिनिधित्व करने के लिए आवश्यक बिट्स की मात्रा देता है जिसे इसे कहा जाता है।
x = 7
x.bit_length()
# Out: 3
देखकर ऊपर कोड काम करता है, तो आप सहज सोच सकते हैं कि 7.bit_length()
के रूप में अच्छी तरह से काम करेगा, केवल पता लगाने के लिए यह एक को जन्म देती है SyntaxError
। क्यों? क्योंकि दुभाषिया को एक विशेषता पहुंच और एक अस्थायी संख्या (उदाहरण के लिए 7.2
या 7.bit_length()
) के बीच अंतर करने की आवश्यकता होती है। यह नहीं हो सकता है, और इसीलिए अपवाद को उठाया जाता है।
एक int
शाब्दिक विशेषताओं को एक्सेस करने के कुछ तरीके हैं:
# parenthesis
(7).bit_length()
# a space
7 .bit_length()
दो डॉट्स का उपयोग करना (जैसे 7..bit_length()
) इस मामले में काम नहीं करता है, क्योंकि यह एक float
शाब्दिक बनाता है और फ्लोट्स में bit_length()
विधि नहीं है।
यह समस्या तब नहीं होती है जब इंटरपर के बाद से float
शाब्दिक विशेषताओं को एक्सेस करना "स्मार्ट" होता है, यह जानने के लिए पर्याप्त है कि float
शाब्दिक में दो नहीं हो सकते .
, उदाहरण के लिए:
7.2.as_integer_ratio()
# Out: (8106479329266893, 1125899906842624)
संचालक या संचालक की जंजीर
किसी भी समानता समानता की जाँच करते समय:
if a == 3 or b == 3 or c == 3:
यह संक्षिप्त करने के लिए आकर्षक है
if a or b or c == 3: # Wrong
ये गलत है; or
ऑपरेटर के पास ==
से कम पूर्वता है, इसलिए अभिव्यक्ति का मूल्यांकन इस तरह किया जाएगा जैसे if (a) or (b) or (c == 3):
:। सही तरीका स्पष्ट रूप से सभी स्थितियों की जाँच कर रहा है:
if a == 3 or b == 3 or c == 3: # Right Way
वैकल्पिक रूप से, निर्मित any()
फ़ंक्शन का उपयोग जंजीरों or
ऑपरेटरों के स्थान पर किया जा सकता है:
if any([a == 3, b == 3, c == 3]): # Right
या, इसे और अधिक कुशल बनाने के लिए:
if any(x == 3 for x in (a, b, c)): # Right
या, इसे छोटा करने के लिए:
if 3 in (a, b, c): # Right
यहाँ, हम का उपयोग in
परीक्षण करने के लिए ऑपरेटर अगर मूल्य एक टपल मूल्यों हम के खिलाफ तुलना करना चाहते हैं में मौजूद है।
इसी तरह लिखना गलत है
if a == 1 or 2 or 3:
जो के रूप में लिखा जाना चाहिए
if a in (1, 2, 3):
sys.argv [0] फ़ाइल का नाम निष्पादित किया जा रहा है
sys.argv[0]
का पहला तत्व sys.argv[0]
अजगर फ़ाइल को निष्पादित करने का नाम है। शेष तत्व स्क्रिप्ट तर्क हैं।
# script.py
import sys
print(sys.argv[0])
print(sys.argv)
$ python script.py
=> script.py
=> ['script.py']
$ python script.py fizz
=> script.py
=> ['script.py', 'fizz']
$ python script.py fizz buzz
=> script.py
=> ['script.py', 'fizz', 'buzz']
शब्दकोश अनियंत्रित हैं
आप उदाहरण के लिए, जैसे कि C ++ std::map
, के द्वारा पायथन डिक्शनरी को हल करने की उम्मीद कर सकते हैं, लेकिन ऐसा नहीं है:
myDict = {'first': 1, 'second': 2, 'third': 3}
print(myDict)
# Out: {'first': 1, 'second': 2, 'third': 3}
print([k for k in myDict])
# Out: ['second', 'third', 'first']
अजगर के पास कोई अंतर्निहित वर्ग नहीं होता है जो कुंजी द्वारा स्वचालित रूप से अपने तत्वों को सॉर्ट करता है।
हालाँकि, यदि छँटाई करना आवश्यक नहीं है, और आप चाहते हैं कि आपका शब्दकोश इसके प्रमुख / मूल्य जोड़े के सम्मिलन के क्रम को याद रखे, तो आप collections.OrderedDict
उपयोग कर सकते हैं। क्रमबद्ध विवरण:
from collections import OrderedDict
oDict = OrderedDict([('first', 1), ('second', 2), ('third', 3)])
print([k for k in oDict])
# Out: ['first', 'second', 'third']
ध्यान रखें कि OrderedDict
डिक्शनरी को एक मानक डिक्शनरी के साथ शुरू करना किसी भी तरह से आपके लिए डिक्शनरी नहीं होगा। यह सब जो संरचना करता है वह कुंजी सम्मिलन के क्रम को संरक्षित करना है।
उनकी स्मृति खपत में सुधार के लिए शब्दकोशों का कार्यान्वयन पायथन 3.6 में बदल दिया गया था। इस नए कार्यान्वयन का एक साइड इफेक्ट यह है कि यह एक फ़ंक्शन को दिए गए कीवर्ड तर्कों के क्रम को भी बनाए रखता है:
def func(**kw): print(kw.keys())
func(a=1, b=2, c=3, d=4, e=5)
dict_keys(['a', 'b', 'c', 'd', 'e']) # expected order
कैविएट : सावधान रहें कि " इस नए कार्यान्वयन का आदेश-संरक्षण पहलू एक कार्यान्वयन विवरण माना जाता है और इस पर भरोसा नहीं किया जाना चाहिए " , क्योंकि यह भविष्य में बदल सकता है।
ग्लोबल इंटरप्रेटर लॉक (GIL) और अवरुद्ध धागे
पाइथन की GIL के बारे में बहुत कुछ लिखा गया है । बहु-थ्रेडेड (मल्टीप्रोसेस के साथ भ्रमित नहीं होना) अनुप्रयोगों के साथ काम करते समय यह कभी-कभी भ्रम पैदा कर सकता है।
यहाँ एक उदाहरण है:
import math
from threading import Thread
def calc_fact(num):
math.factorial(num)
num = 600000
t = Thread(target=calc_fact, daemon=True, args=[num])
print("About to calculate: {}!".format(num))
t.start()
print("Calculating...")
t.join()
print("Calculated")
आपको Calculating...
करने की उम्मीद होगी Calculating...
थ्रेड शुरू होने के तुरंत बाद प्रिंट आउट, हम चाहते थे कि गणना एक नए धागे में हो! लेकिन वास्तविकता में, आप देखते हैं कि गणना पूरी होने के बाद इसे प्रिंट किया जाता है। ऐसा इसलिए है क्योंकि नया धागा C फ़ंक्शन ( math.factorial
) पर निर्भर करता है जो GIL को लॉक करेगा जबकि यह निष्पादित होता है।
इसके आसपास कुछ तरीके हैं। सबसे पहले देशी पायथन में अपने फैक्टरियल फ़ंक्शन को लागू करना है। यह आपके लूप के अंदर रहते हुए मुख्य थ्रेड को नियंत्रण हथियाने की अनुमति देगा। नकारात्मक पक्ष यह है कि यह समाधान बहुत धीमा होगा, क्योंकि हम अब सी फ़ंक्शन का उपयोग नहीं कर रहे हैं।
def calc_fact(num):
""" A slow version of factorial in native Python """
res = 1
while num >= 1:
res = res * num
num -= 1
return res
अपने निष्पादन को शुरू करने से पहले आप कुछ समय के लिए sleep
भी सकते हैं। नोट: यह वास्तव में आपके प्रोग्राम को C फ़ंक्शन के अंदर होने वाली संगणना को बाधित करने की अनुमति नहीं देगा, लेकिन यह आपके मुख्य सूत्र को स्पॉन के बाद जारी रखने की अनुमति देगा, जो कि आप उम्मीद कर सकते हैं।
def calc_fact(num):
sleep(0.001)
math.factorial(num)
सूची समझ में और छोरों के लिए चर लीक
निम्नलिखित सूची समझ पर विचार करें
i = 0
a = [i for i in range(3)]
print(i) # Outputs 2
यह केवल पायथन 2 में होता है, इस तथ्य के कारण कि सूची की समझ "लीक" को लूप नियंत्रण चर को आसपास के दायरे ( स्रोत ) में ले जाती है। इस व्यवहार से हार्ड-टू-फाइ बग्स हो सकते हैं और इसे पायथन 3 में तय किया गया है ।
i = 0
a = [i for i in range(3)]
print(i) # Outputs 0
इसी तरह, लूप के लिए अपने चलना चर के लिए कोई निजी गुंजाइश नहीं है
i = 0
for i in range(3):
pass
print(i) # Outputs 2
इस तरह का व्यवहार पायथन 2 और पायथन 3 दोनों में होता है।
लीक चर के साथ मुद्दों से बचने के लिए, सूची समझ में नए चर का उपयोग करें और उपयुक्त के रूप में छोरों के लिए।
मल्टीपल रिटर्न
Xyz दो मान देता है
def xyz():
return a, b
Xyz स्टोर कोड को एक चर में परिणाम देता है, मान लेता है कि xyz केवल एक मान देता है:
t = xyz()
t
का मान वास्तव में एक tuple (a, b) है इसलिए t
पर कोई भी कार्य यह मान लेना कि tuple नहीं है tuples के बारे में अप्रत्याशित त्रुटि के साथ कोड में गहरी विफल हो सकती है।
TypeError: tuple परिभाषित नहीं करता है ... विधि
यह करना होगा:
a, b = xyz()
शुरुआती लोगों को केवल टपल त्रुटि संदेश पढ़ने से इस संदेश का कारण खोजने में परेशानी होगी!
पायथोनिक JSON कुंजियाँ
my_var = 'bla';
api_key = 'key';
...lots of code here...
params = {"language": "en", my_var: api_key}
यदि आप जावास्क्रिप्ट के लिए उपयोग किए जाते हैं, तो पायथन शब्दकोशों में चर मूल्यांकन वह नहीं होगा जो आप यह होने की उम्मीद करते हैं। जावास्क्रिप्ट में यह बयान में परिणाम होगा params
वस्तु इस प्रकार है:
{
"language": "en",
"my_var": "key"
}
हालाँकि, पायथन में, यह निम्नलिखित शब्दकोश में परिणाम देगा:
{
"language": "en",
"bla": "key"
}
my_var
का मूल्यांकन किया जाता है और इसका मान कुंजी के रूप में उपयोग किया जाता है।