Hướng dẫn python scandir vs listdir - python scandir vs listdir

Tôi đã cố gắng tối ưu hóa chức năng duyệt tệp được viết bằng python, trên windows, bằng cách sử dụng os.scandir () thay vì os.listdir (). Tuy nhiên, thời gian vẫn không thay đổi, khoảng 2 phút rưỡi, và tôi không thể nói tại sao. Dưới đây là các chức năng, nguyên bản và thay đổi:

Phiên bản os.listdir ():

def browse(self, path, tree):
    # for each entry in the path
    for entry in os.listdir(path):
        entity_path = os.path.join(path, entry)
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if os.path.isdir( entity_path ):
                tree[entry] = Folder(entry)
                self.browse(entity_path, tree[entry])
            # if is a file add it to the tree
            if os.path.isfile(entity_path):
                tree[entry] = File(entity_path)

Phiên bản OS.Scandir ():

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)

Ngoài ra, đây là các chức năng phụ trợ được sử dụng trong phạm vi này:

def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)

Có ai có giải pháp cho cách tôi có thể làm cho chức năng chạy nhanh hơn không? Giả định của tôi là việc trích xuất tên và đường dẫn ở đầu làm cho nó chạy chậm hơn nó, điều đó có đúng không?

Tác giả: Ben Hoyt BDFL-Delegate: Victor Stinner Tình trạng: FinalType: Tiêu chuẩn theo dõi: 30-tháng 5 năm 2014PyThon-Vers:Ben Hoyt BDFL-Delegate:Victor Stinner Status:FinalType:Standards TrackCreated:30-May-2014Python-Version:3.5Post-History:27-Jun-2014, 08-Jul-2014, 14-Jul-2014
Mục lục
  • trừu tượng
  • Cơ sở lý luận
  • Thực hiện
  • Cụ thể của đề xuất
    • os.scandir()
    • os.walk()
  • Ví dụ
    • Ghi chú về bộ nhớ đệm
    • Ghi chú về xử lý ngoại lệ
  • Ủng hộ
  • Sử dụng trong tự nhiên
  • Từ chối ý tưởng
    • Đặt tên
    • người hỗ trợ ký đại diện
    • Các phương thức không theo dõi các liên kết symlink theo mặc định
    • Thuộc tính direntry là thuộc tính
    • Các trường Direntry là các đối tượng chỉ thuộc tính thuộc tính tĩnh
    • Các trường Direntry đang tĩnh với tùy chọn đảm bảo_lstat
    • Trả về các giá trị là (tên, stat_result) hai bộ phận
    • Trả về các giá trị bị quá tải các đối tượng Stat_Result
    • Trả về các giá trị là các đối tượng pathlib.path
  • Có thể cải thiện
  • Thảo luận trước
  • Bản quyền

trừu tượng

Cơ sở lý luận

Cơ sở lý luận

Thực hiện

Cụ thể của đề xuất

Ví dụ

Ghi chú về bộ nhớ đệm8-9 times as fast on Windows, and about 2-3 times as fast on POSIX systems. So we’re not talking about micro- optimizations. See more benchmarks here.

Ghi chú về xử lý ngoại lệ

Ủng hộ

Thực hiện

Cụ thể của đề xuất

Ví dụ

Cụ thể của đề xuất

os.scandir()

Ví dụ

scandir(path='.') -> generator of DirEntry objects

Ghi chú về bộ nhớ đệm

  • Ghi chú về xử lý ngoại lệ
  • Nó trả về một trình tạo thay vì một danh sách, do đó
    def git_ignore(self, filepath):
        if '.git' in filepath:
            return True
        if '.ci' in filepath:
            return True
        if '.delivery' in filepath:
            return True
        child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        output = child.communicate()[0]
        status = child.wait()
        return status == 0
    
    ============================================================
    
    class Folder(dict):
        def __init__(self, path):
            self.path = path
            self.categories = {}
    
    ============================================================
    
    class File(object):
        def __init__(self, path):
            self.path = path
            self.filename, self.extension = os.path.splitext(self.path)
    
    6 hoạt động như một trình lặp thực sự thay vì trả lại danh sách đầy đủ ngay lập tức.

def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
2 mang lại một đối tượng
scandir(path='.') -> generator of DirEntry objects
1 cho mỗi tệp và thư mục phụ trong
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
9. Giống như
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
7, các hướng dẫn giả
scandir(path='.') -> generator of DirEntry objects
7 và
scandir(path='.') -> generator of DirEntry objects
8 được bỏ qua và các mục được mang lại theo thứ tự phụ thuộc vào hệ thống. Mỗi đối tượng
scandir(path='.') -> generator of DirEntry objects
1 có các thuộc tính và phương thức sau:

  • def subdirs(path):
        """Yield directory names not starting with '.' under given path."""
        for entry in os.scandir(path):
            if not entry.name.startswith('.') and entry.is_dir():
                yield entry.name
    
    0: Tên tệp của mục nhập, liên quan đến đối số Scandir
    def git_ignore(self, filepath):
        if '.git' in filepath:
            return True
        if '.ci' in filepath:
            return True
        if '.delivery' in filepath:
            return True
        child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        output = child.communicate()[0]
        status = child.wait()
        return status == 0
    
    ============================================================
    
    class Folder(dict):
        def __init__(self, path):
            self.path = path
            self.categories = {}
    
    ============================================================
    
    class File(object):
        def __init__(self, path):
            self.path = path
            self.filename, self.extension = os.path.splitext(self.path)
    
    9 (tương ứng với các giá trị trả về của
    def subdirs(path):
        """Yield directory names not starting with '.' under given path."""
        for entry in os.scandir(path):
            if not entry.name.startswith('.') and entry.is_dir():
                yield entry.name
    
    2)
  • def git_ignore(self, filepath):
        if '.git' in filepath:
            return True
        if '.ci' in filepath:
            return True
        if '.delivery' in filepath:
            return True
        child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        output = child.communicate()[0]
        status = child.wait()
        return status == 0
    
    ============================================================
    
    class Folder(dict):
        def __init__(self, path):
            self.path = path
            self.categories = {}
    
    ============================================================
    
    class File(object):
        def __init__(self, path):
            self.path = path
            self.filename, self.extension = os.path.splitext(self.path)
    
    9: Tên đường dẫn đầy đủ của mục nhập (không nhất thiết là một đường dẫn tuyệt đối) - tương đương với
    def subdirs(path):
        """Yield directory names not starting with '.' under given path."""
        for entry in os.scandir(path):
            if not entry.name.startswith('.') and entry.is_dir():
                yield entry.name
    
    4
  • def subdirs(path):
        """Yield directory names not starting with '.' under given path."""
        for entry in os.scandir(path):
            if not entry.name.startswith('.') and entry.is_dir():
                yield entry.name
    
    5: Trả lại số inode của mục nhập. Kết quả được lưu trong bộ nhớ cache trên đối tượng
    scandir(path='.') -> generator of DirEntry objects
    
    1, sử dụng
    def subdirs(path):
        """Yield directory names not starting with '.' under given path."""
        for entry in os.scandir(path):
            if not entry.name.startswith('.') and entry.is_dir():
                yield entry.name
    
    7 để tìm nạp thông tin cập nhật. Trên Unix, không cần cuộc gọi hệ thống.
  • def subdirs(path):
        """Yield directory names not starting with '.' under given path."""
        for entry in os.scandir(path):
            if not entry.name.startswith('.') and entry.is_dir():
                yield entry.name
    
    8: Tương tự như
    def subdirs(path):
        """Yield directory names not starting with '.' under given path."""
        for entry in os.scandir(path):
            if not entry.name.startswith('.') and entry.is_dir():
                yield entry.name
    
    9, nhưng giá trị trả về được lưu trong bộ đệm trên đối tượng
    scandir(path='.') -> generator of DirEntry objects
    
    1; Không yêu cầu một cuộc gọi hệ thống trong hầu hết các trường hợp; Don Tiết theo các liên kết tượng trưng nếu
    def get_tree_size(path):
        """Return total size of files in given path and subdirs."""
        total = 0
        for entry in os.scandir(path):
            if entry.is_dir(follow_symlinks=False):
                total += get_tree_size(entry.path)
            else:
                total += entry.stat(follow_symlinks=False).st_size
        return total
    
    1 là sai
  • def get_tree_size(path):
        """Return total size of files in given path and subdirs."""
        total = 0
        for entry in os.scandir(path):
            if entry.is_dir(follow_symlinks=False):
                total += get_tree_size(entry.path)
            else:
                total += entry.stat(follow_symlinks=False).st_size
        return total
    
    2: Tương tự như
    def get_tree_size(path):
        """Return total size of files in given path and subdirs."""
        total = 0
        for entry in os.scandir(path):
            if entry.is_dir(follow_symlinks=False):
                total += get_tree_size(entry.path)
            else:
                total += entry.stat(follow_symlinks=False).st_size
        return total
    
    3, nhưng giá trị trả về được lưu trong bộ đệm trên đối tượng
    scandir(path='.') -> generator of DirEntry objects
    
    1; Không yêu cầu một cuộc gọi hệ thống trong hầu hết các trường hợp; Don Tiết theo các liên kết tượng trưng nếu
    def get_tree_size(path):
        """Return total size of files in given path and subdirs."""
        total = 0
        for entry in os.scandir(path):
            if entry.is_dir(follow_symlinks=False):
                total += get_tree_size(entry.path)
            else:
                total += entry.stat(follow_symlinks=False).st_size
        return total
    
    1 là sai
  • def get_tree_size(path):
        """Return total size of files in given path and subdirs."""
        total = 0
        for entry in os.scandir(path):
            if entry.is_dir(follow_symlinks=False):
                total += get_tree_size(entry.path)
            else:
                total += entry.stat(follow_symlinks=False).st_size
        return total
    
    6: Tương tự như
    def get_tree_size(path):
        """Return total size of files in given path and subdirs."""
        total = 0
        for entry in os.scandir(path):
            if entry.is_dir(follow_symlinks=False):
                total += get_tree_size(entry.path)
            else:
                total += entry.stat(follow_symlinks=False).st_size
        return total
    
    7, nhưng giá trị trả về được lưu trong bộ đệm trên đối tượng
    scandir(path='.') -> generator of DirEntry objects
    
    1; không yêu cầu một cuộc gọi hệ thống trong hầu hết các trường hợp
  • def get_tree_size(path):
        """Return total size of files in given path and subdirs."""
        total = 0
        for entry in os.scandir(path):
            if entry.is_dir(follow_symlinks=False):
                total += get_tree_size(entry.path)
            else:
                total += entry.stat(follow_symlinks=False).st_size
        return total
    
    9: Giống như
    def browse(self, path, tree):
        # for each entry in the path
        for dirEntry in os.scandir(path):
            entry_path = dirEntry.name
            entity_path = dirEntry.path
            # check if support by git or not
            if self.git_ignore(entity_path) is False:
                # if is a dir create a new level in the tree
                if dirEntry.is_dir(follow_symlinks=True):
                    tree[entry_path] = Folder(entity_path)
                    self.browse(entity_path, tree[entry_path])
                # if is a file add it to the tree
                if dirEntry.is_file(follow_symlinks=True):
                    tree[entry_path] = File(entity_path)
    
    0, nhưng giá trị trả về được lưu trong bộ đệm trên đối tượng
    scandir(path='.') -> generator of DirEntry objects
    
    1; không yêu cầu gọi hệ thống trên Windows (ngoại trừ Symlinks); Don Tiết theo các liên kết tượng trưng (như
    def get_tree_size(path):
        """Return total size of files in path and subdirs. If
        is_dir() or stat() fails, print an error message to stderr
        and assume zero size (for example, file has been deleted).
        """
        total = 0
        for entry in os.scandir(path):
            try:
                is_dir = entry.is_dir(follow_symlinks=False)
            except OSError as error:
                print('Error calling is_dir():', error, file=sys.stderr)
                continue
            if is_dir:
                total += get_tree_size(entry.path)
            else:
                try:
                    total += entry.stat(follow_symlinks=False).st_size
                except OSError as error:
                    print('Error calling stat():', error, file=sys.stderr)
        return total
    
    2) nếu
    def get_tree_size(path):
        """Return total size of files in given path and subdirs."""
        total = 0
        for entry in os.scandir(path):
            if entry.is_dir(follow_symlinks=False):
                total += get_tree_size(entry.path)
            else:
                total += entry.stat(follow_symlinks=False).st_size
        return total
    
    1 là sai

Tất cả các phương thức có thể thực hiện các cuộc gọi hệ thống trong một số trường hợp và do đó có thể tăng

def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total
4 - xem phần Ghi chú trên phần Xử lý ngoại lệ để biết thêm chi tiết.

Thuộc tính và tên phương thức

scandir(path='.') -> generator of DirEntry objects
1 được chọn giống như các thuộc tính trong mô -đun
def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total
6 mới nếu có thể, cho tính nhất quán. Sự khác biệt duy nhất về chức năng là các phương thức
scandir(path='.') -> generator of DirEntry objects
1 đã lưu bộ đệm các giá trị của chúng trên đối tượng nhập sau cuộc gọi đầu tiên.

Giống như các hàm khác trong mô -đun

def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
5,
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
2 chấp nhận một đối tượng byte hoặc STR cho tham số
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
9 và trả về các thuộc tính
it = os.scandir(path)
while True:
    try:
        entry = next(it)
    except OSError as error:
        handle_error(path, error)
    except StopIteration:
        break
1 và
it = os.scandir(path)
while True:
    try:
        entry = next(it)
    except OSError as error:
        handle_error(path, error)
    except StopIteration:
        break
2 có cùng loại với
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
9. Tuy nhiên, bạn nên sử dụng loại STR, vì điều này đảm bảo hỗ trợ đa nền tảng cho tên tệp unicode. .

os.walk()

Là một phần của đề xuất này, os.walk() cũng sẽ được sửa đổi để sử dụng

def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
2 thay vì
it = os.scandir(path)
while True:
    try:
        entry = next(it)
    except OSError as error:
        handle_error(path, error)
    except StopIteration:
        break
6 và
it = os.scandir(path)
while True:
    try:
        entry = next(it)
    except OSError as error:
        handle_error(path, error)
    except StopIteration:
        break
7. Điều này sẽ tăng tốc độ os.walk() rất đáng kể (như đã đề cập ở trên, bằng 2-20 lần, tùy thuộc vào hệ thống).

Ví dụ

Đầu tiên, một ví dụ rất đơn giản về

def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
2 hiển thị việc sử dụng thuộc tính
it = os.scandir(path)
while True:
    try:
        entry = next(it)
    except OSError as error:
        handle_error(path, error)
    except StopIteration:
        break
1 và phương thức os.scandir()1:

def subdirs(path):
    """Yield directory names not starting with '.' under given path."""
    for entry in os.scandir(path):
        if not entry.name.startswith('.') and entry.is_dir():
            yield entry.name

Hàm os.scandir()2 này sẽ nhanh hơn đáng kể với scandir so với

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
2 và
it = os.scandir(path)
while True:
    try:
        entry = next(it)
    except OSError as error:
        handle_error(path, error)
    except StopIteration:
        break
7 trên cả hệ thống Windows và Posix, đặc biệt là trên các thư mục cỡ trung bình hoặc lớn.

Hoặc, để có được tổng kích thước của các tệp trong một cây thư mục, hiển thị việc sử dụng phương thức os.scandir()5 và thuộc tính

it = os.scandir(path)
while True:
    try:
        entry = next(it)
    except OSError as error:
        handle_error(path, error)
    except StopIteration:
        break
2:

def get_tree_size(path):
    """Return total size of files in given path and subdirs."""
    total = 0
    for entry in os.scandir(path):
        if entry.is_dir(follow_symlinks=False):
            total += get_tree_size(entry.path)
        else:
            total += entry.stat(follow_symlinks=False).st_size
    return total

Điều này cũng cho thấy việc sử dụng tham số

def get_tree_size(path):
    """Return total size of files in given path and subdirs."""
    total = 0
    for entry in os.scandir(path):
        if entry.is_dir(follow_symlinks=False):
            total += get_tree_size(entry.path)
        else:
            total += entry.stat(follow_symlinks=False).st_size
    return total
1 thành os.scandir()8 - trong một hàm đệ quy như thế này, có lẽ chúng ta không muốn theo các liên kết. .

Lưu ý rằng os.scandir()9 sẽ tăng tốc độ tăng tốc độ lớn trên Windows, vì không cần cuộc gọi chỉ số bổ sung, nhưng trên các hệ thống POSIX, thông tin kích thước không được trả về bởi các chức năng lặp thư mục, vì vậy chức năng này đã giành được bất cứ thứ gì ở đó.

Ghi chú về bộ nhớ đệm

Các đối tượng

scandir(path='.') -> generator of DirEntry objects
1 tương đối ngu ngốc - các thuộc tính
def subdirs(path):
    """Yield directory names not starting with '.' under given path."""
    for entry in os.scandir(path):
        if not entry.name.startswith('.') and entry.is_dir():
            yield entry.name
0 và
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
9 rõ ràng luôn được lưu trữ và các phương thức os.walk()3 và os.walk()4 lưu trữ các giá trị của chúng (ngay lập tức trên Windows thông qua hệ thống.

Vì lý do này, các đối tượng

scandir(path='.') -> generator of DirEntry objects
1 được dự định sẽ được sử dụng và vứt bỏ sau khi lặp lại, không được lưu trữ trong dữ liệu tồn tại lâu dài được cấu trúc và các phương thức được gọi hết lần này đến lần khác.

Nếu các nhà phát triển muốn hành vi làm mới của người Viking (ví dụ, để xem thay đổi kích thước tệp), họ chỉ có thể sử dụng các đối tượng os.walk()8 hoặc gọi các hàm ____10 hoặc

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
00 thông thường nhận được dữ liệu mới từ hệ điều hành mỗi cuộc gọi.

Ghi chú về xử lý ngoại lệ

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
01 và os.scandir()5 là các phương thức rõ ràng thay vì các thuộc tính hoặc thuộc tính, để làm rõ rằng chúng có thể không phải là hoạt động rẻ tiền (mặc dù chúng thường là như vậy) và chúng có thể thực hiện một cuộc gọi hệ thống. Do đó, các phương pháp này có thể tăng
def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total
4.

Ví dụ: os.scandir()5 sẽ luôn thực hiện cuộc gọi hệ thống trên các hệ thống dựa trên POSIX và các phương thức

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
01 sẽ thực hiện cuộc gọi hệ thống
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
3 trên các hệ thống đó nếu
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
07 không hỗ trợ
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
08 hoặc trả về điều kiện hoặc trên một số hệ thống tập tin.

Thông thường, điều này không quan trọng - ví dụ, os.walk() như được định nghĩa trong thư viện tiêu chuẩn chỉ bắt các lỗi xung quanh các cuộc gọi

it = os.scandir(path)
while True:
    try:
        entry = next(it)
    except OSError as error:
        handle_error(path, error)
    except StopIteration:
        break
6.

Ngoài ra, bởi vì hành vi gây ra ngoại lệ của các phương pháp

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
13 phù hợp với
def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total
6-chỉ tăng
def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total
4 trong trường hợp quyền hoặc các lỗi gây tử vong khác, nhưng trả về sai nếu đường dẫn không tồn tại cần thiết để bắt lỗi xung quanh các cuộc gọi
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
16.

Tuy nhiên, khi người dùng yêu cầu xử lý lỗi hạt mịn, có thể mong muốn bắt

def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total
4 xung quanh tất cả các cuộc gọi phương thức và xử lý khi thích hợp.

Ví dụ: bên dưới là phiên bản của ví dụ os.scandir()9 được hiển thị ở trên, nhưng với xử lý lỗi hạt mịn được thêm vào:

def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total

Ủng hộ

Mô-đun Scandir trên GitHub đã được đưa ra và được sử dụng khá nhiều (xem sử dụng trên mạng hoang dã trong PEP này), nhưng cũng có một chút hỗ trợ trực tiếp cho chức năng giống như scandir từ các nhà phát triển cốt lõi và những người khác trên Python -Dev và Python-Ideas Danh sách gửi thư. Một mẫu:

  • Python-dev: Một số lượng tốt +1 1 và rất ít tiêu cực cho scandir và pep 471 trên chủ đề Python-dev tháng 6 năm 2014 này: a good number of +1’s and very few negatives for scandir and PEP 471 on this June 2014 python-dev thread
  • Nick Coghlan, một nhà phát triển Python cốt lõi: Tôi đã có nhóm Kỹ thuật phát hành Hat Hat địa phương thể hiện sự không hài lòng của họ khi phải thống kê mọi tệp trong một cây thư mục gắn kết mạng để biết thông tin trong cấu trúc Dirent, do đó đến Os.Scandir từ tôi, miễn là nó có sẵn thông tin đó. [Nguồn1], a core Python developer: “I’ve had the local Red Hat release engineering team express their displeasure at having to stat every file in a network mounted directory tree for info that is present in the dirent structure, so a definite +1 to os.scandir from me, so long as it makes that info available.” [source1]
  • Tim Golden, một nhà phát triển Python cốt lõi, hỗ trợ Scandir đủ để dành thời gian tái cấu trúc và cải thiện đáng kể mô -đun mở rộng Scandir. [Nguồn2], a core Python developer, supports scandir enough to have spent time refactoring and significantly improving scandir’s C extension module. [source2]
  • Christian Heimes, một nhà phát triển Python cốt lõi: Hồi +1 cho một cái gì đó như whiteddir () [[Source3] và thực sự! Tôi muốn xem tính năng này trong 3,4 để tôi có thể loại bỏ bản hack của riêng mình khỏi cơ sở mã của chúng tôi. [Nguồn4], a core Python developer: “+1 for something like yielddir()” [source3] and “Indeed! I’d like to see the feature in 3.4 so I can remove my own hack from our code base.” [source4]
  • Gregory P. Smith, một nhà phát triển Python cốt lõi: Từ 3.4beta1 xảy ra tối nay, đây không phải là 3,4 vì vậy tôi đã tăng tốc độ này lên 3,5. Tôi thực sự thích thiết kế đề xuất được nêu ở trên. [Nguồn5], a core Python developer: “As 3.4beta1 happens tonight, this isn’t going to make 3.4 so i’m bumping this to 3.5. I really like the proposed design outlined above.” [source5]
  • Guido Van Rossum về khả năng thêm scandir vào Python 3.5 (vì đã quá muộn cho 3,4): Tàu cũng đã đi thuyền để thêm scandir () (có hệ điều hành hay pathlib). Bằng mọi cách, hãy thử nghiệm và chuẩn bị sẵn sàng để xem xét cho 3,5, nhưng tôi không muốn thêm nó vào 3,4. [Nguồn6] on the possibility of adding scandir to Python 3.5 (as it was too late for 3.4): “The ship has likewise sailed for adding scandir() (whether to os or pathlib). By all means experiment and get it ready for consideration for 3.5, but I don’t want to add it to 3.4.” [source6]

Hỗ trợ cho bản thân PEP này (hỗ trợ meta?) Đã được Nick Coghlan đưa ra trên Python-dev: Một PEP xem xét tất cả điều này cho 3.5 và đề xuất một API OS.Scandir cụ thể sẽ là một điều tốt. [Nguồn7]

Sử dụng trong tự nhiên

Cho đến nay, việc triển khai

def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
6 chắc chắn rất hữu ích, nhưng đã được đánh dấu rõ ràng là Beta Beta, vì vậy, nó không chắc chắn việc sử dụng nó có bao nhiêu trong tự nhiên. Ben Hoyt đã có một số báo cáo từ những người sử dụng nó. Ví dụ:

  • Chris F: Tôi đang xử lý một số thư mục khá lớn và một nửa mong muốn phải sửa đổi getdents. Vì vậy, cảm ơn vì đã tiết kiệm cho tôi những nỗ lực. [qua email cá nhân]
  • BSCHOLLNICK: Tôi muốn cho bạn biết về điều này, vì tôi đang sử dụng Scandir làm khối xây dựng cho mã này. Ở đây, một ví dụ điển hình về việc Scandir thực hiện cải thiện hiệu suất triệt để so với Os.ListDir. [Nguồn8]
  • Avram L: Tôi đã thử nghiệm scandir của chúng tôi cho một dự án mà tôi đang làm việc. Có vẻ khá vững chắc, vì vậy điều đầu tiên, chỉ muốn nói công việc tốt đẹp! [qua email cá nhân]
  • Matt Z: Tôi đã sử dụng scandir để đổ nội dung của một mạng lưới trong vòng dưới 15 giây. 13 Dirs gốc, 60.000 tệp trong cấu trúc. Điều này sẽ thay thế một số mã VBA cũ được nhúng trong một bảng tính mất 15-20 phút để làm điều tương tự chính xác. [qua email cá nhân]

Những người khác đã yêu cầu một gói PYPI cho nó, đã được tạo ra. Xem gói PYPI.

Các số liệu thống kê của GitHub có nghĩa là quá nhiều, nhưng Scandir có một số người theo dõi, vấn đề, dĩa, v.v ... Tại đây, các số liệu thống kê kể từ ngày 7 tháng 7 năm 2014:

  • Người theo dõi: 17
  • Sao: 57
  • Phân: 20
  • Vấn đề: 4 mở, 26 đóng

Ngoài ra, vì PEP này sẽ tăng tốc độ os.walk() đáng kể, có hàng ngàn nhà phát triển và kịch bản, và rất nhiều mã sản xuất, sẽ được hưởng lợi từ nó. Ví dụ, trên GitHub, có gần như nhiều cách sử dụng của

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
21 (194.000) như có
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
22 (230.000).

Từ chối ý tưởng

Đặt tên

Ứng cử viên thực sự duy nhất khác cho chức năng này Tên tên là

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
23. Tuy nhiên, các chức năng
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
24 trong Python (chủ yếu được tìm thấy trong Python 2) có xu hướng tương đương iterator đơn giản của các đối tác không phải điều khiển của chúng. Ví dụ,
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
25 chỉ là phiên bản ererator của
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
26, nhưng các đối tượng được trả về là giống hệt nhau. Tuy nhiên, trong trường hợp ____ 22, các giá trị trả về là các đối tượng khá khác nhau (
scandir(path='.') -> generator of DirEntry objects
1 đối tượng so với chuỗi tên tệp), vì vậy điều này có thể được phản ánh bởi sự khác biệt về tên - do đó
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
2.

Xem một số cuộc thảo luận có liên quan về Python-dev.

người hỗ trợ ký đại diện

________ 15/________ 16 trên Windows Hỗ trợ vượt qua một loài đại diện của người Hồi giáo như

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
32, vì vậy, những người đầu tiên (bao gồm cả tác giả PEP này) cảm thấy sẽ là một ý tưởng tốt để bao gồm một đối số từ khóa
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
33 cho chức năng
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
6 để người dùng có thể chuyển điều này.

Tuy nhiên, theo suy nghĩ và thảo luận thêm, người ta đã quyết định rằng đây sẽ là ý tưởng tồi, trừ khi nó có thể được thực hiện đa nền tảng (một đối số từ khóa

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
35 hoặc tương tự). Điều này có vẻ đủ dễ dàng lúc đầu-chỉ cần sử dụng hỗ trợ đại diện OS trên Windows và một cái gì đó như
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
36 hoặc
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
37 sau đó trên các hệ thống dựa trên POSIX.

Thật không may, các quy tắc phù hợp với Wildcard Windows chính xác không thực sự được Microsoft ghi lại ở bất cứ đâu và chúng khá kỳ quặc (xem bài đăng trên blog này), có nghĩa là nó rất có vấn đề khi mô phỏng bằng cách sử dụng

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
36 hoặc regexes.

Vì vậy, sự đồng thuận là hỗ trợ Wildcard của Windows là một ý tưởng tồi. Có thể thêm vào một ngày sau đó nếu có một cách đa nền tảng để đạt được nó, nhưng không phải cho phiên bản ban đầu.

Đọc thêm về chủ đề Python-Ideas tháng 11 năm 2012 này và chủ đề Python-Dev tháng 6 năm 2014 này trên PEP 471.

Có nhiều cuộc tranh luận về Python-Dev (xem tin nhắn trong chuỗi này) về việc liệu các phương thức

scandir(path='.') -> generator of DirEntry objects
1 có nên tuân theo các liên kết tượng trưng hay không (khi các phương thức
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
16 không có tham số
def get_tree_size(path):
    """Return total size of files in given path and subdirs."""
    total = 0
    for entry in os.scandir(path):
        if entry.is_dir(follow_symlinks=False):
            total += get_tree_size(entry.path)
        else:
            total += entry.stat(follow_symlinks=False).st_size
    return total
1).

Ban đầu họ đã không (xem các phiên bản trước của mô-đun PEP và Scandir.py này), nhưng Victor Stinner đã đưa ra một trường hợp khá hấp dẫn trên Python-dev rằng theo các liên kết symlink theo mặc định là một ý tưởng tốt hơn, bởi vì:

  • Các liên kết sau thường là những gì bạn muốn (trong 92% trường hợp trong thư viện tiêu chuẩn, các chức năng sử dụng
    def browse(self, path, tree):
        # for each entry in the path
        for dirEntry in os.scandir(path):
            entry_path = dirEntry.name
            entity_path = dirEntry.path
            # check if support by git or not
            if self.git_ignore(entity_path) is False:
                # if is a dir create a new level in the tree
                if dirEntry.is_dir(follow_symlinks=True):
                    tree[entry_path] = Folder(entity_path)
                    self.browse(entity_path, tree[entry_path])
                # if is a file add it to the tree
                if dirEntry.is_file(follow_symlinks=True):
                    tree[entry_path] = File(entity_path)
    
    2 và
    it = os.scandir(path)
    while True:
        try:
            entry = next(it)
        except OSError as error:
            handle_error(path, error)
        except StopIteration:
            break
    
    7 làm theo Symlinks)
  • Đó là tiền lệ được thiết lập bởi các chức năng tương tự
    it = os.scandir(path)
    while True:
        try:
            entry = next(it)
        except OSError as error:
            handle_error(path, error)
        except StopIteration:
            break
    
    7 và
    def subdirs(path):
        """Yield directory names not starting with '.' under given path."""
        for entry in os.scandir(path):
            if not entry.name.startswith('.') and entry.is_dir():
                yield entry.name
    
    9, vì vậy để làm nếu không
  • Với cách tiếp cận không liên kết, nếu bạn muốn theo các liên kết, bạn phải nói điều gì đó như
    def browse(self, path, tree):
        # for each entry in the path
        for dirEntry in os.scandir(path):
            entry_path = dirEntry.name
            entity_path = dirEntry.path
            # check if support by git or not
            if self.git_ignore(entity_path) is False:
                # if is a dir create a new level in the tree
                if dirEntry.is_dir(follow_symlinks=True):
                    tree[entry_path] = Folder(entity_path)
                    self.browse(entity_path, tree[entry_path])
                # if is a file add it to the tree
                if dirEntry.is_file(follow_symlinks=True):
                    tree[entry_path] = File(entity_path)
    
    46, đó là vụng về vụng về

Như một trường hợp cụ thể cho thấy phiên bản không liên kết có liên kết có lỗi, tác giả PEP này đã gây ra lỗi do kiểm tra chính xác này sai trong việc triển khai

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
47 ban đầu của anh ấy trong scandir.py (xem vấn đề #4 tại đây).

Cuối cùng, không có sự thỏa thuận nào rằng các phương pháp nên tuân theo các liên kết của Symlink, nhưng có sự đồng thuận cơ bản giữa những người tham gia có liên quan nhiều nhất và tác giả PEP này tin rằng trường hợp trên đủ mạnh để đảm bảo theo các liên kết symlink theo mặc định.

Ngoài ra, nó rất đơn giản để gọi các phương thức có liên quan với

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
48 nếu hành vi khác là mong muốn.

Thuộc tính direntry là thuộc tính

Trong một số cách, nó sẽ đẹp hơn cho

scandir(path='.') -> generator of DirEntry objects
1
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
16 và
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
3 để trở thành thuộc tính thay vì các phương thức, để chỉ ra rằng chúng rất rẻ hoặc miễn phí. Tuy nhiên, đây không phải là trường hợp, vì
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
3 sẽ yêu cầu gọi hệ điều hành trên các hệ thống dựa trên POSIX nhưng không phải trên Windows. Ngay cả os.scandir()8 và bạn bè cũng có thể thực hiện cuộc gọi HĐH trên các hệ thống dựa trên POSIX nếu giá trị
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
54 là
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
10 (trên một số hệ thống tệp nhất định).

Ngoài ra, mọi người sẽ mong đợi quyền truy cập thuộc tính

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
56 chỉ tăng
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
57, chứ không phải
def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total
4 trong trường hợp nó thực hiện một cuộc gọi hệ thống theo bìa. Mã gọi sẽ phải có ________ 159/________ 160 xung quanh những gì trông giống như một quyền truy cập thuộc tính đơn giản, và do đó, nó tốt hơn nhiều để tạo ra các phương thức của chúng.

Xem chủ đề Python-dev tháng 5 năm 2013 này, nơi tác giả PEP này đưa ra trường hợp này và có thỏa thuận từ một nhà phát triển cốt lõi.

Các trường Direntry là các đối tượng chỉ thuộc tính thuộc tính tĩnh

Trong thông điệp Python-Dev tháng 7 năm 2014 này, Paul Moore đã đề xuất một giải pháp là một trình bao bọc mỏng của người Viking, trong đó đối tượng

scandir(path='.') -> generator of DirEntry objects
1 chỉ có các thuộc tính tĩnh:
def subdirs(path):
    """Yield directory names not starting with '.' under given path."""
    for entry in os.scandir(path):
        if not entry.name.startswith('.') and entry.is_dir():
            yield entry.name
0,
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
9 và os.walk()3, với các thuộc tính
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
65 chỉ có trên Windows . Ý tưởng là sử dụng chức năng cấp thấp hơn, đơn giản hơn như một khối xây dựng cho các chức năng cấp cao hơn.

Lúc đầu, có thỏa thuận chung đơn giản hóa theo cách này là một điều tốt. Tuy nhiên, có hai vấn đề với phương pháp này. Đầu tiên, giả định là

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
66 và các thuộc tính tương tự luôn có mặt trên POSIX, đó là trường hợp (nếu
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
08 không có mặt hoặc là
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
10). Thứ hai, nó có một API khó sử dụng hơn nhiều trong thực tế, vì ngay cả các thuộc tính
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
66 cũng không có mặt trên POSIX và sẽ cần phải được kiểm tra với
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
70 và sau đó
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
0 được gọi nếu chúng có mặt.

Xem phản hồi Python-Dev tháng 7 năm 2014 này từ tác giả PEP này chi tiết tại sao tùy chọn này là một giải pháp không lý tưởng và câu trả lời tiếp theo từ thỏa thuận lồng tiếng cho Paul Moore.

Các trường Direntry đang tĩnh với tùy chọn đảm bảo_lstat

Một lựa chọn có vẻ đơn giản và hấp dẫn khác đã được Nick Coghlan đề xuất trong thông điệp Python-Dev tháng 6 năm 2014 này: Tạo các thuộc tính

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
13 và
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
73 và điền vào thời gian lặp
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
73, nhưng chỉ khi đối số mới
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
75 được quy định trong cuộc gọi
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
2.

Điều này có lợi thế hơn ở trên rằng bạn có thể dễ dàng nhận được kết quả STAT từ

def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
2 nếu bạn cần. Tuy nhiên, nó có nhược điểm nghiêm trọng là việc xử lý lỗi hạt mịn là lộn xộn, bởi vì
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
3 sẽ được gọi (và do đó có khả năng tăng
def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total
4) trong quá trình lặp, dẫn đến một vòng lặp khá xấu xí, được làm bằng tay:

it = os.scandir(path)
while True:
    try:
        entry = next(it)
    except OSError as error:
        handle_error(path, error)
    except StopIteration:
        break

Hoặc điều đó có nghĩa là

def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
2 sẽ phải chấp nhận đối số
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
81 - một hàm để gọi khi xảy ra lỗi
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
3 trong quá trình lặp. Điều này dường như đối với tác giả PEP, không trực tiếp cũng như Pythonic như ________ 159/________ 160 xung quanh một cuộc gọi os.scandir()5.

Một nhược điểm khác là os.scandir() được viết để làm cho mã nhanh hơn. Luôn gọi

def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total
2 trên POSIX sẽ không mang lại bất kỳ tốc độ tăng tốc. Trong hầu hết các trường hợp, bạn không cần đối tượng
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
8 đầy đủ - các phương thức
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
16 là đủ và thông tin này đã được biết đến.

Xem Ben Hoyt sườn tháng 7 năm 2014 Trả lời cuộc thảo luận tóm tắt điều này và chi tiết lý do tại sao ông nghĩ rằng đề xuất PEP 471 ban đầu là một trong những điều đúng đắn.

Trả về các giá trị là (tên, stat_result) hai bộ phận

Ban đầu, tác giả PEP này đã đề xuất khái niệm này như một hàm gọi là

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
90 mang lại hai bộ đôi (tên, stat_result). Điều này có lợi thế là không có loại mới được giới thiệu. Tuy nhiên,
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
8 chỉ được lấp đầy một phần trên các hệ thống dựa trên POSIX (hầu hết các trường được đặt thành
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
92 và các quirks khác), vì vậy chúng không thực sự là các đối tượng
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
8, và điều này sẽ phải được ghi lại hoàn toàn khác với
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
0.

Ngoài ra, Python có hỗ trợ tốt cho các đối tượng thích hợp với các thuộc tính và phương thức, tạo ra một API đơn giản và đơn giản hơn hai bộ phận. Nó cũng làm cho các đối tượng

scandir(path='.') -> generator of DirEntry objects
1 có thể mở rộng hơn và chứng minh trong tương lai khi các hệ điều hành thêm chức năng và chúng tôi muốn đưa vào điều này vào
scandir(path='.') -> generator of DirEntry objects
1.

Xem thêm một số cuộc thảo luận trước đây:

  • Tháng 5 năm 2013 Python-dev Chủ đề nơi Nick Coghlan đưa ra trường hợp ban đầu cho một đối tượng kiểu ____ 31.
  • Tháng 6 năm 2014 Python-dev Chủ đề nơi Nick Coghlan đưa ra (một trường hợp khác) tốt chống lại cách tiếp cận hai tuple.

Trả về các giá trị bị quá tải các đối tượng Stat_Result

Một cách khác được thảo luận là làm cho các giá trị trả về được quá tải các đối tượng

def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
8 với các thuộc tính
def subdirs(path):
    """Yield directory names not starting with '.' under given path."""
    for entry in os.scandir(path):
        if not entry.name.startswith('.') and entry.is_dir():
            yield entry.name
0 và
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
9. Tuy nhiên, ngoài việc này là một loại quá tải kỳ lạ (và căng thẳng!)

Trả về các giá trị là các đối tượng pathlib.path

Với mô -đun thư viện tiêu chuẩn mới của Antoine Pitrou,

def get_tree_size(path):
    """Return total size of files in path and subdirs. If
    is_dir() or stat() fails, print an error message to stderr
    and assume zero size (for example, file has been deleted).
    """
    total = 0
    for entry in os.scandir(path):
        try:
            is_dir = entry.is_dir(follow_symlinks=False)
        except OSError as error:
            print('Error calling is_dir():', error, file=sys.stderr)
            continue
        if is_dir:
            total += get_tree_size(entry.path)
        else:
            try:
                total += entry.stat(follow_symlinks=False).st_size
            except OSError as error:
                print('Error calling stat():', error, file=sys.stderr)
    return total
6, lúc đầu có vẻ như là một ý tưởng tuyệt vời cho
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
2 để trả về các trường hợp os.walk()8. Tuy nhiên, các chức năng ____ 98
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
16 và
def browse(self, path, tree):
    # for each entry in the path
    for dirEntry in os.scandir(path):
        entry_path = dirEntry.name
        entity_path = dirEntry.path
        # check if support by git or not
        if self.git_ignore(entity_path) is False:
            # if is a dir create a new level in the tree
            if dirEntry.is_dir(follow_symlinks=True):
                tree[entry_path] = Folder(entity_path)
                self.browse(entity_path, tree[entry_path])
            # if is a file add it to the tree
            if dirEntry.is_file(follow_symlinks=True):
                tree[entry_path] = File(entity_path)
3 rõ ràng không được lưu trữ, trong khi
def git_ignore(self, filepath):
    if '.git' in filepath:
        return True
    if '.ci' in filepath:
        return True
    if '.delivery' in filepath:
        return True
    child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    output = child.communicate()[0]
    status = child.wait()
    return status == 0

============================================================

class Folder(dict):
    def __init__(self, path):
        self.path = path
        self.categories = {}

============================================================

class File(object):
    def __init__(self, path):
        self.path = path
        self.filename, self.extension = os.path.splitext(self.path)
6 phải lưu trữ chúng theo thiết kế, bởi vì nó (thường) trả về các giá trị từ cuộc gọi hệ thống lặp thư mục ban đầu.

Và nếu các trường hợp os.walk()8 được trả về bởi các giá trị thống kê được lưu trong bộ nhớ cache, nhưng các đối tượng os.walk()8 thông thường rõ ràng không có giá trị, điều đó sẽ nhiều hơn một chút khó hiểu.

Guido Van Rossum đã từ chối rõ ràng os.walk()8 Bộ nhớ cache Stat trong bối cảnh scandir ở đây, làm cho os.walk()8 trở thành một lựa chọn tồi cho các giá trị trả lại scandir.

Có thể cải thiện

Có nhiều cải tiến có thể mà người ta có thể thực hiện để Scandir, nhưng đây là một danh sách ngắn của một số tác giả PEP này có trong tâm trí:

  • Scandir có khả năng có thể được tăng tốc thêm bằng cách gọi
    def browse(self, path, tree):
        # for each entry in the path
        for dirEntry in os.scandir(path):
            entry_path = dirEntry.name
            entity_path = dirEntry.path
            # check if support by git or not
            if self.git_ignore(entity_path) is False:
                # if is a dir create a new level in the tree
                if dirEntry.is_dir(follow_symlinks=True):
                    tree[entry_path] = Folder(entity_path)
                    self.browse(entity_path, tree[entry_path])
                # if is a file add it to the tree
                if dirEntry.is_file(follow_symlinks=True):
                    tree[entry_path] = File(entity_path)
    
    7 /
    def browse(self, path, tree):
        # for each entry in the path
        for dirEntry in os.scandir(path):
            entry_path = dirEntry.name
            entity_path = dirEntry.path
            # check if support by git or not
            if self.git_ignore(entity_path) is False:
                # if is a dir create a new level in the tree
                if dirEntry.is_dir(follow_symlinks=True):
                    tree[entry_path] = Folder(entity_path)
                    self.browse(entity_path, tree[entry_path])
                # if is a file add it to the tree
                if dirEntry.is_file(follow_symlinks=True):
                    tree[entry_path] = File(entity_path)
    
    6 nói 50 lần mỗi khối
    def git_ignore(self, filepath):
        if '.git' in filepath:
            return True
        if '.ci' in filepath:
            return True
        if '.delivery' in filepath:
            return True
        child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        output = child.communicate()[0]
        status = child.wait()
        return status == 0
    
    ============================================================
    
    class Folder(dict):
        def __init__(self, path):
            self.path = path
            self.categories = {}
    
    ============================================================
    
    class File(object):
        def __init__(self, path):
            self.path = path
            self.filename, self.extension = os.path.splitext(self.path)
    
    18 để nó ở trong mô -đun mở rộng C lâu hơn và có thể nhanh hơn một chút. Cách tiếp cận này đã được thử nghiệm, nhưng được đề xuất bởi số 11406 bởi Antoine Pitrou. [Nguồn9]
  • Scandir có thể sử dụng một danh sách miễn phí để tránh chi phí phân bổ bộ nhớ cho mỗi lần lặp - một danh sách ngắn miễn phí 10 hoặc thậm chí 1 có thể giúp đỡ. Được đề xuất bởi Victor Stinner trên một chủ đề Python-Dev vào ngày 27 tháng Sáu.

Thảo luận trước

  • Chủ đề ban đầu tháng 11 năm 2012 Ben Hoyt bắt đầu trên Python-Ideas về việc tăng tốc os.walk()
  • Vấn đề Python 11406, bao gồm đề xuất ban đầu cho chức năng giống như scandir
  • Hơn nữa vào tháng 5 năm 2013, chủ đề Ben Hoyt bắt đầu trên Python-dev đã tinh chỉnh API
    def git_ignore(self, filepath):
        if '.git' in filepath:
            return True
        if '.ci' in filepath:
            return True
        if '.delivery' in filepath:
            return True
        child = subprocess.Popen(['git', 'check-ignore', str(filepath)],
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        output = child.communicate()[0]
        status = child.wait()
        return status == 0
    
    ============================================================
    
    class Folder(dict):
        def __init__(self, path):
            self.path = path
            self.categories = {}
    
    ============================================================
    
    class File(object):
        def __init__(self, path):
            self.path = path
            self.filename, self.extension = os.path.splitext(self.path)
    
    2
  • Tháng 11 năm 2013 Chủ đề Ben Hoyt bắt đầu trên Python-Dev để thảo luận về sự tương tác giữa Scandir và mô-đun
    def get_tree_size(path):
        """Return total size of files in path and subdirs. If
        is_dir() or stat() fails, print an error message to stderr
        and assume zero size (for example, file has been deleted).
        """
        total = 0
        for entry in os.scandir(path):
            try:
                is_dir = entry.is_dir(follow_symlinks=False)
            except OSError as error:
                print('Error calling is_dir():', error, file=sys.stderr)
                continue
            if is_dir:
                total += get_tree_size(entry.path)
            else:
                try:
                    total += entry.stat(follow_symlinks=False).st_size
                except OSError as error:
                    print('Error calling stat():', error, file=sys.stderr)
        return total
    
    6 mới
  • Tháng 6 năm 2014 Chủ đề Ben Hoyt bắt đầu trên Python-Dev để thảo luận về phiên bản đầu tiên của PEP này, với cuộc thảo luận sâu rộng về API
  • Chủ đề đầu tiên vào tháng 7 năm 2014, Ben Hoyt bắt đầu trên Python-Dev để thảo luận về các bản cập nhật của anh ấy cho PEP 471
  • Chủ đề thứ hai vào tháng 7 năm 2014, Ben Hoyt đã bắt đầu trên Python-Dev để thảo luận về các quyết định còn lại cần thiết để hoàn thiện PEP 471, cụ thể là liệu các phương thức
    scandir(path='.') -> generator of DirEntry objects
    
    1 có nên tuân theo Symlinks theo mặc định
  • Câu hỏi về StackoverFlow về lý do tại sao os.walk() chậm và con trỏ về cách sửa nó (điều này đã truyền cảm hứng cho tác giả của PEP này từ rất sớm)
  • Betterwalk, tác giả PEP này đã cố gắng trước đây, trên đó mã Scandir dựa trên

Bản quyền

Tài liệu này đã được đặt trong phạm vi công cộng.