Переопределение Python для встроенных типов данных - PullRequest
3 голосов
/ 02 июня 2011

Можно ли переопределить, какой объект используется в скобках []?

Я могу создать подкласс list объекта, но как заставить интерпретатор использовать мой подкласс вместо объекта списка встроенных файлов? Является ли это возможным?

(я почти уверен, что использую неправильные термины для вопроса - не стесняйтесь редактировать)

>>> class mlist(list):
...     def __init__(self):
...         list.__init__(self)
...     def __getitem__(self, item):
...         return list.__getitem__(self, item) * 2
... 
>>> testlist = mlist()
>>> testlist.append(21)
>>> testlist[0]
42
>>> list = mlist() # maybe setting the 'list' type will do it?
>>> testlist = []
>>> testlist.append(21)
>>> testlist[0]
21                 # Nope
>>> 

У меня нет практического использования для этого - просто любопытно.

Ответы [ 4 ]

7 голосов
/ 02 июня 2011

Скобки являются частью языка.Они используются для создания списков.Переопределить это невозможно (и не желательно!).

2 голосов
/ 02 июня 2011

Попробуйте запустить код после того, как вы запустили опубликованный код

>>> testlist = list()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'mlist' object is not callable

Теперь определите тип, используя опубликованный код

>>> type([])
<type 'list'>
>>> type(list)
<class '__main__.mlist'>
>>> type(testlist)
<type 'list'>

кажется, что [] создает list, вместо mlist, это выглядит странно: S

Обновление

Я проверил байт-код, созданный с помощью dis, и кодниже было сгенерировано

>>> import dis # python's disassembler

>>> def code1():
...     return []
...
>>> dis.dis(code1)
  2           0 BUILD_LIST               0
              3 RETURN_VALUE

>>> def code2():
...     return list()
...
>>> dis.dis(code2)
  2           0 LOAD_GLOBAL              0 (list)
              3 CALL_FUNCTION            0
              6 RETURN_VALUE

Похоже, что list вызовет все, что ему назначено, а [] будет преобразован в BUILD_LIST байт-код.Похоже, что [] не переводится в list, следовательно, поведение [] привязано к созданию списка.

Обновление 2

Класс Python можетбыть обновленным

>>> class NewList(list):
...     pass
...
>>> a = NewList()
>>> a.append(23)
>>> a[0]
23
>>> def double_getitem(self, key):
...     return list.__getitem__(self, key) * 2
...
>>> NewList.__getitem__ = double_getitem
>>> a[0]
46

Ну, кроме встроенных классов, вроде списка

>>> list.__getitem__ = double_getitem
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'list'
0 голосов
/ 02 июня 2011

Это возможно. Большинство вещей возможно в программном обеспечении, если вы готовы стать достаточно грязными. :) Это плохая идея, конечно. Если вы написали какое-либо программное обеспечение с использованием такого изменения, у него будет ряд проблем:

  • Читатели могут легко запутаться в вашем коде. Они думают, что читают Python, поэтому они думают, что знают, что [] означает, но, к сожалению, нет.
  • Если бы область изменения была глобальной (вместо того, чтобы ограничиваться, скажем, одним исходным файлом), вам было бы трудно объединить свое программное обеспечение с чьим-либо другим, поскольку вы эффективно пишете на двух разных языках. Другое программное обеспечение может сломаться, если [] начнет возвращать другой тип, даже если это подкласс.
  • Если область изменения ограничена, вы можете легко запутаться, глядя на разные исходные файлы с разными правилами синтаксиса. Если у вас есть данные, которые обрабатываются различными модулями, вы можете оказаться в ситуации, когда ваш код хочет, чтобы эти данные были в mlist, а какой-то другой код - в списке, и тогда вам, вероятно, грустно.

Вот модуль расширения CPython 2003 года ( и пример ), который работает с Python 2.3. Скорее всего, его нужно обновить, чтобы он работал с более свежими версиями Python, но он показывает, насколько грязными вам нужно для этого конкретного подхода.

Другой подход - изменить вещи на уровне грамматики. Logix предоставляет инструменты для этого подхода. Это включает в себя меньшее количество хакерских атак на C, но приводит к появлению нового синтаксического анализатора и компилятора.

0 голосов
/ 02 июня 2011

Вы можете заменить список на mlist, используя не, как вы пытались,

list = mlist()

, а просто

list = mlist

(у вас могут возникнуть проблемы с запуском в интерпретаторе, потому что mlist() вызывает list () и т. д. рекурсивно. Но если вы поместите код, определяющий mlist, в другую область, например, в импортируемый вами модуль, он будет работать.) Затем вы можете создать новый mlist с помощью

testlist = list()

но, что интересно, не по

testlist = []

, который я считал синтаксически эквивалентным.По-видимому, [] жестко задан для вызова встроенного типа списка, а не того объекта, который в данный момент называется «список».

...