Redefining Pythons builtin datatypes

寵の児 提交于 2020-01-01 14:43:49

问题


Is it possible to redefine which object the brackets [] use?

I can subclass the list object, but how to I make the interpreter use my subclass in place of the buildin list object? Is it possible?

(I'm pretty sure I'm using the wrong terms for the question- feel free to edit)

>>> 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
>>> 

I don't have a practical use for this- just curious.


回答1:


Try running the code after you've run the code you posted

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

Now, determine the type using the code I've posted

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

it seems that [] creates list, instead of mlist, it looks strange :S

Update

I checked the bytecode generated using dis, and the code below was generated

>>> 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

It appears that list will invoke whatever is assigned to it, while [] will be converted to BUILD_LIST bytecode. It appears that [] is not translated to list, hence []'s behavior is stucked to creating list.

Update 2

Python class can be updated

>>> 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

Well, except for builtin classes, like list

>>> 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'



回答2:


The brackets are part of the language. They're used to create lists. It's not possible to redefine that (and not desirable either!).




回答3:


You can replace list with mlist by using not, as you tried,

list = mlist()

but simply

list = mlist

(You might have problems running this in the interpreter, because mlist() calls list() and so on recursively. But if you put the code that defines mlist in a different scope, such as in a module you import, then it will work.) Then you can create a new mlist by

testlist = list()

but interestingly, not by

testlist = []

which I had thought was syntactically equivalent. Apparently [ ] is hardcoded to call the built-in list type, rather than whatever object is currently named "list".




回答4:


It's possible. Most things are possible in software, if you're willing to get sufficiently dirty. :) It's a bad idea, of course. If you wrote any software using such a change, it would have a number of problems:

  • Readers would be easily confused by your code. They think they're reading Python, so they think they know what [] means, but oops nope they don't.
  • If the scope of the change was global (instead of limited to, say, a single source file) then you would have difficulty combining your software with anyone else's, since you're effectively writing in two different languages. Other software might break if [] starts returning a different type, even if it's a subclass.
  • If the scope of the change is limited, then you may easily end up being confused yourself as you look at different source files with different syntax rules. If you have data that is operated on by different modules, you may find yourself in a circumstance where your code wants that data in an mlist and some other code wants it in a list and then you're probably sad.

Here's a CPython extension module from 2003 (and example) which works with Python 2.3. It very likely needs to be updated to work with more recent versions of Python, but it demonstrates how dirty you need to get for this particular approach.

Another approach is to change things at the level of the grammar. Logix provides tools for this approach. This involves less C hacking, but brings in an entire new parser and compiler.



来源:https://stackoverflow.com/questions/6217351/redefining-pythons-builtin-datatypes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!