Python Advanced: пользовательские объекты для реализации функций нарезки

Python

Нарезка — одна из самых захватывающих, мощных и удивительных языковых функций в Python (едва ли одна из них).Python Advanced: недоразумения и расширенное использование нарезки", я представил базовое использование, расширенное использование и некоторые недоразумения в отношении нарезки. Все они основаны на нативных типах последовательностей (таких как строки, списки, кортежи...), поэтому можем ли мы определить собственный тип последовательности и сделать так, чтобы он поддерживал синтаксис среза? Кроме того, можем ли мы настроить другие объекты (например, словари) и сделать так, чтобы они поддерживали нарезку?

1. Магический метод:__getitem__()

Нетрудно заставить пользовательский объект поддерживать синтаксис среза, просто реализуйте магический метод при определении класса.__getitem__()Вот и все. Итак, вот первое знакомство с этим методом.

грамматика:object.__getitem__(self, key)

Официальная интерпретация документа: вызывается для реализации оценки self[key].Для типов последовательностей допустимыми ключами должны быть целые числа и объекты среза.Обратите внимание, что специальная интерпретация отрицательных индексов (если класс хочет эмулировать тип последовательности) до в__getitem__() method. If key is of an inappropriate type, TypeError may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), IndexError should be raised. For mapping types, if key is missing (not in the container), KeyError should be raised.

Кратко переведите:__getitem__()Метод используется для возврата значения, соответствующего ключу параметра, который может быть целочисленным значением или объектом среза, и поддерживает отрицательные индексы; если ключ не относится к двум вышеуказанным типам, будет выдано исключение TypeError; если индекс выходит за границы, будет выброшено сообщение об ошибке IndexError; если определен тип сопоставления, когда ключевой параметр не является значением ключа его объекта, будет выброшено сообщение об ошибке KeyError.

2. Настройте последовательность для реализации функции нарезки.

Затем мы определяем простой MYLIST и назначаем ему функцию среза. (PS: Демонстрирует только полноту других функций).

class MyList():
    def __init__(self):
        self.data = []
    def append(self, item):
        self.data.append(item)
    def __getitem__(self, key):
        print("key is : " + str(key))
        return self.data[key]

l = MyList()
l.append("My")
l.append("name")
l.append("is")
l.append("Python猫")

print(l[3])
print(l[:2])
print(l['hi'])

### 输出结果:
key is : 3
Python猫
key is : slice(None, 2, None)
['My', 'name']
key is : hi
Traceback (most recent call last):
...
TypeError: list indices must be integers or slices, not str

Из результатов вывода пользовательский MyList поддерживает как поиск по индексу, так и операцию среза, что и является нашей целью.

Следует отметить, что в данном примере__getitem__()Метод будет реализовывать различные функции (получать значение бита индекса или значение среза) в соответствии с различными типами параметров, а также будет правильно обрабатывать исключения, поэтому нам не нужно писать громоздкую логику обработки. В интернете полно обучающих материалов, которые вводят в полное заблуждение: научат различать разные типы параметров, а потом напишут большой кусок кода для реализации индексного поиска и синтаксиса слайсов, что просто лишнее. Ниже приведен типичный пример ошибки:

###略去其它代码####
def __getitem__(self, index):
    cls = type(self)
    if isinstance(index, slice):  # 如果index是个切片类型,则构造新实例
       return cls(self._components[index])
    elif isinstance(index, numbers.Integral):  # 如果index是个数,则直接返回
        return self._components[index]
    else:
        msg = "{cls.__name__} indices must be integers"
        raise TypeError(msg.format(cls=cls))

3. Настройте словарь для реализации функции нарезки.

Нарезка — это функция типа последовательности, поэтому в приведенном выше примере нам не нужно писать конкретную логику реализации среза. Однако для других настраиваемых объектов типов, отличных от последовательностей, логику нарезки необходимо реализовать самостоятельно. В качестве примера возьмем пользовательский словарь (PS: только для демонстрации, не гарантирует полноту других функций):

class MyDict():
    def __init__(self):
        self.data = {}
    def __len__(self):
        return len(self.data)
    def append(self, item):
        self.data[len(self)] = item
    def __getitem__(self, key):
        if isinstance(key, int):
            return self.data[key]
        if isinstance(key, slice):
            slicedkeys = list(self.data.keys())[key]
            return {k: self.data[k] for k in slicedkeys}
        else:
            raise TypeError

d = MyDict()
d.append("My")
d.append("name")
d.append("is")
d.append("Python猫")
print(d[2])
print(d[:2])
print(d[-4:-2])
print(d['hi'])

### 输出结果:
is
{0: 'My', 1: 'name'}
{0: 'My', 1: 'name'}
Traceback (most recent call last):
...
TypeError

Ключевым моментом приведенного выше примера является извлечение значения ключа из словаря и нарезка списка значений ключа.

4. Резюме

Наконец, резюме: эта статья знакомит__getitem__()Волшебный метод, и используется для реализации функции нарезки пользовательских объектов (например, типа списка и типа словаря), надеюсь, он вам поможет.

Справочное чтение:

Python Advanced: недоразумения и расширенное использование нарезки

Использование официального документа getitem:t.cn/EbzoZyp

Анализ исходного кода назначения фрагментов Python:t.cn/EbzSaoZ

PS: Эта официальная учетная запись (Python cat) открыла группу обмена читателями.Подробности см. в разделе «Группа общения» в строке меню.

-----------------

Эта статья является оригинальной и впервые опубликована в общедоступной учетной записи WeChat [Python Cat]. Фоновый ответ «Люблю учиться», и вы можете получить более 20 избранных электронных книг бесплатно.