2010-05-30 39 views
43

Trong trăn có cách nào dễ dàng để biết liệu có gì đó không phải là một chuỗi không? Tôi cố gắng để chỉ: if x is not sequence nhưng trăn không thích điều đóPython: kiểm tra xem một đối tượng có phải là một chuỗi

+2

liên quan: Trong python, làm thế nào để xác định xem một biến là Iterable? http://stackoverflow.com/questions/1952464/in-python-how-do-i-determine-if-a-variable-is-iterable/1952481#1952481 – miku

+7

Đúng, nhưng trong khi tất cả các chuỗi có thể lặp lại không phải tất cả các lần lặp lại là chuỗi (bộ và dicts là các thùng chứa có thể lặp lại được tích hợp không phải là trình tự, ví dụ). –

Trả lời

57

iter(x) sẽ nâng cao một TypeError nếu x không thể được lặp trên - nhưng kiểm tra rằng "chấp nhận" bộ và từ điển, mặc dù nó là "từ chối" không trình tự khác chẳng hạn như None và số. Mặt khác, các chuỗi (hầu hết các ứng dụng muốn xem xét "các mục đơn lẻ" chứ không phải chuỗi) trong chuỗi thực tế (vì vậy, bất kỳ kiểm tra nào, trừ khi được đặc biệt cho chuỗi, sẽ xác nhận rằng chúng là) . Vì vậy, các kiểm tra đơn giản như vậy thường không đủ.

Trong Python 2.6 trở lên, lớp cơ sở trừu tượng được giới thiệu và trong số các tính năng mạnh khác, chúng cung cấp hỗ trợ tốt hơn, có hệ thống cho "kiểm tra danh mục" như vậy.

>>> import collections 
>>> isinstance([], collections.Sequence) 
True 
>>> isinstance((), collections.Sequence) 
True 
>>> isinstance(23, collections.Sequence) 
False 
>>> isinstance('foo', collections.Sequence) 
True 
>>> isinstance({}, collections.Sequence) 
False 
>>> isinstance(set(), collections.Sequence) 
False 

Bạn sẽ lưu ý chuỗi là vẫn coi là "một chuỗi" (vì họ ), nhưng ít nhất bạn có được dicts và bộ ra khỏi đường. Nếu bạn muốn loại trừ chuỗi khỏi khái niệm "chuỗi tự động" của mình, bạn có thể sử dụng collections.MutableSequence (nhưng cũng loại trừ bộ dữ liệu, như chuỗi, là chuỗi, nhưng không thể thay đổi) hoặc làm rõ ràng:

import collections 

def issequenceforme(obj): 
    if isinstance(obj, basestring): 
     return False 
    return isinstance(obj, collections.Sequence) 

Phần thưởng thức và phục vụ nóng! -)

+10

Lưu ý rằng ví dụ mã này sẽ trả về kết quả sai đối với các đối tượng thực hiện giao thức chuỗi nhưng không liên quan đến ABC collections.Sequence'. –

+4

Yep: khác với ABC đơn giản, Sequence không thực hiện phương thức lớp '__subclasshook__', vì vậy nó sẽ không bao giờ tự động nhận ra một lớp đã chọn không đăng ký' với nó (hoặc kế thừa từ nó) để biết được sự hiểu biết của một lớp '__getitem__' chấp nhận số nguyên và lát, tăng' IndexError' trên các chỉ mục sai, vv - tất cả bạn cần loại trừ 'dict' và' set', về cơ bản (rằng _do_ dường như "thực hiện chuỗi giao thức "nếu bạn chỉ cần làm nội tâm ... nhưng sau đó hóa ra là không! -). –

+0

Bộ dễ bị loại trừ vì chúng không có '__getitem__', nhưng ánh xạ khó hơn nhiều. Kiểm tra tốt nhất tôi đã nhìn thấy có lẽ là tìm kiếm 'keys', giống như' dict.update', nhưng vẫn còn rất nhiều điều mong muốn. – user2357112

4

Tại sao bạn làm điều này? Cách thông thường ở đây là yêu cầu một loại điều nhất định (Một chuỗi hoặc một số hoặc một đối tượng giống như tệp, v.v.) và sau đó sử dụng nó mà không kiểm tra bất kỳ thứ gì. Trong Python, chúng ta thường không sử dụng các lớp để mang thông tin ngữ nghĩa mà chỉ sử dụng các phương thức được định nghĩa (được gọi là "gõ vịt"). Chúng tôi cũng thích các API nơi chúng tôi biết chính xác những gì mong đợi; sử dụng các đối số từ khóa, tiền xử lý, hoặc định nghĩa một hàm khác nếu bạn muốn thay đổi cách một hàm hoạt động.

+3

Đó là ràng buộc chuyển nhượng. Nếu đối số mà chúng ta truyền vào không phải là int, long hay sequence, chúng ta cần phải tạo ra một 'TypeError' – nicotine

+1

@nicotine, nhận ra rằng phép gán này chỉ ra một thiết kế thường không phải là nonidiomatic và mong manh. Hãy xem xét trường hợp bình thường, nơi một đối tượng phải chính xác là một loại điều. Nếu một tham số được coi là một chuỗi nhưng bạn nhận được một int, khi bạn lập chỉ mục hoặc lặp lại nó, bạn sẽ nhận được một 'TypeError'. Tương tự, nếu bạn cố gắng thực hiện các phép toán số nguyên với một chuỗi bạn muốn. –

+0

Cung cấp một API nhất quán (khi có thể) chỉ mong đợi một loại điều cho phép bạn viết mã đơn giản hơn mà vẫn tăng lỗi khi có sự cố nhưng mạnh mẽ hơn ở chỗ nó hỗ trợ các kiểu mà bạn không nghĩ đến. mục tiêu (ví dụ, một số lớp tùy chỉnh thực hiện '__len__' và' __getitem__' sẽ hoạt động như một chuỗi.) –

6

Các Python 2.6.5 documentation mô tả các loại trình tự sau: chuỗi, chuỗi Unicode, danh sách, bộ đệm, bộ đệm và xrange.

def isSequence(obj): 
    return type(obj) in [str, unicode, list, tuple, buffer, xrange] 
+14

Vấn đề với câu trả lời này là nó sẽ không phát hiện chuỗi không phải là các loại nội trang. Một chuỗi "Python" là bất kỳ đối tượng nào thực hiện các phương thức cần thiết để đáp ứng các hoạt động chuỗi. – intuited

+3

Ngoài ra, sử dụng 'isinstance' thay cho' type' để hỗ trợ các lớp con. – bfontaine

-3

tại sao hỏi tại sao

thử nhận được một chiều dài và nếu ngoại lệ trả về false

def haslength(seq): 
    try: 
     len(seq) 
    except: 
     return False 
    return True 
+1

Một tập hợp 'có độ dài nhưng không phải là một chuỗi. – bfontaine

4

Kể từ Python "tuân thủ" gõ vịt, một trong những phương pháp này là để kiểm tra xem một đối tượng có một số thành viên (phương pháp).

Một chuỗi có độ dài, có chuỗi các mục và hỗ trợ cắt [doc]. Vì vậy, nó sẽ là như thế này:

def is_sequence(obj): 
    t = type(obj) 
    return hasattr(t, '__len__') and hasattr(t, '__getitem__') 
    # additionally: and hasattr(t, '__setitem__') and hasattr(t, '__delitem__') 

Họ đều là những phương pháp đặc biệt, __len__() nên trả lại số hạng mục, __getitem__(i) nên trở về một mục (theo thứ tự đó là i mục -thứ, nhưng không phải với lập bản đồ), __getitem__(slice(start, stop, step)) phải trả về các hậu tố và __setitem____delitem__ như bạn mong đợi.Đây là một hợp đồng như vậy, nhưng liệu đối tượng có thực sự làm những điều này hay không phụ thuộc vào việc liệu đối tượng có tuân theo hợp đồng hay không.

Lưu ý rằng, hàm ở trên cũng sẽ trả về True để ánh xạ, ví dụ: dict, vì ánh xạ cũng có các phương thức này. Để khắc phục điều này, bạn có thể làm một nặng công việc:

def is_sequence(obj): 
    try: 
     len(obj) 
     obj[0:0] 
     return True 
    except TypeError: 
     return False 

Nhưng hầu hết thời gian bạn không cần điều này, chỉ cần làm những gì bạn muốn là nếu đối tượng là một chuỗi và bắt một ngoại lệ nếu bạn ước. Điều này là nhiều hơn pythonic.

+0

Điểm quan trọng về dict là nếu bạn đối xử với nó như một chuỗi bạn sẽ chỉ nhận được các khóa, không phải là các giá trị, và thông tin sẽ bị mất. –

+2

Nếu sử dụng 'hasattr()', bạn cần phải kiểm tra loại đối tượng cho các phương pháp ma thuật, không phải đối tượng đó. Xem [Python 2] (https://docs.python.org/2/reference/datamodel.html#special-method-lookup-for-new-style-classes) và [Python 3] (https: // docs Tài liệu .python.org/3/reference/datamodel.html # special-method-lookup) về cách các phương thức đặc biệt được tìm kiếm. – augurar

+0

@augurar Cảm ơn người đàn ông – BornToCode

4

Tôi nghĩ rằng đoạn mã dưới đây làm những gì bạn muốn:

def is_sequence(obj): 
    return hasattr(type(obj), '__iter__') 
+2

Nên là 'hasattr (type (obj), '__iter __')', xem [bình luận này] (https://stackoverflow.com/questions/2937114/#comment71833903_31043360). – augurar

Các vấn đề liên quan