CPython Class variable exposed to Python is altered.

Peter Otten __peter__ at web.de
Wed Apr 12 05:47:40 EDT 2017


Vincent Vande Vyvre wrote:

> Le 12/04/17 à 10:51, Peter Otten a écrit :
>> Vincent Vande Vyvre wrote:
>>
>>> Le 12/04/17 à 08:57, Vincent Vande Vyvre a écrit :
>>>> Hi,
>>>>
>>>> Learning CPython, I've made this simple exercice, a module test which
>>>> contains an object Test.
>>>>
>>>> The object Test has an attribute name, fixed at instanciation.
>>>>
>>>> So, I try my code with a script:
>>>>
>>>> -------------------------------------------
>>>> from test import Test
>>>>
>>>> for n in ("The name", "Foo", "Spam"):
>>>>      t = Test(n)
>>>>      print("%s --> %s" %(n, t.name))
>>>> -------------------------------------------
>>>>
>>>> And the return:
>>>>
>>>> Uhe name --> Uhe name
>>>> Goo --> Goo
>>>> Tpam --> Tpam
>>>>
>>>> As we can see, the first letter is changed with the next letter in
>>>> alphabetical order, but not only for the attribute name, also for the
>>>> reference n.
>>>       if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|", kwlist, &name))
>>>           return -1;
>>>
>>>       if (name) {
>>>           tmp = self->name;
>>>           Py_INCREF(name);
>> While I don't know how to do this properly you seem to be applying
>> Py_INCREF() to a C string rather than a Python string object. C being C
>> you can cast anything to anything else...
>>
>> Aren't there any warnings at compile time?
>>
> 
> No, no warning.
> 
> 
> For the truth, this code is copy-pasted from the doc.
> 
> https://docs.python.org/3.5//extending/newtypes.html#adding-data-and-methods-to-the-basic-example

But the example expects objects (the big O), not strings. Following the 
example you need

     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|", kwlist, &name))
         return -1;

and also

static PyMemberDef Test_members[] = {
     {"name", T_OBJECT_EX, offsetof(Test, name), 0,
      "The object name"},
     {NULL}  /* Sentinel */
};

If you want a string instead of an object you must not apply Py_INCREF(), 
you probably have to manage its lifetime yourself.



More information about the Python-list mailing list