Смущает преобразование цикла for в карту, которое дает разные результаты.Python

Программы на Python
Ответить
Anonymous
 Смущает преобразование цикла for в карту, которое дает разные результаты.

Сообщение Anonymous »

У меня есть существующая реализация функции, использующая цикл for.
Я хочу преобразовать ее в более функциональную форму с помощью операции сопоставления .
(Эта функция работает)
Вот моя текущая реализация. Это функция, которую я хочу преобразовать:
def _fast_scandir_3_impl_get_paths_recursive(target: str) -> list[str]:
items:list[str] = []
if os.path.isfile(target):
items.append(target)
elif os.path.isdir(target):
items.append(target)
for item in os.listdir(target):
item = os.path.join(target, item)
more_items = _fast_scandir_3_impl_get_paths_recursive(item)
items.extend(more_items)
return items

(Эта функция не работает)
Это моя попытка преобразовать ее .
def _fast_scandir_3_impl_get_paths_recursive(target: str) -> list[str]:
items:list[str] = []
if os.path.isfile(target):
items.append(target)
elif os.path.isdir(target):
items.append(target)
items.extend(
map(
_fast_scandir_3_impl_get_paths_recursive,
map(
lambda item: os.path.join(target, item),
os.listdir(target),
)
)
)
return items

Вот остальная часть кода
Строго говоря, вам это не нужно. (См. добавленные тестовые примеры в конце этого вопроса.) Я включил его, чтобы вы могли запустить что-то, вызывающее исключение.
  • Если вы запустите это с версией «цикла for» указанной выше функции она будет работать
  • Если вы запустите это с версией «map» вышеуказанной функции вызовет исключение
def _fast_scandir_3_impl_convert_paths_to_path_tuples(paths:list[str]) -> list[tuple[str, str]]:
def path_to_tuple(path:str) -> tuple[str, str]:
if os.path.isfile(path):
return ('f', path)
elif os.path.isdir(path):
return ('d', path)

return (
list(
map(
path_to_tuple,
paths,
)
)
)

def fast_scandir_3(target:str) -> list[tuple[str, str]]:

# get all paths
paths = _fast_scandir_3_impl_get_paths_recursive(target)

# convert paths to tuple depending on type
path_tuples = _fast_scandir_3_impl_convert_paths_to_path_tuples(paths)

return path_tuples

Моя структура тестового каталога:
example-target-directory/
example-file.txt
example/subdir/
example-file-2.txt

Вывод
Исходный код:
running fast_scandir_3(example-target-directory)
results:
('d', '/home/user/work/python/example-target-directory')
('f', '/home/user/work/python/example-target-directory/example-file.txt')
('d', '/home/user/work/python/example-target-directory/example-subdir')
('f', '/home/user/work/python/example-target-directory/example-subdir/example-file-2.txt')

"Новый" код:
  • Он прерывается при вызове функции _fast_scandir_3_impl_convert_paths_to_path_tuples, потому что вместо аргументом является один список, а не набор вложенных списков.
Немного изменив код, мы можем наблюдать следующее:
def fast_scandir_3(target:str) -> list[tuple[str, str]]:

# get all paths
paths = _fast_scandir_3_impl_get_paths_recursive(target)
print(paths)

Вы должны обнаружить, что print(paths) печатает вложенный набор списков, а не один список. Если вы не заметили такого поведения, значит что-то не так.
Я не могу понять, почему эта функция возвращает список списков вместо просто список.
Некоторая отладка
Если мы сломаем функцию, поведение которой изменилось:
def _fast_scandir_3_impl_get_paths_recursive(target: str) -> list[str]:
items:list[str] = []

if os.path.isfile(target):
items.append(target)

# it breaks somewhere in here:
elif os.path.isdir(target):
items.append(target)

# this appears to be fine
joined_items = list(
map(
lambda item: os.path.join(target, item),
os.listdir(target),
)
)
print(joined_items)

items.extend(
# this should produce a list
map(
_fast_scandir_3_impl_get_paths_recursive, # this function called with arg `str`
joined_items, # this is a list of str
)
)
return items

Кажется, что должно быть то же самое, но это не так.
Мы можем даже проверить, что _fast_scandir_3_impl_get_paths_recursive получает str аргументы, использующие это:
def _fast_scandir_3_impl_get_paths_recursive(target: str) -> list[str]:
assert isinstance(target, str), f'target is not str: {target}, {type(target)}'

Действительно.
Трассировка стека
Фактическое исключение с трассировкой стека:
Traceback (most recent call last):
File "fast_scandir_test_3.py", line 7, in
directory_list = _fast_scandir_3_impl_get_paths_recursive(target)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "fast_scandir.py", line 113, in _fast_scandir_3_impl_get_paths_recursive
reduce(
File "fast_scandir.py", line 116, in
lambda item: do(item),
^^^^^^^^
File "fast_scandir.py", line 92, in do
tmp = _fast_scandir_3_impl_get_paths_recursive(item)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "fast_scandir.py", line 129, in _fast_scandir_3_impl_get_paths_recursive
items.extend(

TypeError: stat: path should be string, bytes, os.PathLike or integer, not list

Дополнительная информация: карта работает должным образом
  • Кто-то в комментариях предположил, что несколько вызовов карты создает вложенные итераторы, но я не обнаружил такого поведения. Этот код создает один список без вложенных списков.
result = (
list(
map(
lambda x: x + 1,
map(
lambda x: x + 2,
map(
lambda x: x + 3,
[1, 2, 3, 4, 5],
)
)
)
)
)

print(result) # [7, 8, 9, 10, 11]

Два очень простых тестовых файла, которые вы можете попробовать:
# test1.py

import os

def _fast_scandir_3_impl_get_paths_recursive(target: str) -> list[str]:
items:list[str] = []
if os.path.isfile(target):
items.append(target)
elif os.path.isdir(target):
items.append(target)
for item in os.listdir(target):
item = os.path.join(target, item)
more_items = _fast_scandir_3_impl_get_paths_recursive(item)
items.extend(more_items)
return items

print(_fast_scandir_3_impl_get_paths_recursive('example-target-directory'))

# test2.py

import os

def _fast_scandir_3_impl_get_paths_recursive(target: str) -> list[str]:
items:list[str] = []
if os.path.isfile(target):
items.append(target)
elif os.path.isdir(target):
items.append(target)
items.extend(
map(
_fast_scandir_3_impl_get_paths_recursive,
map(
lambda item: os.path.join(target, item),
os.listdir(target),
)
)
)
return items

print(_fast_scandir_3_impl_get_paths_recursive('example-target-directory'))

Они печатают разные вещи:
user@host:~/work/python$ python3 test1.py
['example-target-directory', 'example-target-directory/example-subdir', 'example-target-directory/example-subdir/example-file-2.txt', 'example-target-directory/example-file.txt']

user@host:~/work/python$ python3 test2.py
['example-target-directory', ['example-target-directory/example-subdir', ['example-target-directory/example-subdir/example-file-2.txt']], ['example-target-directory/example-file.txt']]


Подробнее здесь: https://stackoverflow.com/questions/792 ... nt-results
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»