[python] पायथन में सामान्य नुकसान



14 Answers

जब आपको सरणी की आबादी की आवश्यकता होती है तो आपको ऐसा कुछ लिखने का लुत्फ उठाया जा सकता है:

>>> a=[[1,2,3,4,5]]*4

और यह सुनिश्चित करें कि जब आप इसे देखेंगे तो यह आपको वह देगा जो आप उम्मीद करते हैं

>>> from pprint import pprint
>>> pprint(a)

[[1, 2, 3, 4, 5],
 [1, 2, 3, 4, 5],
 [1, 2, 3, 4, 5],
 [1, 2, 3, 4, 5]]

लेकिन उम्मीद नहीं है कि आपकी आबादी के तत्व अलग-अलग वस्तुएं हों:

>>> a[0][0] = 2
>>> pprint(a)

[[2, 2, 3, 4, 5],
 [2, 2, 3, 4, 5],
 [2, 2, 3, 4, 5],
 [2, 2, 3, 4, 5]]

जब तक आपको इसकी आवश्यकता नहीं है ...

एक कामकाज का उल्लेख करने लायक है:

a = [[1,2,3,4,5] for _ in range(4)]
Question

संभावित डुप्लिकेट:
पायथन 2.x गॉचा और लैंडमाइन्स

आज मैं कई वर्षों के बाद mutable डिफ़ॉल्ट तर्कों द्वारा फिर से काटा गया था। जब तक आवश्यक हो, मैं आमतौर पर म्यूटेबल डिफ़ॉल्ट तर्कों का उपयोग नहीं करता, लेकिन मुझे लगता है कि समय के साथ मैं इसके बारे में भूल गया। आज आवेदन में मैंने पीडीएफ पीढ़ी के फ़ंक्शन की तर्क सूची में tocElements = [] जोड़ा और अब "सामग्री की तालिका" "पीडीएफ जेनरेट" के प्रत्येक आमंत्रण के बाद लंबी और अधिक हो जाती है। :)

मुझे अपनी चीज़ों की सूची में और क्या जोड़ना चाहिए ताकि बचने के लिए?

  • हमेशा मॉड्यूल को उसी तरह आयात करें, उदाहरण के लिए from y import x और import x को विभिन्न मॉड्यूल के रूप में माना जाता है

  • सूचियों के स्थान पर रेंज का उपयोग न करें क्योंकि range() वैसे भी एक इटरेटर बन जाएगा, निम्नलिखित विफल हो जाएंगे:

    myIndexList = [0, 1, 3]
    isListSorted = myIndexList == range(3)  # will fail in 3.0
    isListSorted = myIndexList == list(range(3))  # will not
    

    Xrange के साथ गलती से किया जा सकता है :

    myIndexList == xrange(3)
    
  • कई अपवाद प्रकारों को पकड़ने से सावधान रहें:

    try:
        raise KeyError("hmm bug")
    except KeyError, TypeError:
        print TypeError
    

    यह प्रिंट करता है "हम्म बग", हालांकि यह एक बग नहीं है; ऐसा लगता है कि हम दोनों प्रकार के अपवादों को पकड़ रहे हैं, लेकिन इसके बजाय हम केवल KeyError को चर टाइपरर के रूप में पकड़ रहे हैं , इसके बजाय इसका उपयोग करें:

    try:
        raise KeyError("hmm bug")
    except (KeyError, TypeError):
        print TypeError
    



एक डिफ़ॉल्ट तर्क को म्यूट करना:

def foo(bar=[]):
    bar.append('baz')
    return bar

डिफ़ॉल्ट मान का मूल्यांकन केवल एक बार होता है, और हर बार फ़ंक्शन कहलाता नहीं है। foo() को बार-बार कॉल ['baz'] , ['baz', 'baz'] , ['baz', 'baz', 'baz'] , ...

यदि आप बार को म्यूट करना चाहते हैं तो ऐसा कुछ करें:

def foo(bar=None):
    if bar is None:
        bar = []

    bar.append('baz')
    return bar

या, यदि आप अंतिम होने के लिए तर्क पसंद करते हैं:

def foo(bar=[]):
    not_bar = bar[:]

    not_bar.append('baz')
    return not_bar



इनलाइन तर्क के लिए X and Y or Z का उपयोग करके मुझे खुद को प्रशिक्षित करने की एक बुरी आदत थी।

जब तक आप 100% हमेशा गारंटी नहीं दे सकते कि Y एक वास्तविक मूल्य होगा, भले ही आपका कोड 18 महीने के समय में बदल जाए, फिर भी आप कुछ अप्रत्याशित व्यवहार के लिए स्वयं को सेट अप करते हैं।

शुक्र है, बाद के संस्करणों में आप Y if X else Z उपयोग कर सकते हैं।




यदि आप सी ++ से आ रहे हैं, तो एहसास करें कि कक्षा परिभाषा में घोषित चर स्थिर हैं। आप init विधि में nonstatic सदस्यों को शुरू कर सकते हैं।

उदाहरण:

class MyClass:
  static_member = 1

  def __init__(self):
    self.non_static_member = random()



++n और --n सी या जावा पृष्ठभूमि से आने वाले लोगों द्वारा अपेक्षित काम नहीं कर सकता है।

++n सकारात्मक संख्या का सकारात्मक है, जो कि बस n

--n ऋणात्मक संख्या का नकारात्मक है, जो कि बस n




त्रुटि संदेशों में %s formatter का उपयोग करना। लगभग हर परिस्थिति में, %r का उपयोग किया जाना चाहिए।

उदाहरण के लिए, इस तरह कोड की कल्पना करें:

try:
    get_person(person)
except NoSuchPerson:
    logger.error("Person %s not found." %(person))

इस त्रुटि को मुद्रित किया गया:

ERROR: Person wolever not found.

यह कहना असंभव है कि क्या person चर स्ट्रिंग "wolever" , यूनिकोड स्ट्रिंग u"wolever" या Person क्लास का एक उदाहरण है (जिसे def __str__(self): return self.name परिभाषित किया गया है जिसे def __str__(self): return self.name )। जबकि, अगर %r का उपयोग किया गया था, तो तीन अलग-अलग त्रुटि संदेश होंगे:

...
logger.error("Person %r not found." %(person))

अधिक उपयोगी त्रुटियों का उत्पादन करेंगे:

ERROR: Person 'wolever' not found.
ERROR: Person u'wolever' not found.
ERROR: Person  not found.

इसके लिए एक और अच्छा कारण यह है कि पथ कॉपी / पेस्ट करने के लिए बहुत आसान हैं। कल्पना कीजिए:

try:
    stuff = open(path).read()
except IOError:
    logger.error("Could not open %s" %(path))

यदि path some path/with 'strange' "characters" , तो त्रुटि संदेश होगा:

ERROR: Could not open some path/with 'strange' "characters"

जो एक शेल में कॉपी / पेस्ट करने के लिए दृश्यात्मक पार्स और हार्ड करना मुश्किल है।

जबकि, अगर %r का उपयोग किया जाता है, तो त्रुटि होगी:

ERROR: Could not open 'some path/with \'strange\' "characters"'

दृश्यमान रूप से पार्स करना आसान है, प्रतिलिपि बनाना आसान है, सब कुछ बेहतर है।




import this    

सुंदर बदसूरत से बेहतर है।
स्पष्ट से स्पष्ट स्पष्ट है।
सरल जटिल से बेहतर है।
परिसर जटिल से बेहतर है।
फ्लैट नेस्टेड से बेहतर है।
स्पैस घने से बेहतर है।
पठनीयता की गणना करता है।
नियमों को तोड़ने के लिए विशेष मामले पर्याप्त नहीं हैं।
हालांकि व्यावहारिकता शुद्धता धड़कता है।
त्रुटियों को चुपचाप कभी नहीं गुजरना चाहिए।
जब तक स्पष्ट रूप से चुप नहीं किया जाता है।
अस्पष्टता के सामने, अनुमान लगाने के लिए प्रलोभन मना कर दिया।
एक होना चाहिए - और अधिमानतः इसे करने का एकमात्र तरीका।
यद्यपि वह तब तक स्पष्ट नहीं हो सकता जब तक कि आप डच न हों।
अब कभी भी बेहतर नहीं है।
हालांकि अभी से कभी भी बेहतर नहीं होता है।
अगर कार्यान्वयन को समझाना मुश्किल है, तो यह एक बुरा विचार है।
अगर कार्यान्वयन को समझाना आसान है, तो यह एक अच्छा विचार हो सकता है।
नेमस्पेस एक महान विचार है - चलो उनमें से अधिक करते हैं!

import not_this

बदसूरत कोड लिखें।
निहित कोड लिखें।
जटिल कोड लिखें।
नेस्टेड कोड लिखें।
घने कोड लिखें।
अपठनीय कोड लिखें।
विशेष मामलों को लिखें।
शुद्धता के लिए प्रयास करें।
त्रुटियों और अपवादों को अनदेखा करें।
रिलीज से पहले इष्टतम कोड लिखें।
प्रत्येक कार्यान्वयन को फ्लोचार्ट की आवश्यकता होती है।
नामस्थान का उपयोग न करें।




आश्चर्यचकित है कि किसी ने यह नहीं कहा:

इंडेंट करते समय टैब और रिक्त स्थान मिलाएं।

वास्तव में, यह एक हत्यारा है। मुझ पर विश्वास करो। विशेष रूप से , अगर यह चलता है।




कभी भी मान लें कि बहु-थ्रेडेड पायथन एप्लिकेशन और एक एसएमपी सक्षम मशीन (उदाहरण के लिए एक बहु-कोर सीपीयू से लैस) आपको अपने आवेदन में वास्तविक समांतरता पेश करने का लाभ देगा। सबसे अधिक संभावना यह जीआईएल (ग्लोबल इंटरप्रेटर लॉक) की वजह से नहीं होगी जो आपके आवेदन को बाइट-कोड दुभाषिया स्तर पर सिंक्रनाइज़ करता है।

सीपीआई में समवर्ती कोड डालने या रैपर के माध्यम से कई प्रक्रियाओं (थ्रेड के बजाए) का उपयोग करके एसएमपी का लाभ लेने जैसे कुछ कामकाज हैं (उदाहरण के लिए http://www.parallelpython.org पर उपलब्ध एक) लेकिन यदि कोई पाइथन में वास्तविक बहु-थ्रेडिंग की आवश्यकता है, किसी को ज्योथन, आयरनपीथन आदि जैसी चीजों को देखना चाहिए (जीआईएल सीपीथॉन दुभाषिया की एक विशेषता है, इसलिए अन्य कार्यान्वयन प्रभावित नहीं होते हैं)।

पायथन 3000 एफएक्यू (आर्टिमा में उपलब्ध) के मुताबिक उपरोक्त अभी भी नवीनतम पायथन संस्करणों के लिए खड़ा है।




डिफ़ॉल्ट म्यूटेबल तर्क से कुछ हद तक संबंधित, एक खाली सूची उत्तीर्ण होने पर "अनुपलब्ध" केस परिणामों के लिए कोई कैसे अंतर करता है:

def func1(toc=None):
    if not toc:
        toc = []
    toc.append('bar')

def func2(toc=None):
    if toc is None:
        toc = []
    toc.append('bar')

def demo(toc, func):
    print func.__name__
    print '  before:', toc
    func(toc)
    print '  after:', toc

demo([], func1)
demo([], func2)

आउटपुट यहां है:

func1
  before: []
  after: []
func2
  before: []
  after: ['bar']



मानक पुस्तकालय में देखने से पहले अपना खुद का कोड रोलिंग। उदाहरण के लिए, इसे लिखना:

def repeat_list(items):
    while True:
        for item in items:
            yield item

जब आप इसका उपयोग कर सकते हैं:

from itertools import cycle

अक्सर अनदेखा मॉड्यूल के उदाहरण ( itertools अलावा) में शामिल हैं:

  • कमांड लाइन पार्सर्स बनाने के लिए optparse
  • कॉन्फ़िगरेशन फ़ाइलों को मानक तरीके से पढ़ने के लिए ConfigParser
  • अस्थायी फ़ाइलों को बनाने और प्रबंधित करने के लिए tempfile
  • पाइथन ऑब्जेक्ट्स को डिस्क पर संग्रहीत करने के लिए shelve , जब एक पूर्ण डेटाबेस डेटाबेस अधिक हो जाता है तो आसान होता है



Stdlib से एक के रूप में एक ही नाम के साथ एक स्थानीय मॉड्यूल बनाना। यह लगभग हमेशा दुर्घटना से किया जाता है (जैसा कि इस प्रश्न में बताया गया है), लेकिन आमतौर पर क्रिप्टिक त्रुटि संदेशों में परिणाम होता है।




सामान्य pitfall: डिफ़ॉल्ट तर्क का मूल्यांकन एक बार किया जाता है :

def x(a, l=[]):
    l.append(a)
    return l

print x(1)
print x(2)

प्रिंट:

[1]
[1, 2]

यानी आप हमेशा एक ही सूची प्राप्त करते हैं।




my_variable = <something>
...
my_varaible = f(my_variable)
...
use my_variable and thinking it contains the result from f, and not the initial value

पाइथन आपको किसी भी तरह से चेतावनी नहीं देगा कि दूसरे असाइनमेंट पर आपने वैरिएबल नाम गलत वर्तनी की है और एक नया बनाया है।




स्ट्रिंग मिलान / परिवर्तन के लिए पूर्ण नियमित अभिव्यक्ति दृष्टिकोण को re आयात करना और उपयोग करना, जब प्रत्येक सामान्य ऑपरेशन (जैसे पूंजीकरण, सरल मिलान / खोज) के लिए पूरी तरह से अच्छी स्ट्रिंग विधियां मौजूद होती हैं।




Related



Tags

python python