2009-05-07 22 views
60

Tôi có một thường trình lấy danh sách các chuỗi như một tham số, nhưng tôi muốn hỗ trợ truyền vào một chuỗi đơn và chuyển đổi nó thành danh sách một chuỗi. Ví dụ:Làm cách nào để biết biến số python là chuỗi hay danh sách?

def func(files): 
    for f in files: 
     doSomethingWithFile(f) 

func(['file1','file2','file3']) 

func('file1') # should be treated like ['file1'] 

Làm cách nào để chức năng của tôi có thể cho biết chuỗi hoặc danh sách đã được chuyển vào? Tôi biết có một chức năng type, nhưng có cách nào "có nhiều sắc" hơn không?

Trả lời

36

Vâng, không có gì lạ khi kiểm tra loại. Có nói rằng, nếu bạn sẵn sàng để đặt một gánh nặng nhỏ trên người gọi:

def func(*files): 
    for f in files: 
     doSomethingWithFile(f) 

func(*['file1','file2','file3']) #Is treated like func('file1','file2','file3') 
func('file1') 

tôi muốn tranh luận này là pythonic hơn ở chỗ "rõ ràng là tốt hơn so với tiềm ẩn". Ở đây có ít nhất một sự công nhận trên một phần của người gọi khi đầu vào đã có trong danh sách mẫu.

+9

Chắc chắn phương pháp "rõ ràng" hơn sẽ yêu cầu người dùng chuyển một tệp đơn trong danh sách? Giống như func (['file1']) – dbr

+1

Tôi đồng ý rằng điều đó là rõ ràng, nhưng tôi không thấy nó rõ ràng hơn. Cả hai kỹ thuật đều sử dụng cùng một logic; một là ngược lại. Tôi tình cờ nghĩ rằng ở trên là hơi trực quan hơn, bởi vì nó nhấn mạnh rằng các tập tin trong danh sách chứ không phải là danh sách chính nó có liên quan đến func. –

43
isinstance(your_var, basestring) 
+3

Giải pháp này cần một số giải thích, một số ngữ cảnh. Cả your_var lẫn basestring đều không có trong bài viết của OP. –

+2

Điều này không hoạt động từ Python 3. Sử dụng 'isinstance (your_var, str)'. –

32

Cá nhân, tôi không thực sự thích loại hành vi này - nó cản trở việc nhập vịt. Người ta có thể lập luận rằng nó không tuân theo câu thần chú "Rõ ràng là tốt hơn là ngầm". Tại sao không sử dụng cú pháp varargs:

def func(*files): 
    for f in files: 
     doSomethingWithFile(f) 

func('file1', 'file2', 'file3') 
func('file1') 
func(*listOfFiles) 
+1

"Cá nhân, tôi không thực sự thích loại hành vi này", bạn đang đề cập đến điều gì? –

+0

@ nemo Tôi nghĩ rằng anh ấy có nghĩa là câu hỏi ban đầu, có thể được hiểu là yêu cầu một hàm có tham số là chuỗi hoặc danh sách các chuỗi trong đó cuộc gọi hàm không đề cập đến loại tham số nào được chuyển. Tôi đồng ý với điều này . –

+0

FWIW, varargs chỉ hoạt động nếu không có arg khác: 'func (file, someflag)', không thể chuyển thành 'func (* files, someflag)' mà không chuyển 'someflag' thành từ khóa arg – pjz

15

Tôi sẽ nói cách Python nhất là làm cho người dùng luôn chuyển danh sách, ngay cả khi chỉ có một mục trong đó. Nó làm cho nó thực sự rõ ràng func() có thể mất một danh sách các file

def func(files): 
    for cur_file in files: 
     blah(cur_file) 

func(['file1']) 

Theo Dave gợi ý, bạn có thể sử dụng cú pháp func(*files), nhưng tôi chưa bao giờ thích tính năng này, và nó có vẻ rõ ràng hơn ("rõ ràng là tốt hơn so với tiềm ẩn") chỉ cần yêu cầu một danh sách. Nó cũng biến trường hợp đặc biệt của bạn (gọi func với một tệp) thành trường hợp mặc định, bởi vì bây giờ bạn phải sử dụng cú pháp bổ sung để gọi func với danh sách ..

Nếu bạn muốn tạo một trường hợp đặc biệt cho một cuộc tranh cãi là một chuỗi, sử dụng isinstance() builtin, và so sánh với basestring (mà cả hai str()unicode() có nguồn gốc từ) ví dụ:

def func(files): 
    if isinstance(files, basestring): 
     doSomethingWithASingleFile(files) 
    else: 
     for f in files: 
      doSomethingWithFile(f) 

Thực sự, tôi khuyên bạn nên chỉ đơn giản đòi hỏi một danh sách, thậm chí chỉ với một tập tin (sau khi tất cả, nó chỉ đòi hỏi hai nhân vật phụ!)

+10

Vấn đề là nếu bạn chỉ dựa vào việc gõ vịt ở đây, một chuỗi * được * xử lý như một danh sách với cách gõ vịt, và không làm điều đúng. Thay vì xử lý nó như một mục duy nhất, python sẽ xử lý chuỗi như một danh sách các ký tự. Whups. –

10
if hasattr(f, 'lower'): print "I'm string like" 
+0

Một giải pháp rất đơn giản hoạt động hoàn hảo cho tôi. Cảm ơn! –

+3

hoạt động cho đến khi ai đó chuyển cho bạn bộ sưu tập có phương pháp 'thấp hơn trên đó: -/ – AlexChaffee

+1

^chẳng hạn như đối tượng toán học hoặc đối tượng có giao diện với chức năng thế giới thực chẳng hạn như tăng hoặc giảm cửa sổ được điều khiển bằng máy. :) –

3

Varargs đã gây nhầm lẫn cho tôi, vì vậy tôi đã thử nghiệm nó trong Python để xóa nó cho bản thân mình.

Trước hết PEP cho vararg là here.

Đây là chương trình mẫu, dựa trên hai câu trả lời từ Dave và David Berger, tiếp theo là đầu ra, chỉ để làm rõ.

def func(*files): 
    print files 
    for f in files: 
     print(f) 

if __name__ == '__main__': 
    func(*['file1','file2','file3']) #Is treated like func('file1','file2','file3') 
    func('onestring') 
    func('thing1','thing2','thing3') 
    func(['stuff1','stuff2','stuff3']) 

Và kết quả đầu ra;

('file1', 'file2', 'file3') 
file1 
file2 
file3 
('onestring',) 
onestring 
('thing1', 'thing2', 'thing3') 
thing1 
thing2 
thing3 
(['stuff1', 'stuff2', 'stuff3'],) 
['stuff1', 'stuff2', 'stuff3'] 

Hy vọng điều này hữu ích cho người khác.

10
def func(files): 
    for f in files if not isinstance(files, basestring) else [files]: 
     doSomethingWithFile(f) 

func(['file1', 'file2', 'file3']) 

func('file1') 
+0

POP 8 dường như thích isinstance (u'abc ', basestring) thay vì sử dụng mô-đun kiểu. – max

+0

@mdorseif: Tôi đã chỉnh sửa câu trả lời để sử dụng 'basestring' thay vì mô-đun' loại'. – jfs

6

Nếu bạn có quyền kiểm soát nhiều hơn người gọi, sau đó một trong những câu trả lời khác là tốt hơn. Tôi không có mà sang trọng trong trường hợp của tôi vì vậy tôi quyết định chọn giải pháp sau đây (với hãy cẩn thận):

def islistlike(v): 
    """Return True if v is a non-string sequence and is iterable. Note that 
    not all objects with getitem() have the iterable attribute""" 
    if hasattr(v, '__iter__') and not isinstance(v, basestring): 
     return True 
    else: 
     #This will happen for most atomic types like numbers and strings 
     return False 

Cách tiếp cận này sẽ làm việc cho trường hợp bạn đang đối phó với một bí quyết thiết lập các loại danh sách giống như đáp ứng các tiêu chí trên. Một số loại trình tự sẽ bị bỏ qua.

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