Cara memeriksa apakah variabel string dengan kompatibilitas python 2 dan 3

171

Saya sadar bahwa saya dapat menggunakan: isinstance(x, str)di python-3.x tapi saya perlu memeriksa apakah ada string di python-2.x juga. Akan isinstance(x, str)bekerja seperti yang diharapkan di python-2.x? Atau apakah saya perlu memeriksa versi dan menggunakan isinstance(x, basestr)?

Secara khusus, dalam python-2.x:

>>>isinstance(u"test", str)
False

dan python-3.x tidak punya u"foo"

Randall Hunt
sumber
2
sintaks untuk Unicode literal diperkenalkan kembali dalam Python 3.3
jfs
Aneh. Saya mendapatkan `` `>>> isinstance (u" test ", basestring) Benar` `pada Python 2.7.16
Darakian

Jawaban:

209

Jika Anda menulis kode yang kompatibel dengan 2.x-dan-3.x, Anda mungkin ingin menggunakan enam :

from six import string_types
isinstance(s, string_types)
ecatmur
sumber
Maaf saya agak bingung tentang hasil berikut. >>> isinstance(u"foo", string_types) True >>> isinstance(u"foo".encode("utf-8"), string_types) True Saya mengharapkan isinstance (u "foo", string_types) mengembalikan false.
Chandler.Huang
1
@ Chandler.Huang pertanyaan ini adalah tentang mengidentifikasi strdan unicodemenggunakan Python 2, atau strPython 3. Jika Anda tidak ingin unicodemengandalkan Python 2, gunakan saja str.
ecatmur
@ecatmur woops, terima kasih! menghapusnya, jadi tidak ada yang bingung
runDOSrun
4
Anda juga dapat menggunakannya dari futurepaket alih-alih six:from future.utils import string_types
SuperGeo
113

Pendekatan paling singkat yang saya temukan tanpa bergantung pada paket seperti enam, adalah:

try:
  basestring
except NameError:
  basestring = str

kemudian, dengan anggapan Anda telah memeriksa string dengan Python 2 dengan cara yang paling umum,

isinstance(s, basestring)

sekarang juga akan berfungsi untuk Python 3+.

hbristow
sumber
10
Untuk py3, basestring = (str, bytes)darirequests/compat.py
Tanky Woo
Bagus, tapi mengapa? Alangkah baiknya jika Python3 akan kompatibel-mundur di sini. Solusi di atas berfungsi. Akan lebih baik, jika tidak ada kebutuhan untuk itu.
guettli
2
Untuk memuaskan dukungan py2 & 3 dan mypy, saya berakhir denganif not hasattr(__builtins__, "basestring"): basestring = (str, bytes)
Dave Lee
35

Bagaimana dengan ini, bekerja dalam semua kasus?

isinstance(x, ("".__class__, u"".__class__))
Fil
sumber
@holdenweb: Tidak dan ya - hack yang bagus "hanya berdampak jika perlu" saya pikir.
Dilettant
1
Alasan mengapa saya menyukai jawaban ini adalah karena ramah dengan migrasi dari python2 ke 3.
Tiagojdferreira
4
Saya juga pergi dengan opsi ini, membungkusnya dalam fungsi pembantu, jadi itu hanya muncul sekali, dan ada tempat di docstring untuk kredit Fil.
Carl Smith
2
Rapi, dan saya menggunakannya sendiri, sampai saya sadar bahwa saya juga sudah from __future__ import unicode_literalsaktif. Sekarang saya akan dengan:isinstance(val, (str, u"".__class__))
Graham Klyne
18

Ini adalah jawaban @Lev Levitsky, ditulis ulang sedikit.

try:
    isinstance("", basestring)
    def isstr(s):
        return isinstance(s, basestring)
except NameError:
    def isstr(s):
        return isinstance(s, str)

The try/ exceptuji dilakukan sekali, dan kemudian mendefinisikan fungsi yang selalu bekerja dan secepat mungkin.

EDIT: Sebenarnya, kita bahkan tidak perlu menelepon isinstance(); kita hanya perlu mengevaluasi basestringdan melihat apakah kita mendapatkan NameError:

try:
    basestring  # attempt to evaluate basestring
    def isstr(s):
        return isinstance(s, basestring)
except NameError:
    def isstr(s):
        return isinstance(s, str)

Saya pikir lebih mudah untuk mengikuti panggilan isinstance().

steveha
sumber
isinstance("", basestring)adalah apa yang saya maksud dengan "panggilan". Pokoknya, +1.
Lev Levitsky
1
Python adalah bahasa yang sangat dinamis, dan saya pikir tidak terlihat buruk sama sekali untuk melakukan tes seperti itu. Ini adalah teknik yang berguna untuk menentukan sesuatu pada suatu waktu, dan berdasarkan itu, mengatur fungsi yang akan selalu benar. Terima kasih untuk +1.
steveha
5
Saya akan menuliskannya sebagai:try: string_types = basestring except NameError: string_types = str
jfs
12

The futureperpustakaan menambahkan (untuk Python 2) nama-nama yang kompatibel , sehingga Anda dapat melanjutkan menulis Python 3 . Anda dapat dengan mudah melakukan hal berikut:

from builtins import str
isinstance(x, str) 

Untuk menginstalnya , jalankan saja pip install future.

Sebagai peringatan , itu hanya mendukung python>=2.6, >=3.3tetapi itu lebih modern daripada sixyang hanya disarankan jika menggunakanpython 2.5

toto_tico
sumber
8

Mungkin menggunakan solusi seperti

def isstr(s):
    try:
        return isinstance(s, basestring)
    except NameError:
        return isinstance(s, str)
Lev Levitsky
sumber
Maaf mengganggu Anda, tetapi isinstance(u'hello', basestr)menghasilkan SyntaxError: invalid syntaxbagi saya dengan Python 3.2.3 di bawah Window 7 .. tahu mengapa ini terjadi? Sepertinya tidak suka u- Saya mendapatkan kesalahan ini dengan strdanbasestr
Levon
1
@Levon Tidak masalah :) Itu karena Python3 tidak memiliki sintaks itu , seperti strpada Python3 menurut definisi Unicode. Oleh karena itu, tidak ada basestringtipe, maka NameErroryang tertangkap dalam cuplikan saya.
Lev Levitsky
Itu memang memiliki sintaks sebagai noop sekarang. dalam 3,3
Randall Hunt
2
Saya sarankan melakukan try / excepttes satu kali, dan berdasarkan hasil dari tes tunggal, Anda mendefinisikan isstr()dengan benar. Tidak perlu mengeluarkan overhead pengecualian untuk setiap panggilan isstr().
steveha
@Ranman benar tentang Python 3.3, ini tautan ke PEP .
Lev Levitsky
7

Anda bisa mendapatkan kelas suatu objek dengan memanggil object.__class__, jadi untuk memeriksa apakah objek adalah tipe string default:

    isinstance(object,"".__class__)

Dan Anda dapat menempatkan yang berikut ini di bagian atas kode Anda sehingga string yang dilampirkan dengan tanda kutip berada dalam unicode dengan python 2:

    from __future__ import unicode_literals
Martin Hansen
sumber
Saya solusi ini sedikit. Saya menemukan itu berguna untuk mendefinisikan str = "" .__ class__, yang sekarang memungkinkan isinstance (objek, str) ditulis secara normal, dan juga memastikan bahwa str (objek) akan mengembalikan string unicode baik dalam Python 2 dan Python 3.
amicitas
Ini tidak berfungsi saat mem-parsing XML: some_element.textadalah 'str' tetapi perbandingan dengan 'unicode' akan gagal
vault
Tidak berfungsi dengan string unicode pada python 2: isinstance (u'XXX ',' '.__ class__) == False
Fil
0

Anda dapat mencoba ini di awal kode Anda:

from __future__ import print_function
import sys
if sys.version[0] == "2":
    py3 = False
else:
    py3 = True
if py3: 
    basstring = str
else:
    basstring = basestring

dan kemudian dalam kode:

anystring = "test"
# anystring = 1
if isinstance(anystring, basstring):
    print("This is a string")
else:
    print("No string")
bunkus
sumber
0

Hati-hati! Dalam python 2, strdan bytespada dasarnya sama. Ini dapat menyebabkan bug jika Anda mencoba untuk membedakan keduanya.

>>> size = 5    
>>> byte_arr = bytes(size)
>>> isinstance(byte_arr, bytes)
True
>>> isinstance(byte_arr, str)
True
Fardin
sumber
-4

ketik (string) == str

mengembalikan true jika string, dan false jika tidak

confused_programmer241
sumber
1
Tidak berlaku untuk Python 2, di mana stringada string unicode
lxop