action.name.len()
instead of len(action.name)
? Do you want to add flexibility to your favorite Python? Are you told that this is impossible? Then let's get into some of the details of the Python object model! class foo(object): def getA(self): return "A" x = foo() print x.getA() # “A” def getB(obj): return "B" foo.getA = getB # print x.getA() # “B”
>>> list.length = len
TypeError: can't set attributes of built-in/extension type 'list'
list
and foo
are instances of the same type
metaclass. But the Python interpreter distinguishes between these two types, and provides different behavior when trying to change the list of class members.string.__len__
with your own implementation, then this change will in no way be reflected on the Python modules written in C. From an API point of view, the PyString_Size (...) function will remain unchanged. Such dissonance can lead to subtle bugs and undefined behavior.typeobject.c
file in the "type_setattro"
function. This function is called when the Python script tries to add or change a property of a class. The function is readable as type.__setattr__
. To remove the restriction that prevents us, we need to replace this method with our own more loyal implementation.type.__setattr__
results in an already familiar exception:TypeError: can't set attributes of built-in/extension type 'type'
type
object, then instead of a pointer to the function "type_setattro"
you can substitute a pointer to your own version of the __setattr__
method. #include <Python.h> static setattrofunc original_setattr_func = NULL; PyMODINIT_FUNC inittypehack(void) { PyObject *m; m = Py_InitModule("typehack", NULL); if (m == NULL) return; apply_patch(); } void apply_patch() { original_setattr_func = PyType_Type.tp_setattro; // __setattr__ PyType_Type.tp_setattro = new_setattr_func; // __setattr__ }
PyType_Type
is a structure that stores all information about the metaclass type
: name, size of the object in memory, flags. In particular, it stores pointers to functions that implement certain metaclass methods.new_setattr_func
. I will not give all the code here. Just describe the logic of the work.__dyn_attrs__
field is __dyn_attrs__
, in which the strings with the names of all the added attributes are stored. In the future, it will be possible to replace only the attributes from this list. This is such a foolproof protection, which does not give a 100% guarantee, but helps to keep the original attributes intact.__dyn_attrs__
list. Otherwise, an exception is thrown.PyType_Modified(type)
function.>>> import typehack #god mode on
>>> def custom_len(text):
... return len(txt)
...
>>> list.size = custom_len # "size"
>>> ['Tinker', 'Tailor', 'Solder', 'Spy'].size()
4
>>> str.len = property(custom_len) # "len"
>>> "Hello".len
5
Source: https://habr.com/ru/post/142034/
All Articles