Могу ли я рассматривать файл как список в python?

Это своего рода вопрос, но я также просто надеюсь, что мне не нужно писать кучу кода, чтобы получить желаемое поведение. (Кроме того, если он уже существует, он, вероятно, работает быстрее, чем то, что я написал бы в любом случае.) У меня есть несколько больших списков чисел, которые не могут уместиться в памяти — по крайней мере, не все одновременно. И это нормально, потому что мне нужна только небольшая часть каждого списка за раз, и я знаю, как сохранять списки в файлы и зачитывать часть списка, которая мне нужна. Проблема в том, что мой метод сделать это несколько неэффективен, поскольку он включает в себя итерацию по файлу для той части, которую я хочу. Итак, мне было интересно, есть ли какая-то библиотека или что-то еще, что я не нашел, что позволяет мне индексировать файл, как если бы это был список, используя нотацию [], с которой я знаком. Так как я сам пишу файлы, я могу сделать из них форматирование, какое мне нужно, но в настоящее время мои файлы не содержат ничего, кроме элементов списка с \n в качестве разделителя между значениями.

Просто напомнить, что я ищу/сделать это более конкретным.

  1. Я хочу использовать нотацию индексации списка (включая нарезку на подсписок и отрицательную индексацию) для доступа к содержимому списка, записанного в файле.
  2. Доступный подсписок (например, f[1:3]) должен возвращаться как объект списка python в памяти.
  3. Я хотел бы иметь возможность назначать индексы файла (например, f[i] = x должен записать значение x в файл f в месте, соответствующем индексу i)

Честно говоря, я не ожидаю, что такое может существовать, но никогда не знаешь, когда упускаешь что-то в своем исследовании. Итак, я решил спросить. Кстати, если этого не существует, можно ли перегрузить оператор [] в python?

Вы можете перегрузить оператор [], определив __getitem__. Кроме того, когда вы говорите «индекс», вы имеете в виду «позицию в файле» (в отличие от номера строки), верно?

gmds 10.04.2019 02:43

Как минимум, чтобы сделать этот эффективный, вам нужно записывать записи с фиксированной длиной кадра, чтобы можно было использовать seek для поиска нужных элементов без необходимости учитывать переменную длину строки.

donkopotamus 10.04.2019 02:55

@gmds Под индексом я подразумеваю позицию в списке, сохраняемую в файле. В настоящее время для меня означает номер строки, так как это то, что разделяет элементы списка, но в настоящее время я думаю, что хочу сделать то, что предлагает donkopotamus, с фиксированной длиной кадра (что означает, что я должен переключиться на двоичный файл?), но мое понимание " позиция в файле" - это точный символ/байт, в котором я нахожусь, а это не то, что мне нужно, поскольку каждый кадр занимает несколько байтов. Я думаю, что я хочу использовать seek и struct для чтения/записи в файл с использованием форматирования c-типа, но мне нужно провести дополнительные исследования, чтобы быть уверенным.

suri0001 11.04.2019 00:52
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
157
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если ваши данные чисто числовые, вы можете рассмотреть возможность использования массивов numpy и сохранения данных в формате npy. После сохранения в этом формате вы можете загрузить отображаемый в память файл как:

>>> X = np.load("some-file.npy", mmap_mode = "r")
>>> X[1000:1003]
memmap([4, 5, 6])

Этот доступ будет загружаться непосредственно с диска, не требуя загрузки начальных данных.

Если OP не может поместить все свои данные в память, есть ли способ вообще записать этот файл?

Nathan Vērzemnieks 11.04.2019 07:45

Конечно... используя, например, numpy.memmap.

donkopotamus 11.04.2019 11:35

Я думаю, что это может быть полезно включить в ваше решение, была моя точка зрения.

Nathan Vērzemnieks 11.04.2019 18:04

Похоже, это может быть то, что мне нужно, но просмотр документации memmap предупредил меня о модуле python mmap. Прямо сейчас я не совсем уверен, какой из них мне нужен, потому что они, похоже, делают то же самое, что и memmap, только для numpy. Есть ли причина, по которой вы специально предложили memmap вместо mmap?

suri0001 11.04.2019 23:26

Только потому, что для быстрого доступа вам нужен фреймовый протокол, который будет использовать записи фиксированной длины для хранения элементов (это означает, что реализация может быстро искать нужное место) ... если вы просто mmap свой текстовый файл, у вас будет нет записи фиксированной длины и не может оптимизировать поиск правильного индекса... существует множество альтернатив разное, таких как hdf5

donkopotamus 11.04.2019 23:52

На самом деле вы можете сделать это, написав простой класс, я думаю:

class FileWrapper:

    def __init__(self, path, **kwargs):
        self._file = open(path, 'r+', **kwargs)

    def _do_single(self, where, s=None):
        if where >= 0:
            self._seek(where)

        else:
            self._seek(where, 2)

        if s is None:
            return self._read(1)

        else:
            return self._write(s)

    def _do_slice_contiguous(self, start, end, s=None):
        if start is None:
            start = 0

        if end is None:
            end = -1

        self._seek(start)
        if s is None:
            return self._read(end - start)

        else:
            return self._write(s)

    def _do_slice(self, where, s=None):
        if s is None:
            result = []
            for index in where:
                file._seek(index)
                result.append(file.read(1))

            return result

        else:
            for index, char in zip(where, s):
                file._seek(index)
                file._write(char)

            return len(s)

    def __getitem__(self, key):
        if isinstance(key, int):
            return self._do_single(key)

        elif isinstance(key, slice):
            if self._is_contiguous(key):
                return self._do_slice_contiguous(key.start, key.stop)

            else:
                return self._do_slice(self._process_slice(key))

        else:
            raise ValueError('File indices must be ints or slices.')

    def __setitem__(self, key, value):
        if isinstance(key, int):
            return self._do_single(key, value)

        elif isinstance(key, slice):
            if self._is_contiguous(key):
                return self._do_slice_contiguous(key.start, key.stop, value)

            else:
                where = self._process_slice(key)
                if len(where) == len(value):
                    return self._do_slice(where, value)

                else:
                    raise ValueError('Length of slice not equal to length of string to be written.')


    def __del__(self):
        self._file.close()

    def _is_contiguous(self, key):
        return key.step is None or key.step == 1

    def _process_slice(self, key):
        return range(key.start, key.stop, key.step)

    def _read(self, size):
        return self._file.read(size)

    def _seek(self, offset, whence=0):
        return self._file.seek(offset, whence)

    def _write(self, s):
        return self._file.write(s)

Я уверен, что можно было бы сделать много оптимизаций, так как я торопился с этим, но писать было весело.

Это не отвечает на вопрос полностью, потому что он поддерживает произвольный доступ к персонажи, как предполагается, к строкам, которые находятся на более высоком уровне абстракции и более сложны в обработке (поскольку они могут быть переменной длины)

Другие вопросы по теме