Могу ли я рассматривать файл как список в Python? - PullRequest
2 голосов
/ 10 апреля 2019

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

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

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

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

Ответы [ 2 ]

1 голос
/ 10 апреля 2019

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

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)

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

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

1 голос
/ 10 апреля 2019

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

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

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

...