कैसे एक चर बताने के लिए चलने योग्य है, लेकिन एक स्ट्रिंग नहीं है


88

मेरे पास एक फ़ंक्शन है जो एक तर्क लेता है जो एकल आइटम या दोहरी आइटम हो सकता है:

def iterable(arg)
    if #arg is an iterable:
        print "yes"
    else:
        print "no"

ताकि:

>>> चलने योग्य (("एफ", "एफ"))
हाँ

>>> चलने योग्य (["एफ", "एफ"])
हाँ

>>> चलने योग्य ("एफएफ")
नहीं

समस्या यह है कि स्ट्रिंग तकनीकी रूप से चलने योग्य है, इसलिए मैं कोशिश करते समय ValueError को नहीं पकड़ सकता arg[1]। मैं आइंस्टीन () का उपयोग नहीं करना चाहता, क्योंकि यह अच्छा अभ्यास नहीं है (या इसलिए मुझे बताया गया है)।


1
पायथन का कौन सा संस्करण? मेरा मानना ​​है कि उत्तर 2. * और 3 के बीच अलग है
— कैथी वान स्टोन

4
आपको गलत तरीके से बताया गया, आइंस्टीन बुरा व्यवहार नहीं है।
— लेन्नर्ट रेगेब्र

3
ओह, रुको, शायद वह इस सिद्धांत को संदर्भित करता है कि वस्तुओं के प्रकार की जांच करना बुरा है, और यह कार्यक्रम टूटने का संकेत है? यह सिद्धांत में सच है (लेकिन हमेशा व्यवहार में नहीं)। ऐसा मामला हो भी सकता है और नहीं भी। लेकिन यह फ़ंक्शन की स्थापना नहीं है जो समस्या है, यह प्रकारों के लिए जाँच करने की आदत है।
— लेन्नर्ट रेगेब्र

@ लेनार्ट: canonical.org/~kragen/isinstance हालांकि यह पुराना हो सकता है
— पुजारी

@ हालांकि यह प्रकार-आधारित फ़ंक्शन को ओवरलोडिंग का उल्लेख नहीं करता है, और isinstanceगतिशील रूप से टाइप की गई भाषाओं में इसे करने का तरीका है। रोज़ इस्तेमाल होने वाली चीज़ नहीं, लेकिन उचित मामलों में ठीक है।
— कोस

जवाबों:


50

आइंस्टीन का प्रयोग करें (मैं नहीं देखता कि यह बुरा व्यवहार क्यों है)

import types
if not isinstance(arg, types.StringTypes):

स्ट्रिंगटाइप्स के उपयोग पर ध्यान दें। यह सुनिश्चित करता है कि हम कुछ अस्पष्ट प्रकार के स्ट्रिंग के बारे में न भूलें।

उल्टा, यह व्युत्पन्न स्ट्रिंग वर्गों के लिए भी काम करता है।

class MyString(str):
    pass

isinstance(MyString("  "), types.StringTypes) # true

इसके अलावा, आप इस पिछले प्रश्न पर एक नज़र रखना चाहते हैं ।

चीयर्स।


नायब: पायथन 3 में व्यवहार बदल गया StringTypesऔर basestringअब परिभाषित नहीं किया गया है। अपनी आवश्यकताओं पर निर्भर करता है, तो आप उन्हें में जगह ले सकता है isinstanceके द्वारा str, या के एक सबसेट टपल (str, bytes, unicode), जैसे Cython उपयोगकर्ताओं के लिए। जैसा कि @Theron Luhn ने उल्लेख किया है, आप भी उपयोग कर सकते हैं six।


अच्छा, scvalex। मैं अपने -1 को निकाल रहा हूं और इसे +1 :-) बना रहा हूं।
— टॉम

2
मुझे लगता है कि खराब अभ्यास का विचार बतख टाइपिंग सिद्धांत के कारण है। किसी विशेष वर्ग के सदस्य होने का मतलब यह नहीं है कि यह एकमात्र ऐसी वस्तु है जिसका उपयोग किया जा सकता है और न ही अपेक्षित तरीके उपलब्ध हैं। लेकिन मुझे लगता है कि कभी-कभी आप सिर्फ यह पता नहीं लगा सकते हैं कि क्या तरीका मौजूद है, भले ही यह isinstanceएकमात्र तरीका हो।
— एस्टनी डे

2
नोट: type.StringTypes Python 3 में उपलब्ध नहीं है। चूंकि py3k में केवल एक स्ट्रिंग प्रकार है, मुझे लगता है कि यह सुरक्षित है do isinstance(arg, str)। एक बैकवर्ड-संगत संस्करण के लिए, pythonhosted.org/six/#six.string_types
— Theron Luhn

मैं सख्ती से पायथन 3 का उपयोग करता हूं और देखा गया types.StringTypesहै कि पायथन 3 में उपलब्ध नहीं है। पायथन 2 में मूल्य क्या है?
— केविनपेयर

2
2017 : यह उत्तर अब मान्य नहीं है, ढेर सारे संस्करणों के साथ काम करने वाले के लिए stackoverflow.com/a/44328500/99834 देखें ।
— सोरिन

26

2017 तक, यहां एक पोर्टेबल समाधान है जो पायथन के सभी संस्करणों के साथ काम करता है:

#!/usr/bin/env python
import collections
import six


def iterable(arg):
    return (
        isinstance(arg, collections.Iterable) 
        and not isinstance(arg, six.string_types)
    )


# non-string iterables    
assert iterable(("f", "f"))    # tuple
assert iterable(["f", "f"])    # list
assert iterable(iter("ff"))    # iterator
assert iterable(range(44))     # generator
assert iterable(b"ff")         # bytes (Python 2 calls this a string)

# strings or non-iterables
assert not iterable(u"ff")     # string
assert not iterable(44)        # integer
assert not iterable(iterable)  # function

बाईटस्ट्रेस के साथ 2/3 के बीच कुछ छोटी विसंगतियां हैं, लेकिन यदि आप देशी "स्ट्रिंग" का उपयोग करते हैं तो वे दोनों झूठे हैं
— निक टी

16

पाइथन 2.6 के बाद से, सार आधार वर्गों की शुरुआत के साथ, isinstance(एबीसी पर प्रयोग किया जाता है, ठोस वर्ग नहीं) अब पूरी तरह से स्वीकार्य माना जाता है। विशेष रूप से:

from abc import ABCMeta, abstractmethod

class NonStringIterable:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __iter__(self):
        while False:
            yield None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is NonStringIterable:
            if any("__iter__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented

यह एक सटीक प्रति (केवल वर्ग नाम बदलकर) के Iterableरूप में परिभाषित किया गया है _abcoll.py(एक कार्यान्वयन विस्तार collections.py) ... कारण यह काम करता है के रूप में आप चाहते हैं, जबकि collections.Iterableयह नहीं है कि बाद में अतिरिक्त मील जाता है तार सुनिश्चित करने के लिए कर रहे हैं माना जाता है कि Iterable.register(str)इसके बाद स्पष्ट रूप से कॉल करकेclass कथन के ।

निश्चित रूप से अन्य वर्गों के लिए कॉल करने से पहले इसे __subclasshook__वापस लेना आसान है False, anyजिसे आप विशेष रूप से अपनी परिभाषा से बाहर करना चाहते हैं।

किसी भी मामले में, के बाद आप के रूप में इस नए मॉड्यूल आयात किया है myiter, isinstance('ciao', myiter.NonStringIterable)हो जाएगा False, और isinstance([1,2,3], myiter.NonStringIterable)हो जाएगा True, तो आप अनुरोध बस के रूप में - और अजगर 2.6 में और बाद में इस अवतार लेना इस तरह की जांच के लिए उचित तरीका माना जाता है ... एक सार आधार वर्ग को परिभाषित और isinstanceउस पर जाँच करें ।


पायथन में 3 isinstance('spam', NonStringIterable)रिटर्न True।
— निक टी

1
(...) और पाइथन 2.6 में और बाद में इस तरह की जाँचों को मूर्त रूप देने का उचित तरीका माना जाता है ... (...) अमूर्त वर्ग की अच्छी तरह से ज्ञात अवधारणा का इस तरह से दुरुपयोग करना कभी भी उचित तरीका माना जा सकता है जो मेरी समझ से परे है। इसके बदले उचित तरीका यह होगा कि आप कुछ आकर्षक दिखने वाले ऑपरेटर को पेश करें ।
— पायोत्र डोब्रोगोस्ट

एलेक्स, क्या आप निक के दावे को संबोधित कर सकते हैं कि यह पायथन 3 में काम नहीं करता है? मुझे उत्तर पसंद है, लेकिन यह सुनिश्चित करना चाहूंगा कि मैं भविष्य में प्रूफ कोड लिख रहा हूं।
— मेरलिन मॉर्गन-ग्राहम

@ MerlynMorgan-ग्राहम, यह सही है, क्योंकि __iter__ है अब अजगर 3. तो मेरी "आसान बढ़ाने के लिए" पैरा लागू और जैसे हो जाता है में तार में लागू if issublass(cls, str): return Falseकी जरूरत के शुरू में जोड़े जाने के लिए __subclasshook__(किसी अन्य वर्ग है जो परिभाषित करने के साथ ही __iter__, लेकिन में अपने मानसिकता को "गैर-स्ट्रिंग पुनरावृत्तियों" के रूप में स्वीकार नहीं किया जाना चाहिए।
— एलेक्स मार्टेली

@AlexMartelli Python 3 के लिए, क्या आपका मतलब यह नहीं है कि if issublass(C, str): return Falseजोड़ा जाना चाहिए?
— रोब स्मॉलशायर

4

मुझे लगता है कि यह एक पुरानी पोस्ट है, लेकिन मुझे लगा कि यह इंटरनेट पोस्टेरिटी के लिए मेरा दृष्टिकोण जोड़ने लायक है। नीचे दिया गया कार्य पायथन 2 और 3 दोनों के साथ अधिकांश परिस्थितियों में मेरे लिए काम करता है:

def is_collection(obj):
    """ Returns true for any iterable which is not a string or byte sequence.
    """
    try:
        if isinstance(obj, unicode):
            return False
    except NameError:
        pass
    if isinstance(obj, bytes):
        return False
    try:
        iter(obj)
    except TypeError:
        return False
    try:
        hasattr(None, obj)
    except TypeError:
        return True
    return False

यह (गलत) बिल्ट-इन का उपयोग करके एक गैर-स्ट्रिंग पुनरावृत्ति के लिए जाँच करता है, hasattrजिसमें TypeErrorतब उठाया जाएगा जब इसका दूसरा तर्क स्ट्रिंग या यूनिकोड स्ट्रिंग नहीं होगा।


3

पिछले उत्तरों को मिलाकर, मैं उपयोग कर रहा हूं:

import types
import collections

#[...]

if isinstance(var, types.StringTypes ) \
    or not isinstance(var, collections.Iterable):

#[Do stuff...]

100% मूर्खतापूर्ण सबूत नहीं है, लेकिन अगर कोई वस्तु एक चलने योग्य नहीं है, तो आप अभी भी इसे पास कर सकते हैं और बतख टाइपिंग में वापस आ सकते हैं।


संपादित करें: पायथन 3

types.StringTypes == (str, unicode)। Phython3 समतुल्य है:

if isinstance(var, str ) \
    or not isinstance(var, collections.Iterable):

आपका आयात विवरण 'प्रकार' होना चाहिए न कि 'प्रकार'
— पॉल

3

2.x

मैंने सुझाव दिया होगा:

hasattr(x, '__iter__')

या डेविड चार्ल्स की टिप्पणी को देखते हुए पायथन 3 के लिए इसे ट्वीक करना, किस बारे में है:

hasattr(x, '__iter__') and not isinstance(x, (str, bytes))

3.x

बिलिन basestringसार प्रकार हटा दिया गया था । strइसके बजाय उपयोग करें । strऔर bytesप्रकार के एक साझा आधार वर्ग वारंट आम में कार्यक्षमता पर्याप्त नहीं है।


3
शायद इसलिए __iter__कि पायथन 3 में तार हैं?
— davidrmcharles

@DavidCharles ओह, सच में? मेरी गलती। मैं एक Jython उपयोगकर्ता हूँ और Jython का वर्तमान में कोई संस्करण नहीं है 3.
— माइक कृंतक

यह वास्तव में एक जवाब नहीं है, अधिक टिप्पणी / सवाल है, और यह 3.x के लिए गलत है। क्या आप इसे साफ कर सकते हैं? क्या आप दावा कर सकते हैं कि "साझा 'वर्ग को वारंट करने के लिए " स्ट्र' और 'बाइट्स' प्रकारों में पर्याप्त कार्यक्षमता नहीं है। " 3.x के प्रमुख बिंदुओं में से एक यूनिकोड बाइट्स को प्रथम श्रेणी का नागरिक बनाना था।
— 6

मुझे कोई सुराग नहीं है कि मैंने उपरोक्त में से कोई क्यों लिखा है। मैंने "3.x" के तहत सभी पाठ को हटाने का प्रस्ताव दिया है ... हालाँकि आपने मेरा उत्तर पहले ही संपादित कर लिया है। पसंद आने पर इसे और संपादित करें।
— माइक कृंतक

0

जैसा कि आप सही ढंग से इंगित करते हैं, एक एकल स्ट्रिंग एक चरित्र अनुक्रम है।

तो जिस चीज को आप वास्तव में करना चाहते हैं, वह यह पता लगाना है कि argआइंस्टीन या प्रकार (a) == str का उपयोग करके किस प्रकार का अनुक्रम है।

यदि आप किसी ऐसे फंक्शन को महसूस करना चाहते हैं जो मापदंडों की एक परिवर्तनीय राशि लेता है, तो आपको इसे इस तरह करना चाहिए:

def function(*args):
    # args is a tuple
    for arg in args:
        do_something(arg)

फ़ंक्शन ("एफएफ") और फ़ंक्शन ("एफएफ", "एफएफ") काम करेंगे।

मैं ऐसा परिदृश्य नहीं देख सकता जहाँ आपकी तरह एक अनुमापनीय () फ़ंक्शन की आवश्यकता हो। यह आइंस्टीन () नहीं है जो खराब शैली है, लेकिन ऐसी परिस्थितियां हैं जहां आपको आइंस्टीन () का उपयोग करने की आवश्यकता है।


4
के उपयोग type(a) == strसे बचना होगा। यह एक बुरा अभ्यास है क्योंकि यह समान प्रकार या इससे प्राप्त प्रकारों को ध्यान में नहीं रखता है str। typeप्रकार पदानुक्रम पर चढ़ाई नहीं करता है, जबकि isinstanceकरता है, इसलिए इसका उपयोग करना बेहतर है isinstance।
— अकीरोस

0

एलेक्स मार्टेली की उत्कृष्ट हैक पर स्पष्ट रूप से विस्तार करने collections.pyऔर इसके चारों ओर कुछ प्रश्नों को संबोधित करने के लिए: पायथ 3.6% में वर्तमान कार्य समाधान है

import collections
import _collections_abc as cabc
import abc


class NonStringIterable(metaclass=abc.ABCMeta):

    __slots__ = ()

    @abc.abstractmethod
    def __iter__(self):
        while False:
            yield None

    @classmethod
    def __subclasshook__(cls, c):
        if cls is NonStringIterable:
            if issubclass(c, str):
                return False
            return cabc._check_methods(c, "__iter__")
        return NotImplemented

और प्रदर्शन किया

>>> typs = ['string', iter(''), list(), dict(), tuple(), set()]
>>> [isinstance(o, NonStringIterable) for o in typs]
[False, True, True, True, True, True]

यदि आप iter('')बहिष्करण में जोड़ना चाहते हैं , उदाहरण के लिए, पंक्ति को संशोधित करें

            if issubclass(c, str):
                return False

होने के लिए

            # `str_iterator` is just a shortcut for `type(iter(''))`*
            if issubclass(c, (str, cabc.str_iterator)):
                return False

लेना

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