a

Câu hỏi Làm cách nào để kiểm tra xem tệp có tồn tại không?


Làm cách nào để xem liệu tệp có tồn tại hay không, mà không sử dụng try tuyên bố?


4361
2017-09-17 12:55


gốc




Các câu trả lời:


Nếu lý do bạn kiểm tra là bạn có thể làm một việc như if file_exists: open_it(), an toàn hơn để sử dụng try xung quanh nỗ lực mở nó. Kiểm tra và sau đó mở các rủi ro tệp bị xóa hoặc di chuyển hoặc một cái gì đó giữa khi bạn kiểm tra và khi bạn cố mở nó.

Nếu bạn không định mở tệp ngay lập tức, bạn có thể sử dụng os.path.isfile

Trở về True nếu đường dẫn là một tệp thông thường hiện có. Điều này theo các liên kết tượng trưng, ​​vì vậy cả hai islink () và isfile () có thể đúng cho cùng một đường dẫn.

import os.path
os.path.isfile(fname) 

nếu bạn cần chắc chắn đó là một tập tin.

Bắt đầu với Python 3.4, pathlib mô-đun cung cấp một cách tiếp cận hướng đối tượng (backported to pathlib2 trong Python 2.7):

from pathlib import Path

my_file = Path("/path/to/file")
if my_file.is_file():
    # file exists

Để kiểm tra một thư mục, hãy làm:

if my_file.is_dir():
    # directory exists

Để kiểm tra xem liệu Path đối tượng tồn tại độc lập cho dù đó là một tệp hoặc thư mục, sử dụng exists():

if my_file.exists():
    # path exists

Bạn cũng có thể dùng resolve() trong một try khối:

try:
    my_abs_path = my_file.resolve()
except FileNotFoundError:
    # doesn't exist
else:
    # exists

3963
2017-09-17 12:57



liên quan đến nhận xét đầu tiên (sử dụng "thử" nếu kiểm tra trước khi mở) tiếc là điều này sẽ không hoạt động nếu bạn muốn mở để gắn thêm chắc chắn nó tồn tại trước khi chế độ 'a' sẽ tạo nếu không tồn tại. - makapuf
tôi có os.path.isfile không tồn tại. - JeromeJ


Bạn có os.path.exists chức năng:

import os.path
os.path.exists(file_path)

Điều này trả về True cho cả tệp và thư mục nhưng thay vào đó bạn có thể sử dụng

os.path.isfile(file_name)

để kiểm tra xem đó có phải là một tập tin cụ thể không. Nó tuân theo các liên kết tượng trưng.


1626
2017-09-17 12:57





không giống isfile(), exists() sẽ trở lại True cho các thư mục.
Vì vậy, tùy thuộc vào nếu bạn chỉ muốn các tệp đơn thuần hoặc các thư mục, bạn sẽ sử dụng isfile() hoặc là exists(). Đây là một đầu ra REPL đơn giản.

>>> print os.path.isfile("/etc/password.txt")
True
>>> print os.path.isfile("/etc")
False
>>> print os.path.isfile("/does/not/exist")
False
>>> print os.path.exists("/etc/password.txt")
True
>>> print os.path.exists("/etc")
True
>>> print os.path.exists("/does/not/exist")
False

837
2017-09-17 15:01





import os.path

if os.path.isfile(filepath):

468
2017-09-17 12:55





Sử dụng os.path.isfile() với os.access():

import os
import os.path

PATH='./file.txt'

if os.path.isfile(PATH) and os.access(PATH, os.R_OK):
    print "File exists and is readable"
else:
    print "Either the file is missing or not readable"

223
2018-01-16 05:57



có nhiều điều kiện, một số điều là thừa, là ít hơn rõ ràng và rõ ràng. - wim
Nó cũng thừa. Nếu tệp không tồn tại, os.access() sẽ trả về false. - user207421
@EJP Trong các tập tin linux có thể tồn tại nhưng không accesible. - e-info128


import os
os.path.exists(path) # Returns whether the path (directory or file) exists or not
os.path.isfile(path) # Returns whether the file exists or not

209
2017-09-17 12:56



Câu trả lời này là sai. os.path.exists trả về true cho những thứ không phải là các tệp, chẳng hạn như các thư mục. Điều này cho kết quả dương tính giả. Xem các câu trả lời khác đề xuất os.path.isfile. - Chris Johnson
Thư mục là một loại tệp unix.stackexchange.com/questions/197439/… - James Roth


Đây là cách đơn giản nhất để kiểm tra xem tệp có tồn tại hay không. Chỉ bởi vì tệp tồn tại khi bạn đã chọn không Bảo hành rằng nó sẽ ở đó khi bạn cần mở nó.

import os
fname = "foo.txt"
if os.path.isfile(fname):
    print("file does exist at this time")
else:
    print("no such file exists at this time")

139
2018-06-27 13:38



Miễn là bạn định truy cập tệp, điều kiện chủng tộc không tồn tại, bất kể chương trình của bạn được xây dựng như thế nào. Chương trình của bạn không thể đảm bảo rằng một quá trình khác trên máy tính chưa sửa đổi tệp. Đó là những gì Eric Lippert gọi là ngoại lệ ngoại sinh. Bạn không thể tránh nó bằng cách kiểm tra sự tồn tại của tập tin trước. - Isaac Supeene
@IsaacSupeene Thực hành tốt nhất là làm cho cửa sổ của (tệp) hoạt động càng nhỏ càng tốt theo sau là một xử lý ngoại lệ thích hợp - un33k


2017/12/22:

Mặc dù hầu hết mọi cách có thể đã được liệt kê trong (ít nhất một trong số) câu trả lời hiện có (ví dụ: Python 3.4 công cụ cụ thể đã được thêm), tôi sẽ cố gắng nhóm mọi thứ lại với nhau.

chú thích: mọi phần của Python mã thư viện chuẩn mà tôi sẽ đăng, thuộc về phiên bản 3.5.3 (Trích dẫn doc là phiên bản 3 riêng).

Báo cáo vấn đề:

  1. Kiểm tra tệp (đáng tranh cãi: cũng thư mục ("đặc biệt" tập tin)?) Sự tồn tại
  2. Không sử dụng try / except / else / finally khối

Phương pháp khả thi:

  1. [Python]: os.path.tồn tại(con đường) (cũng kiểm tra các thành viên gia đình chức năng khác như os.path.isfile, os.path.isdir, os.path.lexists cho các hành vi hơi khác nhau)

    os.path.exists(path)
    

    Trở về True nếu con đường đề cập đến một đường dẫn hiện có hoặc một bộ mô tả tệp mở. Trả lại False cho các liên kết tượng trưng bị hỏng. Trên một số nền tảng, chức năng này có thể trở lại False nếu quyền không được cấp để thực thi os.stat () trên tệp được yêu cầu, ngay cả khi con đường thể chất tồn tại.

    Tất cả tốt, nhưng nếu sau cây nhập khẩu:

    • os.path - - posixpath.py (ntpath.py)

      • genericpath.py, hàng ~ # 20 +

        def exists(path):
            """Test whether a path exists.  Returns False for broken symbolic links"""
            try:
                st = os.stat(path)
            except os.error:
                return False
            return True
        

    nó chỉ là một try/except chặn xung quanh [Python]: os.stat(đường dẫn, *, dir_fd = Không, follow_symlinks = True). Vì vậy, mã của bạn là try/except miễn phí, nhưng thấp hơn trong framestack có (ít nhất) một khối đó. Điều này cũng áp dụng cho các func khác (kể cả  os.path.isfile).

    1.1. [Python]: pathlib.Path.is_file()

    • Đó là một fancier (và nhiều hơn nữa con trănic) cách xử lý đường dẫn, nhưng
    • Dưới mui xe, nó chính xác giống nhau cả thôi (pathlib.py, hàng ~ # 1330):

      def is_file(self):
          """
          Whether this path is a regular file (also True for symlinks pointing
          to regular files).
          """
          try:
              return S_ISREG(self.stat().st_mode)
          except OSError as e:
              if e.errno not in (ENOENT, ENOTDIR):
                  raise
              # Path doesn't exist or is a broken symlink
              # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
              return False
      
  2. [Python]: Với người quản lý ngữ cảnh tuyên bố. Hoặc:

    • Tạo một cái:

      class Swallow:  # Dummy example
          swallowed_exceptions = (FileNotFoundError,)
      
          def __enter__(self):
              print("Entering...")
      
          def __exit__(self, exc_type, exc_value, exc_traceback):
              print("Exiting:", exc_type, exc_value, exc_traceback)
              return exc_type in Swallow.swallowed_exceptions  # only swallow FileNotFoundError (not e.g. TypeError - if the user passes a wrong argument like None or float or ...)
      
      • Và việc sử dụng nó - tôi sẽ tái tạo isfile hành vi (lưu ý rằng đây chỉ là để chứng minh mục đích, làm không phải cố gắng viết mã như vậy cho sản xuất):

        import os
        import stat
        
        
        def isfile_seaman(path):  # Dummy func
            result = False
            with Swallow():
                result = stat.S_ISREG(os.stat(path).st_mode)
            return result
        
    • Sử dụng [Python]: contextlib.ngăn chặn(* ngoại lệ) - cái mà đặc biệt được thiết kế để loại bỏ các ngoại lệ có chọn lọc


    Nhưng, họ dường như được đóng gói hơn try/except/else/finally khối, như [Python]: The với tuyên bố tiểu bang:

    Điều này cho phép phổ biến thử...ngoại trừ...cuối cùng các mẫu sử dụng được đóng gói để tái sử dụng thuận tiện.

  3. Các hàm truyền tải của hệ thống tập tin (và tìm kiếm kết quả cho (các) mục phù hợp)


    Kể từ khi các iterate trên thư mục, (trong hầu hết các trường hợp) họ không hiệu quả cho vấn đề của chúng tôi (có những trường hợp ngoại lệ, như không ký tự đại diện globbing - như @ShadowRanger chỉ ra), vì vậy tôi sẽ không nhấn mạnh vào chúng. Chưa kể rằng trong một số trường hợp, việc xử lý tên tệp có thể được yêu cầu.

  4. [Python]: os.truy cập(đường dẫn, chế độ, *, dir_fd = Không, effective_ids = False, follow_symlinks = True) có hành vi gần với os.path.exists (thực sự nó rộng hơn, chủ yếu là vì 2nd tranh luận)

    • Quyền Người dùng có thể hạn chế tệp "mức hiển thị" khi trạng thái của tài liệu:

      ... kiểm tra xem người dùng đang gọi có quyền truy cập được chỉ định đến con đường. chế độ nên là F_OK để kiểm tra sự tồn tại của đường dẫn ...

    os.access("/tmp", os.F_OK)
    

    Vì tôi cũng làm việc C, Tôi cũng sử dụng phương pháp này vì dưới mui xe, nó gọi tự nhiên APIS (một lần nữa, qua "$ {PYTHON_SRC_DIR} /Modules/posixmodule.c"), nhưng nó cũng mở ra một cổng cho có thể lỗi người dùngvà nó không phải là Pythonic như các biến thể khác. Vì vậy, như @AaronHall đã chỉ ra đúng, không sử dụng nó trừ khi bạn biết những gì bạn đang làm:

    chú thích: gọi cho người bản xứ APIs cũng có thể qua [Python]: ctypes - Thư viện hàm ngoại ngữ cho Python, nhưng trong hầu hết các trường hợp, nó phức tạp hơn.

    (Thắng lợi cụ thể): Từ msvcr *(vcruntime *) xuất khẩu [MSDN]: _access, _waccess gia đình chức năng là tốt, đây là một ví dụ:

    Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import os, ctypes
    >>> ctypes.CDLL("msvcrt")._waccess(u"C:\\Windows\\System32\\cmd.exe", os.F_OK)
    0
    >>> ctypes.CDLL("msvcrt")._waccess(u"C:\\Windows\\System32\\___cmd.exe", os.F_OK)
    -1
    

    Ghi chú:

    • Mặc dù nó không phải là một thực hành tốt, tôi đang sử dụng os.F_OK trong cuộc gọi, nhưng đó chỉ là sự rõ ràng (giá trị của nó là 0)
    • Tôi đang sử dụng _waccess để cùng một mã hoạt động trên Python3 và Python2 (mặc dù unicode sự khác biệt liên quan giữa chúng)
    • Mặc dù điều này nhắm vào một khu vực rất cụ thể, nó không được đề cập trong bất kỳ câu trả lời nào trước đây


    Các Lnx (Ubtu (16 x64)) đối tác là tốt:

    Python 3.5.2 (default, Nov 17 2016, 17:05:23)
    [GCC 5.4.0 20160609] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import os, ctypes
    >>> ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6").access(b"/tmp", os.F_OK)
    0
    >>> ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6").access(b"/tmp1", os.F_OK)
    -1
    

    Ghi chú:

    • Thay vào đó hardcoding libcĐường dẫn của ("/lib/x86_64-linux-gnu/libc.so.6") có thể (và rất có thể, sẽ) khác nhau giữa các hệ thống, None (hoặc chuỗi rỗng) có thể được chuyển đến CDLL constructor (ctypes.CDLL(None).access(b"/tmp", os.F_OK)). Theo [người đàn ông]: DLOPEN (3):

      Nếu tên tệp là NULL, sau đó xử lý trả về là cho chính   chương trình. Khi được trao cho dlsym(), xử lý này khiến tìm kiếm   biểu tượng trong chương trình chính, theo sau là tất cả các đối tượng được chia sẻ được tải tại   khởi động chương trình, và sau đó tất cả các đối tượng dùng chung được tải bởi dlopen() với   lá cờ RTLD_GLOBAL.

      • Chương trình chính (hiện tại) (con trăn) được liên kết với libc, do đó, biểu tượng của nó (bao gồm access) sẽ được tải
      • Điều này phải được xử lý cẩn thận, vì các chức năng như main, Py_Main và (tất cả) những người khác có sẵn; gọi họ có thể có hiệu ứng tai hại (trên chương trình hiện tại)
      • Điều này cũng không áp dụng cho Thắng lợi (nhưng đó không phải là một vấn đề lớn, kể từ đó msvcrt.dllnằm ở "% SystemRoot% \ System32" cái nào ở trong %CON ĐƯỜNG% theo mặc định). Tôi muốn tiến xa hơn và nhân rộng hành vi này Thắng lợi (và gửi một bản vá), nhưng khi nó quay ra, [MSDN]: Hàm GetProcAddress chỉ "thấy" đã xuất biểu tượng, vì vậy, trừ khi ai đó khai báo các hàm trong tệp thực thi chính là __declspec(dllexport) (tại sao trên trái đất đều đặn người đó sẽ làm điều đó?), chương trình chính có thể tải được nhưng khá nhiều không sử dụng được
  5. Cài đặt một số 3rd Mô-đun bên có khả năng hệ thống tệp

    Nhiều khả năng, sẽ dựa vào một trong những cách trên (có thể với các tùy chỉnh nhỏ).
    Một ví dụ sẽ là (một lần nữa, Thắng lợi riêng) [GitHub]: Python cho Windows (pywin32) Tiện ích mở rộng, mà là một Python bọc lại WINAPIS.

    Nhưng, vì điều này giống như một cách giải quyết khác, tôi dừng ở đây.

  6. Giải pháp khác (lame) (gainarie) (như tôi muốn gọi nó,) sysadmin cách tiếp cận: sử dụng Python như một trình bao bọc để thực thi các lệnh shell

    • Thắng lợi:

      (py35x64_test) e:\Work\Dev\StackOverflow\q000082831>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os; print(os.system('dir /b \"C:\\Windows\\System32\\cmd.exe\" > nul 2>&1'))"
      0
      
      (py35x64_test) e:\Work\Dev\StackOverflow\q000082831>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os; print(os.system('dir /b \"C:\\Windows\\System32\\cmd.exe.notexist\" > nul 2>&1'))"
      1
      
    • Lnx (Ubtu):

      [cfati@cfati-ubtu16x64-0:~]> python3 -c "import os; print(os.system('ls \"/tmp\" > /dev/null 2>&1'))"
      0
      [cfati@cfati-ubtu16x64-0:~]> python3 -c "import os; print(os.system('ls \"/tmp.notexist\" > /dev/null 2>&1'))"
      512
      

Tóm lại:

  • Làm sử dụng try / except / else / finally các khối, bởi vì chúng có thể ngăn bạn chạy vào một loạt các vấn đề khó chịu. Một ví dụ mà tôi có thể nghĩ đến là hiệu suất: các khối như vậy tốn kém, vì vậy hãy thử không đặt chúng trong mã mà nó phải chạy hàng trăm nghìn lần mỗi giây (nhưng vì (trong hầu hết các trường hợp) nó liên quan đến truy cập đĩa, nó sẽ không phải là trường hợp).

Ghi chú cuối cùng (s):

  • Tôi sẽ cố gắng giữ cho nó cập nhật, bất kỳ đề nghị được chào đón, tôi sẽ kết hợp bất cứ điều gì hữu ích mà sẽ đi vào câu trả lời

137
2018-06-20 19:28



Bạn có thể xây dựng trên tuyên bố này không? "Mặc dù nó không phải là một thực hành tốt, tôi đang sử dụng os.F_OK trong cuộc gọi, nhưng đó chỉ là cho rõ ràng (giá trị của nó là 0)" - sk8asd123
@ sk8asd123: Loại khó để doo nó trong một bình luận: nói chung, nó là tốt nhất để sử dụng hằng số với các chức năng mà họ đến với nhau. Điều đó áp dụng khi làm việc với nhiều mô-đun xác định cùng một hằng số, bởi vì một số có thể không được cập nhật và tốt nhất cho các hàm và hằng số được đồng bộ hóa. Khi làm việc với ctypes (gọi các hàm trực tiếp) Tôi nên xác định hằng số (từ MSDN), hoặc không sử dụng một hằng số nào cả. Nó chỉ là một hướng dẫn mà tôi sử dụng, trong 99,9% nó có thể làm cho không có sự khác biệt (chức năng). - CristiFati
@CristiFati: Tính đến 3,6, glob.iglob (và glob.glob là tốt) được dựa trên os.scandir, bây giờ là lười biếng; để có được lần truy cập đầu tiên trong một thư mục gồm 10 triệu tệp, bạn chỉ quét cho đến khi bạn đạt đến lần truy cập đầu tiên. Và thậm chí trước 3.6, nếu bạn sử dụng glob phương pháp w / o bất kỳ ký tự đại diện nào, chức năng là thông minh: Nó biết bạn chỉ có thể có một lần truy cập, vì vậy nó đơn giản hóa việc sử dụng os.path.isdir hoặc là os.path.lexists (tùy thuộc vào việc con đường kết thúc bằng /). - ShadowRanger
Đó là một phần thứ hai của bình luận của tôi (globcard không wildcarded không thực sự lặp lại các thư mục, và không bao giờ có) không có nghĩa là nó là một giải pháp hoàn hảo hiệu quả cho vấn đề (chậm hơn so với gọi trực tiếp os.path.isdir hoặc là os.path.lexist vì nó là một chuỗi các cuộc gọi hàm và các hoạt động chuỗi của Python trước khi nó quyết định đường dẫn hiệu quả là khả thi, nhưng không có cuộc gọi hệ thống hoặc công việc I / O nào, đó là các đơn đặt hàng có cường độ chậm hơn). - ShadowRanger


Python 3.4+ có một mô-đun đường dẫn hướng đối tượng: pathlib. Sử dụng mô-đun mới này, bạn có thể kiểm tra xem tệp có tồn tại như thế này không:

import pathlib
p = pathlib.Path('path/to/file')
if p.is_file():  # or p.is_dir() to see if it is a directory
    # do stuff

Bạn có thể (và thường nên) vẫn sử dụng try/except chặn khi mở tệp:

try:
    with p.open() as f:
        # do awesome stuff
except OSError:
    print('Well darn.')

Các mô-đun pathlib có rất nhiều thứ thú vị trong nó: globbing thuận tiện, kiểm tra chủ sở hữu của tập tin, dễ dàng hơn tham gia đường dẫn, vv Đó là giá trị kiểm tra ra. Nếu bạn đang sử dụng Python cũ (phiên bản 2.6 hoặc mới hơn), bạn vẫn có thể cài đặt pathlib bằng pip:

# installs pathlib2 on older Python versions
# the original third-party module, pathlib, is no longer maintained.
pip install pathlib2

Sau đó, nhập nó như sau:

# Older Python versions
import pathlib2 as pathlib

121
2018-02-08 02:38





Thích câu lệnh thử. Nó được coi là phong cách tốt hơn và tránh điều kiện chủng tộc.

Đừng dùng từ ngữ của tôi cho nó. Có rất nhiều hỗ trợ cho lý thuyết này. Đây là một cặp vợ chồng:


111
2017-11-04 00:48



Vui lòng thêm các nguồn tốt hơn để hỗ trợ tuyên bố của bạn. - BlueTrin
Liên kết Tránh Điều kiện Race (liên kết hỗ trợ Apple dev) được trích dẫn không hỗ trợ câu trả lời của bạn. Nó chỉ liên quan đến việc sử dụng các tệp tạm thời có chứa thông tin nhạy cảm trên các hệ điều hành được thiết kế kém, không được sandbox tạm thời các tệp / thư mục tạm thời thông qua các quyền hạn chế. Sử dụng try...except không giúp giải quyết cái đó dù sao đi nữa. - jstine
Mặc dù liên kết này có thể trả lời câu hỏi, nhưng tốt hơn nên đưa các phần quan trọng của câu trả lời vào đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở thành không hợp lệ nếu trang được liên kết thay đổi. - - Từ đánh giá - user3483203
@chrisz Tôi không nghĩ rằng đó là liên kết chỉ - nó thực sự có thông tin khác với liên kết. - EJoshuaS


Làm cách nào để kiểm tra xem tệp có tồn tại hay không, sử dụng Python, mà không sử dụng câu lệnh thử?

Bây giờ đã có từ Python 3.4, nhập và khởi tạo Path đối tượng với tên tệp và kiểm tra is_file phương thức (lưu ý rằng điều này trả về True cho các liên kết tượng trưng trỏ đến các tệp thông thường):

>>> from pathlib import Path
>>> Path('/').is_file()
False
>>> Path('/initrd.img').is_file()
True
>>> Path('/doesnotexist').is_file()
False

Nếu bạn đang sử dụng Python 2, bạn có thể backport mô-đun pathlib từ pypi, pathlib2hoặc kiểm tra bằng cách khác isfile từ os.path module:

>>> import os
>>> os.path.isfile('/')
False
>>> os.path.isfile('/initrd.img')
True
>>> os.path.isfile('/doesnotexist')
False

Bây giờ ở trên có lẽ là câu trả lời trực tiếp thực dụng tốt nhất ở đây, nhưng có khả năng của một điều kiện chủng tộc (tùy thuộc vào những gì bạn đang cố gắng để thực hiện), và thực tế là việc thực hiện cơ bản sử dụng một try, nhưng Python sử dụng try ở khắp mọi nơi trong việc thực hiện nó.

Bởi vì Python sử dụng try ở khắp mọi nơi, thực sự không có lý do gì để tránh việc triển khai sử dụng nó.

Nhưng phần còn lại của câu trả lời này cố gắng xem xét những điều này.

Câu trả lời dài hơn, nhiều hơn nữa

Có sẵn từ Python 3.4, sử dụng mới Path đối tượng trong pathlib. Lưu ý rằng .exists không hoàn toàn đúng, bởi vì các thư mục không phải là các tệp (ngoại trừ theo nghĩa unix mọi điều là một tệp).

>>> from pathlib import Path
>>> root = Path('/')
>>> root.exists()
True

Vì vậy, chúng ta cần phải sử dụng is_file:

>>> root.is_file()
False

Đây là trợ giúp về is_file:

is_file(self)
    Whether this path is a regular file (also True for symlinks pointing
    to regular files).

Vì vậy, hãy lấy một tệp mà chúng tôi biết là một tệp:

>>> import tempfile
>>> file = tempfile.NamedTemporaryFile()
>>> filepathobj = Path(file.name)
>>> filepathobj.is_file()
True
>>> filepathobj.exists()
True

Theo mặc định, NamedTemporaryFile xóa tệp khi đóng (và sẽ tự động đóng khi không còn tham chiếu nữa).

>>> del file
>>> filepathobj.exists()
False
>>> filepathobj.is_file()
False

Nếu bạn đào sâu vào việc thực hiện, tuy nhiên, bạn sẽ thấy rằng is_file sử dụng try:

def is_file(self):
    """
    Whether this path is a regular file (also True for symlinks pointing
    to regular files).
    """
    try:
        return S_ISREG(self.stat().st_mode)
    except OSError as e:
        if e.errno not in (ENOENT, ENOTDIR):
            raise
        # Path doesn't exist or is a broken symlink
        # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
        return False

Điều kiện chủng tộc: Tại sao chúng tôi thích thử

Chúng tôi thích try bởi vì nó tránh điều kiện chủng tộc. Với try, bạn chỉ cần cố gắng đọc tệp của bạn, mong đợi nó ở đó, và nếu không, bạn bắt ngoại lệ và thực hiện bất kỳ hành vi dự phòng nào có ý nghĩa.

Nếu bạn muốn kiểm tra xem tệp có tồn tại trước khi bạn cố gắng đọc hay không và bạn có thể xóa nó và sau đó bạn có thể đang sử dụng nhiều luồng hoặc quy trình hoặc chương trình khác biết về tệp đó và có thể xóa nó - bạn có nguy cơ một điều kiện của cuộc đua nếu bạn kiểm tra nó tồn tại, bởi vì bạn sau đó cuộc đua để mở nó trước khi điều kiện (sự tồn tại của nó) thay đổi.

Điều kiện chủng tộc là rất khó để gỡ lỗi bởi vì có một cửa sổ rất nhỏ, trong đó họ có thể gây ra chương trình của bạn thất bại.

Nhưng nếu đây là động lực của bạn, bạn có thể lấy giá trị của một try tuyên bố bằng cách sử dụng suppress quản lý ngữ cảnh.

Tránh điều kiện chủng tộc mà không có tuyên bố thử: suppress

Python 3.4 cho chúng ta suppress trình quản lý ngữ cảnh (trước đây là ignore quản lý ngữ cảnh), trong đó ngữ nghĩa chính xác cùng một điều trong ít dòng, trong khi cũng (ít nhất bề ngoài) đáp ứng yêu cầu ban đầu để tránh một try tuyên bố:

from contextlib import suppress
from pathlib import Path

Sử dụng:

>>> with suppress(OSError), Path('doesnotexist').open() as f:
...     for line in f:
...         print(line)
... 
>>>
>>> with suppress(OSError):
...     Path('doesnotexist').unlink()
... 
>>> 

Đối với Pythons trước đó, bạn có thể cuộn của riêng bạn suppress, nhưng không có try sẽ tiết tú hơn với. tôi tin tưởng đây thực sự là câu trả lời duy nhất không sử dụng try ở mọi cấp độ trong Python có thể được áp dụng cho trước Python 3.4 vì nó sử dụng trình quản lý ngữ cảnh thay thế:

class suppress(object):
    def __init__(self, *exceptions):
        self.exceptions = exceptions
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is not None:
            return issubclass(exc_type, self.exceptions)

Có lẽ dễ dàng hơn khi thử:

from contextlib import contextmanager

@contextmanager
def suppress(*exceptions):
    try:
        yield
    except exceptions:
        pass

Các tùy chọn khác không đáp ứng yêu cầu "không thử":

isfile

import os
os.path.isfile(path)

từ tài liệu:

os.path.isfile(path)

Trả về True nếu đường dẫn là một tệp thông thường hiện có. Điều này theo biểu tượng   liên kết, vì vậy cả hai islink() và isfile() có thể đúng cho cùng một đường dẫn.

Nhưng nếu bạn kiểm tra nguồncủa hàm này, bạn sẽ thấy nó thực sự sử dụng câu lệnh try:

# This follows symbolic links, so both islink() and isdir() can be true
# for the same path on systems that support symlinks
def isfile(path):
    """Test whether a path is a regular file"""
    try:
        st = os.stat(path)
    except os.error:
        return False
    return stat.S_ISREG(st.st_mode)
>>> OSError is os.error
True

Tất cả những gì nó đang làm là sử dụng đường dẫn cụ thể để xem liệu nó có thể có được số liệu thống kê trên nó hay không, OSError và sau đó kiểm tra xem đó có phải là một tệp không nếu nó không làm tăng ngoại lệ.

Nếu bạn có ý định làm điều gì đó với tập tin, tôi sẽ đề xuất trực tiếp thử nó với một thử-ngoại trừ để tránh một điều kiện chủng tộc:

try:
    with open(path) as f:
        f.read()
except OSError:
    pass

os.access

Có sẵn cho Unix và Windows os.access, nhưng để sử dụng bạn phải vượt qua cờ, và nó không phân biệt giữa các tập tin và thư mục. Điều này được sử dụng nhiều hơn để kiểm tra nếu người dùng thực sự gọi có quyền truy cập trong môi trường đặc quyền nâng cao:

import os
os.access(path, os.F_OK)

Nó cũng bị các vấn đề về chủng tộc giống như isfile. Từ tài liệu:

Chú thích:   Sử dụng quyền truy cập () để kiểm tra xem người dùng có được phép không, ví dụ: mở tệp tin   trước khi thực sự làm như vậy bằng cách sử dụng open () tạo ra một lỗ hổng bảo mật, bởi vì   người dùng có thể khai thác khoảng thời gian ngắn giữa việc kiểm tra và   mở tập tin để thao tác nó. Tốt hơn là sử dụng EAFP   kỹ thuật. Ví dụ:

if os.access("myfile", os.R_OK):
    with open("myfile") as fp:
        return fp.read()
return "some default data"

được viết tốt hơn là:

try:
    fp = open("myfile")
except IOError as e:
    if e.errno == errno.EACCES:
        return "some default data"
    # Not a permission error.
    raise
else:
    with fp:
        return fp.read()

Tránh sử dụng os.access. Nó là một hàm mức thấp có nhiều cơ hội cho lỗi người dùng hơn các đối tượng mức cao hơn và các hàm được thảo luận ở trên.

Phê bình câu trả lời khác:

Một câu trả lời khác nói về điều này os.access:

Cá nhân, tôi thích cái này vì dưới mui xe, nó gọi API gốc (thông qua "$ {PYTHON_SRC_DIR} /Modules/posixmodule.c"), nhưng nó cũng mở ra một cổng cho các lỗi người dùng có thể, và nó không phải là Pythonic như các biến thể khác :

Câu trả lời này nói rằng nó thích một phương pháp không phải là Pythonic, dễ bị lỗi, không có biện minh. Dường như khuyến khích người dùng sử dụng các API cấp thấp mà không hiểu chúng.

Nó cũng tạo ra một trình quản lý ngữ cảnh, bằng cách trả về vô điều kiện True, cho phép tất cả Ngoại lệ (bao gồm KeyboardInterrupt và SystemExit!) để vượt qua âm thầm, đó là cách hay để ẩn lỗi.

Điều này dường như khuyến khích người dùng áp dụng thực hành kém.


101
2017-08-11 03:54