जाँचें कि ऑब्जेक्ट पायथन में फ़ाइल-जैसा है


93

फ़ाइल की तरह की वस्तुएं पायथन में ऑब्जेक्ट हैं जो एक वास्तविक फ़ाइल की तरह व्यवहार करते हैं, उदाहरण के लिए एक रीड () और एक लेखन विधि () है, लेकिन एक अलग कार्यान्वयन है। यह डक टंकण अवधारणा का बोध और बोध है ।

हर जगह एक फ़ाइल जैसी वस्तु की अनुमति देने के लिए अच्छा अभ्यास माना जाता है, जहां एक फ़ाइल की उम्मीद की जाती है ताकि एक वास्तविक फ़ाइल के बजाय एक स्ट्रिंग या सॉकेट ऑब्जेक्ट का उपयोग किया जा सके। तो इस तरह से चेक करना बुरा है:

if not isinstance(fp, file):
   raise something

यह जांचने का सबसे अच्छा तरीका है कि क्या कोई वस्तु (उदाहरण के लिए एक विधि का पैरामीटर) "फाइल-लाइक" है?

जवाबों:


45

आम तौर पर आपके कोड में इस तरह की जाँच करना अच्छा नहीं है जब तक कि आपकी विशेष आवश्यकताएं न हों।

पायथन में टाइपिंग गतिशील है, आपको यह जांचने की आवश्यकता क्यों है कि क्या ऑब्जेक्ट फ़ाइल की तरह है, बजाय इसके उपयोग करने के जैसे कि यह एक फ़ाइल थी और परिणामी त्रुटि को संभाल रही थी?

कोई भी चेक जो आप कर सकते हैं, वैसे भी रनटाइम पर होने वाला है, इसलिए ऐसा कुछ करना if not hasattr(fp, 'read')और कुछ अपवाद उठाना केवल कॉल करने fp.read()और परिणामस्वरूप मौजूद त्रुटि को संभालने की तुलना में थोड़ी अधिक उपयोगिता प्रदान करता है यदि विधि मौजूद नहीं है।


whyऑपरेटरों के बारे में क्या पसंद है __add__, __lshift__या __or__कस्टम कक्षाओं में? (फ़ाइल ऑब्जेक्ट और एपीआई: docs.python.org/glossary.html#term-file-object )
n611x007 12

@naxa: तो क्या वास्तव में उन ऑपरेटरों के बारे में?
मार्टीन्यू

32
अक्सर यह कोशिश करता है कि मैं काम करूं लेकिन मैं पायथोनिक मैक्सिम नहीं खरीदता हूं कि अगर यह पायथन में करना मुश्किल है तो यह गलत है। कल्पना कीजिए कि आप एक वस्तु को पास कर चुके हैं और 10 अलग-अलग चीजें हैं जो आप उस वस्तु के साथ उसके प्रकार के आधार पर कर सकते हैं। आप प्रत्येक संभावना को आजमाने और त्रुटि को संभालने के लिए नहीं जा रहे हैं जब तक कि आप इसे सही तरीके से प्राप्त न करें। यह पूरी तरह से अक्षम होगा। आपको यह पूछने की आवश्यकता नहीं है कि यह किस प्रकार का है, लेकिन आपको यह पूछने में सक्षम होने की आवश्यकता है कि क्या यह ऑब्जेक्ट इंटरफ़ेस एक्स को लागू करता है।
jcoffland

31
तथ्य यह है कि अजगर संग्रह पुस्तकालय प्रदान करता है जिसे "इंटरफ़ेस प्रकार" कहा जा सकता है (उदाहरण के लिए, अनुक्रम) इस तथ्य से बात करता है कि यह अक्सर उपयोगी होता है, यहां तक ​​कि अजगर में भी। सामान्य तौर पर, जब कोई पूछता है कि "फू कैसे करें", "डू फू" उच्च संतोषजनक उत्तर नहीं है।
एडम

1
विशेषता को सभी प्रकार के कारणों से उठाया जा सकता है, जिनका उस वस्तु से कोई लेना-देना नहीं है, जो वस्तु आपके लिए आवश्यक इंटरफेस का समर्थन करती है। हैपेट्रा को IOBase से प्राप्त न होने वाली फ़िल्टरों के लिए आवश्यक है
एरिक

74

3.1+ के लिए, निम्न में से एक:

isinstance(something, io.TextIOBase)
isinstance(something, io.BufferedIOBase)
isinstance(something, io.RawIOBase)
isinstance(something, io.IOBase)

2.x के लिए, "फ़ाइल जैसी वस्तु" बहुत ही अस्पष्ट है, जिसके लिए जांच की जा सकती है, लेकिन आप जिस भी फ़ंक्शन (कार्य) के साथ काम कर रहे हैं, उसके लिए प्रलेखन उम्मीद के साथ आपको बताएगा कि उन्हें वास्तव में क्या चाहिए; यदि नहीं, तो कोड पढ़ें।


जैसा कि अन्य उत्तर बताते हैं, पूछने वाली पहली बात यह है कि आप वास्तव में क्या जाँच रहे हैं। आमतौर पर, ईएएफपी पर्याप्त और अधिक मुहावरेदार है।

शब्दकोष कहते हैं, "फ़ाइल जैसी वस्तु" जो अंततः यह तीन में से एक का एक उदाहरण है जिसका अर्थ है "फ़ाइल वस्तु", के लिए एक पर्याय है सार आधार वर्ग में परिभाषित मॉड्यूल जो खुद के सभी उपवर्गों कर रहे हैं, । तो, जांच करने का तरीका बिल्कुल ऊपर दिखाया गया है।ioIOBase

(हालाँकि, जाँच IOBaseकरना बहुत उपयोगी नहीं है। क्या आप एक ऐसे मामले की कल्पना कर सकते हैं जहाँ आपको एक वास्तविक फ़ाइल-जैसे read(size)किसी एक-तर्क फ़ंक्शन readसे अलग करने की आवश्यकता है, जिसका नाम फ़ाइल-जैसा नहीं है, बिना पाठ फ़ाइलों और कच्चे के बीच अंतर करने की आवश्यकता के बिना बाइनरी फाइलें? तो, वास्तव में, आप लगभग हमेशा जांचना चाहते हैं, उदाहरण के लिए, "एक पाठ फ़ाइल ऑब्जेक्ट" है, न कि "एक फ़ाइल की तरह ऑब्जेक्ट" है।)


2.x के लिए, जबकि ioमॉड्यूल 2.6+ के बाद से मौजूद है, बिल्ट-इन फ़ाइल ऑब्जेक्ट्स ioकक्षाओं के उदाहरण नहीं हैं, न ही स्टडीलिब में कोई फ़ाइल जैसी ऑब्जेक्ट्स हैं, और न ही अधिकांश तृतीय-पक्ष फ़ाइल-जैसी ऑब्जेक्ट्स हैं मुठभेड़ की संभावना है। "फ़ाइल-जैसा ऑब्जेक्ट" का अर्थ की कोई आधिकारिक परिभाषा नहीं थी; यह सिर्फ "एक बिलियन फाइल ऑब्जेक्ट की तरह कुछ है ", और विभिन्न कार्यों का अर्थ "जैसे" द्वारा अलग-अलग चीजें हैं। ऐसे कार्यों का दस्तावेज होना चाहिए कि उनका क्या मतलब है; यदि वे नहीं करते हैं, तो आपको कोड देखना होगा।

हालांकि, सबसे आम अर्थ "हैं read(size)", "है read()", या "तार का एक पुनरावृत्ति है", लेकिन कुछ पुराने पुस्तकालयों में readlineसे एक के बजाय उम्मीद कर सकते हैं, कुछ पुस्तकालय close()आपको उन्हें देने वाली फाइलें पसंद करते हैं, कुछ उम्मीद करेंगे कि यदि filenoतब मौजूद है अन्य कार्यक्षमता उपलब्ध है, आदि और इसी तरह write(buf)(हालांकि उस दिशा में बहुत कम विकल्प हैं)।


1
अंत में, कोई इसे वास्तविक रख रहा है।
एंथनी रटलेज

16
एकमात्र उपयोगी उत्तर। क्यों StackOverflowers आगे बढ़ रहे हैं "आप जो करना चाह रहे हैं उसे करना बंद करें, क्योंकि मैं बेहतर जानता हूं ... और PEP 8, EAFP, और सामान!" पोस्ट मेरी नाजुक पवित्रता से परे हैं। ( शायद Cululhu जानता है? )
सेसिल करी

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

1
इसे बेहतर इंजीनियरिंग के रूप में देखा जा सकता है और मैं इसे व्यक्तिगत रूप से पसंद करूंगा, लेकिन काम नहीं कर सकता। यह आमतौर पर आवश्यक नहीं है कि फ़ाइल जैसी वस्तुएं विरासत में मिली हैं IOBase। उदाहरण के लिए पाइस्टेस्ट फिक्स्चर आपको देते हैं _pytest.capture.EncodedFileजो किसी भी चीज़ से विरासत में नहीं मिलता है।
टॉम गेवेनिक

46

जैसा कि दूसरों ने कहा है कि आपको आम तौर पर इस तरह की जाँच से बचना चाहिए। एक अपवाद तब होता है जब वस्तु वैध रूप से भिन्न प्रकार की हो सकती है और आप प्रकार के आधार पर अलग व्यवहार चाहते हैं। ईएएफपी विधि हमेशा यहां काम नहीं करती है क्योंकि एक वस्तु एक से अधिक प्रकार के बतख की तरह दिख सकती है!

उदाहरण के लिए एक इनिलाइज़र अपनी कक्षा की एक फ़ाइल, स्ट्रिंग या उदाहरण ले सकता है। फिर आपके पास कोड हो सकता है जैसे:

class A(object):
    def __init__(self, f):
        if isinstance(f, A):
            # Just make a copy.
        elif isinstance(f, file):
            # initialise from the file
        else:
            # treat f as a string

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

एक साइड नोट के रूप में, आप पाइथन 3 में उसी तरह से फाइल की जांच नहीं कर सकते हैं। आपको isinstance(f, io.IOBase)इसके बदले कुछ चाहिए होगा।


28

यहां प्रभावी प्रतिमान ईएएफपी है: अनुमति की तुलना में माफी मांगना आसान है। आगे बढ़ो और फ़ाइल इंटरफ़ेस का उपयोग करें, फिर परिणामी अपवाद को संभालें, या उन्हें कॉलर को प्रचारित करने दें।


9
+1: यदि xफ़ाइल की तरह नहीं है, तो x.read()यह खुद अपवाद होगा। क्यों एक अतिरिक्त अगर बयान लिखें? बस वस्तु का उपयोग करें। यह या तो काम करेगा या टूट जाएगा।
S.Lott

3
अपवाद को संभालना भी मत। यदि कोई व्यक्ति ऐसी किसी चीज़ से गुजरा है जो आपके द्वारा अपेक्षित एपीआई से मेल नहीं खाती है, तो यह आपकी समस्या नहीं है।
२२:२२ बजे habnabit

1
@ ऐरन गैलाघर: मुझे यकीन नहीं है। क्या आपका कथन सच है, भले ही मेरे लिए एक सुसंगत स्थिति को संरक्षित करना कठिन है?
dmeister

1
एक सुसंगत स्थिति को संरक्षित करने के लिए आप "स्टेटमेंट / एंड" (लेकिन इसके अलावा नहीं!) या नए "स्टेटमेंट" का उपयोग कर सकते हैं।
drxzcl

यह "विफल उपवास और जोर से विफल" प्रतिमान के अनुरूप भी है। जब तक आप सावधानीपूर्वक, स्पष्ट हैसट्रेट (...) चेक कभी-कभी एक फ़ंक्शन / विधि का उपयोग कर सकते हैं जब तक कि वह अपनी इच्छित कार्रवाई किए बिना सामान्य रूप से वापस न आए।
बेन बर्न्स

11

किसी स्थिति की जाँच करके किसी त्रुटि को उठाना अक्सर उपयोगी होता है, जब उस त्रुटि को सामान्य रूप से बहुत बाद तक नहीं उठाया जाएगा। यह 'उपयोगकर्ता-भूमि' और 'एपीआई' कोड के बीच सीमा के लिए विशेष रूप से सच है।

आप बाहर निकलने के दरवाजे पर एक पुलिस स्टेशन में मेटल डिटेक्टर नहीं लगाते हैं, आप इसे प्रवेश द्वार पर रख देंगे! यदि किसी शर्त की जाँच नहीं की जाती है, तो एक त्रुटि हो सकती है जो पहले 100 लाइनों में पकड़ी जा सकती थी, या उप-वर्ग में उठाए जाने के बजाय एक सुपर-क्लास में हो सकती है, तो मैं कहता हूं कि जाँच में कुछ भी गलत नहीं है।

जब आप एक से अधिक प्रकार स्वीकार कर रहे होते हैं, तो उचित प्रकारों के लिए जाँच करना भी समझ में आता है। एक अपवाद को बढ़ाने के लिए बेहतर है जो कहता है कि "मुझे बस एक अपवाद की आवश्यकता है, या फ़ाइल को" केवल एक अपवाद को बढ़ाने की तुलना में क्योंकि कुछ चर में 'खोज' विधि नहीं है ...

इसका मतलब यह नहीं है कि आप पागल हो जाते हैं और हर जगह ऐसा करते हैं, अधिकांश भाग के लिए मैं खुद को बढ़ाने वाले अपवादों की अवधारणा से सहमत हूं, लेकिन अगर आप अपने एपीआई को बहुत स्पष्ट कर सकते हैं, या अनावश्यक कोड निष्पादन से बच सकते हैं क्योंकि एक साधारण शर्त पूरी नहीं हुई है ऐसा करो!


1
मैं सहमत हूं, लेकिन हर जगह इसके साथ पागल नहीं होने की रेखाओं के साथ - इनमें से बहुत सी चिंताओं को परीक्षण के दौरान हिला देना चाहिए, और कुछ "जहां इसे पकड़ने के लिए / उपयोगकर्ता को कैसे प्रदर्शित किया जाए" सवालों का जवाब प्रयोज्य आवश्यकताओं द्वारा उत्तर दिया जाएगा।
बेन बर्न्स

7

आप कोशिश कर सकते हैं और विधि को बुला सकते हैं फिर अपवाद को पकड़ सकते हैं:

try:
    fp.read()
except AttributeError:
    raise something

यदि आप केवल एक पढ़ने और लिखने की विधि चाहते हैं, तो आप ऐसा कर सकते हैं:

if not (hasattr(fp, 'read') and hasattr(fp, 'write')):
   raise something

अगर मैं तुम होते तो मैं कोशिश / विधि को छोड़कर जाता।


मैं उदाहरणों के क्रम को बदलने का सुझाव दूंगा। tryहमेशा पहली पसंद है। hasattrचेकों ही कर रहे हैं - वास्तव में कुछ अस्पष्ट कारण के लिए - आप बस का उपयोग नहीं कर सकते हैं try
S.Lott

1
यदि आप बाद में डेटा को संसाधित करना चाहते हैं तो ब्लॉक में सभी कोड डालने से बचने के लिए मैं fp.read(0)इसके बजाय उपयोग करने का सुझाव देता हूं । fp.read()tryfp
मेव

3
ध्यान दें कि fp.read()बड़ी फ़ाइलों के साथ तुरंत मेमोरी का उपयोग बढ़ जाएगा।
Kyrylo Perevozchikov

मुझे लगता है कि यह अजगर है, लेकिन फिर हमें अन्य मुद्दों के बीच फाइल को दो बार पढ़ना होगा। उदाहरण के लिए, Flaskमैंने ऐसा किया है और अंतर्निहित FileStorageवस्तु को महसूस किया है कि इसे पढ़ने के बाद सूचक रीसेट की आवश्यकता है।
एडम ह्यूजेस

2

ज्यादातर परिस्थितियों में, इसे संभालने का सबसे अच्छा तरीका नहीं है। यदि कोई विधि किसी फ़ाइल जैसा ऑब्जेक्ट लेती है, और यह वह ऑब्जेक्ट है जिसे वह पास नहीं किया गया है, तो वह अपवाद जो उस समय उठाया जाता है, जब विधि ऑब्जेक्ट का उपयोग करने की कोशिश करती है, किसी भी अपवाद से कम जानकारीपूर्ण नहीं है जिसे आपने स्पष्ट रूप से उठाया हो।

कम से कम एक मामला है जहां आप इस तरह की जांच करना चाहते हैं, हालांकि, और जब ऑब्जेक्ट का उपयोग तुरंत उस चीज़ से नहीं किया जा रहा है जिसे आपने इसे पारित किया है, जैसे कि यदि यह एक क्लास के कंस्ट्रक्टर में सेट किया जा रहा है। उस मामले में, मुझे लगता है कि ईएएफपी के सिद्धांत को "तेजी से विफल" के सिद्धांत द्वारा ट्रम्प किया गया है। मैं यह सुनिश्चित करने के लिए वस्तु की जाँच करूँगा कि यह उन तरीकों को लागू करे जिन्हें मेरी कक्षा की ज़रूरत है (और वे विधियाँ हैं), जैसे:

class C():
    def __init__(self, file):
        if type(getattr(file, 'read')) != type(self.__init__):
            raise AttributeError
        self.file = file

1
getattr(file, 'read')सिर्फ के बजाय क्यों file.read? यह ठीक यही काम करता है।
१ert

1
इससे भी महत्वपूर्ण बात यह है कि यह जाँच गलत है। यह तब दिया जाएगा जब एक वास्तविक fileउदाहरण दिया जाएगा । (बिलिन / सी-एक्सटेंशन प्रकार के उदाहरणों के तरीके प्रकार के हैं builtin_function_or_method, जबकि पुराने शैली के वर्ग हैं instancemethod)। तथ्य यह है कि यह एक पुरानी शैली वर्ग है, और कहा कि इसे इस्तेमाल करता है ==बजाय के प्रकार पर ininstanceया issubclass, आगे की समस्याओं कर रहे हैं, लेकिन अगर मूल विचार काम नहीं करता, कि शायद ही मायने रखती है।

2

मैंने आपके प्रश्न पर चलना शुरू कर दिया जब मैं एक openतरह का फ़ंक्शन लिख रहा था जो फ़ाइल नाम, फ़ाइल डिस्क्रिप्टर या पूर्व-ओपन फ़ाइल जैसी ऑब्जेक्ट को स्वीकार कर सकता था।

एक readविधि के लिए परीक्षण करने के बजाय , जैसा कि अन्य उत्तर सुझाते हैं, मैंने जाँच की कि क्या वस्तु को खोला जा सकता है। यदि यह हो सकता है, तो यह एक स्ट्रिंग या डिस्क्रिप्टर है, और मेरे पास परिणाम से हाथ में एक मान्य फ़ाइल जैसी वस्तु है। यदि कोई openउठाता है TypeError, तो ऑब्जेक्ट पहले से ही एक फ़ाइल है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.