จะทราบได้อย่างไรว่าวัตถุ Python เป็นสตริง?


402

ฉันจะตรวจสอบว่าวัตถุ Python เป็นสตริง (ปกติหรือ Unicode) ได้อย่างไร


18
สิ่งที่เจสันอ้างถึงคือการพิมพ์เป็ด (ถ้ามันเหมือนเป็ดมันน่าจะเป็นเป็ด) ใน Python คุณมักจะ "ปล่อยให้โค้ดของคุณทำงาน" บนวัตถุที่มีลักษณะคล้ายสตริงโดยไม่ต้องทดสอบว่าเป็นสตริงย่อยหรือสตริงย่อย สำหรับข้อมูลเพิ่มเติมโปรดดู: docs.python.org/glossary.html#term-duck-typing
Ben Hoyt

4
นั่นคือสิ่งที่ฉันชอบมาก ฉันมักจะถามคำถามมันไม่ได้รับคำตอบคนบอกฉันว่าฉันไม่ควรทำอย่างนั้นและทำไมและฉันเติบโตขึ้นเป็นโปรแกรมเมอร์ =)
Physicsmichael

24
+1: เพียงเพราะคำตอบไม่ค่อยจำเป็นไม่ได้หมายความว่าคำถามนั้นไม่ถูกต้อง แม้ว่าฉันคิดว่ามันเป็นเรื่องดีที่จะได้รับคำเตือนที่นี่ แต่ฉันคิดว่ามันไม่สมควรที่จะลบล้างคำถาม
เทรเวอร์

17
นี่อาจเป็นการใช้การตรวจสอบประเภทที่ถูกต้องที่สุดใน Python สตริงนั้นสามารถทำซ้ำได้ดังนั้นการแยกความแตกต่างออกจากรายการด้วยวิธีอื่นจึงเป็นความคิดที่ไม่ดี
ojrac

3
มีหลายกรณีที่จำเป็นต้องแยกสตริงจาก iterables อื่น ๆ ตัวอย่างเช่นดูซอร์สโค้ดของ PrettyPrinter ในโมดูล pprint
saxman01

คำตอบ:



178

Python 2

วิธีตรวจสอบว่าวัตถุoเป็นชนิดสตริงของคลาสย่อยของชนิดสตริงหรือไม่:

isinstance(o, basestring)

เพราะทั้งสองstrและเป็นคลาสย่อยunicodebasestring

ในการตรวจสอบว่าประเภทของoถูกต้องหรือไม่str:

type(o) is str

ในการตรวจสอบว่าoเป็นอินสแตนซ์ของstrหรือคลาสย่อยของstr:

isinstance(o, str)

ดังกล่าวข้างต้นยังทำงานสำหรับสตริง Unicode ถ้าคุณแทนที่ด้วยstrunicode

อย่างไรก็ตามคุณอาจไม่จำเป็นต้องทำการตรวจสอบประเภทอย่างชัดเจนเลย "การพิมพ์เป็ด" อาจเหมาะกับความต้องการของคุณ ดูhttp://docs.python.org/glossary.html#term-duck-typing

ดูเพิ่มเติมวิธีบัญญัติของการตรวจสอบประเภทในงูหลามคืออะไร?


ตัวแปรท้องถิ่น 'str' ถูกอ้างอิงก่อนกำหนด
john ktejik

@johnktejik python3 เทียบกับ python2 คุณต้องตรวจสอบbasestringใน py2
erikbwork

170

Python 3

ใน Python 3.x basestringไม่สามารถใช้งานได้อีกต่อไปเช่นstrเดียวกับประเภทสตริง (ที่มีความหมายของ Python 2.x unicode)

ดังนั้นการตรวจสอบใน Python 3.x จึงเป็นเพียง:

isinstance(obj_to_test, str)

นี้ต่อไปนี้การแก้ไขอย่างเป็นทางการ2to3เครื่องมือการแปลง: แปลงไปbasestringstr


94

Python 2 และ 3

(Cross-เข้ากันได้)

หากคุณต้องการตรวจสอบโดยไม่คำนึงถึงเวอร์ชัน Python (2.x vs 3.x) ให้ใช้six( PyPI ) และstring_typesแอตทริบิวต์ของมัน:

import six

if isinstance(obj, six.string_types):
    print('obj is a string!')

ภายในsix(โมดูลไฟล์เดียวที่มีน้ำหนักเบามาก) เพียงทำสิ่งนี้ :

import sys
PY3 = sys.version_info[0] == 3

if PY3:
    string_types = str
else:
    string_types = basestring

หรือคุณสามารถใช้future( PyPI ) เพื่อเก็บชื่อ:from past.builtins import basestring
David Nemeskey

1
BTW the Cheat Sheetเป็นทรัพยากรที่ดีเยี่ยมสำหรับการใช้งานร่วมกับ Python ได้
David Nemeskey

1
สิ่งที่เกี่ยวกับการไม่ใช้การนำเข้าใด ๆ ความพยายามครั้งแรกแล้วถอยกลับไปbasestring strEgdef is_string(obj): try: return isinstance(obj, basestring) # python 2 except NameError: return isinstance(obj, str) # python 3
isaacbernat

19

ฉันพบสิ่งนี้มากกว่าpythonic:

if type(aObject) is str:
    #do your stuff here
    pass

ตั้งแต่ประเภทวัตถุเดี่ยว, จะสามารถนำมาใช้ในการทำเปรียบเทียบวัตถุรูปแบบ str


4
นี่ไม่ใช่วิธีการทดสอบทั่วไปที่แนะนำสำหรับประเภทเนื่องจากการสืบทอด: isinstance(obj_to_test, str)มีความหมายอย่างชัดเจนในการทดสอบประเภทและมีความได้เปรียบในการใช้ขั้นตอนเดียวกับกรณีอื่น ๆ ที่ไม่ใช่ str
Eric O Lebigot

14

ถ้าใครอยากจะอยู่ห่างจากที่ชัดเจนประเภทการตรวจสอบ (และมีมีเหตุผลที่ดีที่จะอยู่ห่างจากมัน) น่าจะเป็นส่วนที่ปลอดภัยที่สุดของโปรโตคอลสตริงเพื่อเช็คอินคือ:

str(maybe_string) == maybe_string

มันจะไม่วนซ้ำผ่าน iterable หรือ iterator มันจะไม่เรียก list-of-strings สตริงและตรวจพบstringlikeเป็นสตริงอย่างถูกต้อง

แน่นอนว่ามีข้อเสียคือ ตัวอย่างเช่นstr(maybe_string)อาจเป็นการคำนวณที่หนักหน่วง จึงมักจะเป็นคำตอบคือมันขึ้นอยู่กับ

แก้ไข: ตามที่@Tcll ชี้ให้เห็นในความคิดเห็นคำถามจะถามหาวิธีในการตรวจสอบทั้งสตริง Unicode และ bytestrings ใน Python 2 คำตอบนี้จะล้มเหลวโดยมีข้อยกเว้นสำหรับสตริง unicode ที่มีอักขระที่ไม่ใช่ ASCII และใน Python 3 จะมีการคืนค่าFalseการทดสอบทั้งหมด


ในกรณีของวัตถุที่เริ่มต้นด้วยข้อมูลการเป็นตัวแทนนี้อาจไม่ทำงานตามที่คาดไว้ ... b = b'test'; r = str(b) == bซึ่งbเก็บข้อมูลเดียวกันเป็นstr(b)แต่ (เป็นวัตถุไบต์) ไม่ตรวจสอบเป็นสตริง
Tcll

@Tcll Right คำถามจริง ๆ แล้วบอกว่า "ปกติหรือ Unicode" ฉันเดาว่าฉันอ่านมันไม่ถูกต้อง
clacke

11

ในการตรวจสอบว่าตัวแปรของคุณเป็นอะไรที่คุณควรทำ:

s='Hello World'
if isinstance(s,str):
#do something here,

ผลลัพธ์ของ isistance จะให้ค่าบูลีนจริงหรือเท็จเพื่อให้คุณสามารถปรับเปลี่ยนได้ตามความเหมาะสม คุณสามารถตรวจสอบตัวย่อที่คาดหวังของค่าของคุณโดยเริ่มต้นใช้: type (s) ซึ่งจะส่งกลับคุณพิมพ์ 'str' เพื่อให้คุณสามารถใช้มันในฟังก์ชั่น isistance


5

ฉันอาจจัดการกับเรื่องนี้ในรูปแบบการพิมพ์เป็ดเหมือนคนอื่น ๆ พูดถึง ฉันจะรู้ได้อย่างไรว่าสตริงเป็นสตริงจริงๆ? อย่างชัดเจนโดยการแปลงเป็นสตริง!

def myfunc(word):
    word = unicode(word)
    ...

หาก arg เป็นสตริงหรือยูนิโค้ดอยู่แล้ว real_word จะเก็บค่าไว้โดยไม่แก้ไข หากวัตถุที่ผ่านการใช้__unicode__วิธีการที่ใช้ในการรับการเป็นตัวแทนของ Unicode หากไม่สามารถใช้วัตถุที่ส่งเป็นสตริงได้unicodeบิวด์อินจะยกข้อยกเว้น


3
isinstance(your_object, basestring)

จะเป็นจริงถ้าวัตถุของคุณเป็นประเภทสตริง 'str' เป็นคำที่สงวนไว้

คำขอโทษของฉันคำตอบที่ถูกต้องคือใช้ 'basestring' แทน 'str' เพื่อให้รวมสตริง unicode ด้วย - ดังที่ได้กล่าวไว้ข้างต้นโดยหนึ่งในผู้เผชิญเหตุอื่น ๆ


ไม่ทำงานสำหรับวัตถุ Unicode ซึ่งมีการร้องขออย่างชัดเจนในคำถาม
dbn

1

เย็นนี้ฉันวิ่งเข้าไปในสถานการณ์ที่ฉันคิดว่าฉันจะต้องตรวจสอบกับstrประเภท แต่มันกลับกลายเป็นว่าฉันไม่ได้

วิธีการของฉันในการแก้ปัญหาอาจจะใช้ได้ในหลาย ๆ สถานการณ์ดังนั้นฉันขอเสนอด้านล่างในกรณีที่ผู้อื่นที่อ่านคำถามนี้สนใจ (Python 3 เท่านั้น)

# NOTE: fields is an object that COULD be any number of things, including:
# - a single string-like object
# - a string-like object that needs to be converted to a sequence of 
# string-like objects at some separator, sep
# - a sequence of string-like objects
def getfields(*fields, sep=' ', validator=lambda f: True):
    '''Take a field sequence definition and yield from a validated
     field sequence. Accepts a string, a string with separators, 
     or a sequence of strings'''
    if fields:
        try:
            # single unpack in the case of a single argument
            fieldseq, = fields
            try:
                # convert to string sequence if string
                fieldseq = fieldseq.split(sep)
            except AttributeError:
                # not a string; assume other iterable
                pass
        except ValueError:
            # not a single argument and not a string
            fieldseq = fields
        invalid_fields = [field for field in fieldseq if not validator(field)]
        if invalid_fields:
            raise ValueError('One or more field names is invalid:\n'
                             '{!r}'.format(invalid_fields))
    else:
        raise ValueError('No fields were provided')
    try:
        yield from fieldseq
    except TypeError as e:
        raise ValueError('Single field argument must be a string'
                         'or an interable') from e

การทดสอบบางอย่าง:

from . import getfields

def test_getfields_novalidation():
    result = ['a', 'b']
    assert list(getfields('a b')) == result
    assert list(getfields('a,b', sep=',')) == result
    assert list(getfields('a', 'b')) == result
    assert list(getfields(['a', 'b'])) == result

1

มันง่ายใช้รหัสต่อไปนี้ (เราถือว่าวัตถุที่กล่าวถึงเป็น obj) -

if type(obj) == str:
    print('It is a string')
else:
    print('It is not a string.')

0

คุณสามารถทดสอบได้โดยต่อกับสตริงว่าง:

def is_string(s):
  try:
    s += ''
  except:
    return False
  return True

แก้ไข :

การแก้ไขคำตอบของฉันหลังจากความคิดเห็นชี้ให้เห็นว่าสิ่งนี้ล้มเหลวด้วยรายการ

def is_string(s):
  return isinstance(s, basestring)

คุณพูดถูกต้องขอบคุณที่ชี้ให้เห็น ฉันได้รับคำตอบทางเลือก
georgepsarakis

-3

สำหรับแนวทางการพิมพ์เป็ดที่ดีสำหรับการกดสตริงที่มีโบนัสในการทำงานกับทั้ง Python 2.x และ 3.x:

def is_string(obj):
    try:
        obj + ''
        return True
    except TypeError:
        return False

wisefishอยู่ใกล้กับเป็ดพิมพ์ก่อนที่เขาจะเปลี่ยนไปisinstanceวิธีการยกเว้นว่า+=มีความหมายที่แตกต่างกันสำหรับรายการกว่า+ไม่


2
คุณมีสอง downvotes และไม่มีใครแสดงความคิดเห็น ฉันไม่ได้ลงคะแนน แต่ฉันไม่ชอบวิธีการแก้ปัญหาของคุณเพราะ: * มากเกินไป verbose คุณไม่จำเป็นต้องกำหนดฟังก์ชั่นในการทำเช่นนี้ * เเพง. การดักจับข้อยกเว้นนั้นไม่ดีต่อประสิทธิภาพ * ข้อผิดพลาดง่าย. วัตถุอื่นอาจนำไปใช้เพิ่มดูสตริงและยกข้อยกเว้นประเภทอื่นซึ่งไม่ใช่ TypeError
santiagobasulto

นอกจากนี้ที่นี่คุณกำลังใช้วิธีการพิมพ์เป็ดซึ่งมีความสวยงาม แต่จบลงด้วยการขว้างปาและจับข้อยกเว้นเพียงเพื่อหาสิ่งที่ไม่สวยงาม
Alexey Tigarev

นี่อาจเป็นวิธีเดียวที่ถูกต้องตามกฎหมายในการแยกความแตกต่างระหว่างสตริงที่เหมือนกันและบางส่วนที่ใช้ซ้ำได้ของสตริง ใครจะมองหาคุณลักษณะเช่นisalphaแต่ใครจะรู้วิธีการที่ปลอดภัยที่จะมองหา?
clacke

ฉันตระหนักว่า__str__วิธีการบวกกับความเท่าเทียมกันอาจเป็นวิธีการที่โง่เขลา แต่ถึงกระนั้นก็ไม่ได้มีข้อแม้
clacke

@santiagobasulto ข้อยกเว้นราคาถูกใน Python หากคุณคาดว่าข้อผิดพลาด 1% ของเวลาtryสามารถเร็วขึ้น หากคุณคาดหวัง 99% ของเวลาอาจจะไม่ ความแตกต่างด้านประสิทธิภาพนั้นน้อยมากจะดีกว่าถ้าคุณใช้รหัสและระบุว่าช้า
Nick T

-4
if type(varA) == str or type(varB) == str:
    print 'string involved'

จาก EDX - MITx หลักสูตรออนไลน์: 6.00.1x วิทยาการคอมพิวเตอร์เบื้องต้นและการเขียนโปรแกรมโดยใช้ Python


6
นี่อาจเป็นวิธีที่เลวร้ายที่สุดในการตรวจสอบ มันไม่เพียง แต่แยกวัตถุ Unicode มันยังไม่รวมคลาสย่อยของstr !
สิงหาคม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.