[Python-bugs-list] [ python-Bugs-576990 ] inheriting from property and docstrings
noreply@sourceforge.net
noreply@sourceforge.net
Tue, 24 Sep 2002 05:43:35 -0700
Bugs item #576990, was opened at 2002-07-03 10:42
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=576990&group_id=5470
Category: Python Interpreter Core
Group: Python 2.2.1
Status: Open
>Resolution: Accepted
Priority: 5
Submitted By: Roeland Rengelink (rengelink)
>Assigned to: Guido van Rossum (gvanrossum)
Summary: inheriting from property and docstrings
Initial Comment:
If I inherit from property, and try to initialize a derived
property object, the doc string doesn't get set. This bug
was introduced in 2.2.1, and is present in 2.3a0:
Compare:
Python 2.2 (#1, Mar 26 2002, 15:46:04)
[GCC 2.95.3 20010315 (SuSE)] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> class myprop(property):pass
...
>>> a = myprop(None, None, None, 'hi')
>>> print a.__doc__
hi
and,
Python 2.2.1 (#1, Jun 16 2002, 16:19:48)
[GCC 2.95.3 20010315 (SuSE)] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> class myprop(property):pass
...
>>> a = myprop(None, None, None, 'hi')
>>> print a.__doc__
None
There is no problem with the getter/setter functions
passed to the constructor. i.e.: myprop(f,g,h,None) works
identical in 2.2 and 2.2.1
Good luck,
Roeland Rengelink
----------------------------------------------------------------------
>Comment By: Guido van Rossum (gvanrossum)
Date: 2002-09-24 08:43
Message:
Logged In: YES
user_id=6380
OK, I'll have a look. We've have numerous hacks upon hacks
to get __doc__ to behave right. I don't know if it is within
my powers to fix this without breaking other things. But if
it is, I'll try to fix it in 2.2.1 as well as 2.3.
----------------------------------------------------------------------
Comment By: Roeland Rengelink (rengelink)
Date: 2002-09-09 06:49
Message:
Logged In: YES
user_id=302601
To give a usage example:
(because rhettinger thought this was a very strange use of
properties, and, for all I know, he may be right)
>>> class typed_property(property):
... def __init__(self, tp, doc):
... def getter(inst):
... return inst.__dict__[self]
... def setter(inst, val):
... if not isinstance(val, tp):
... raise TypeError
... inst.__dict__[self] = val
... property.__init__(self, getter, setter,
... None, doc)
...
>>> class A(object):
... a = typed_property(int, 'a prop')
...
>>> inst = A()
>>> inst.a = 1
>>> print inst.a
1
>>> inst.a = 'a'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in setter
TypeError
>>> A.a.__doc__
'a prop'
The last only works in 2.2, and then only if typed_property
itself has no doc string
----------------------------------------------------------------------
Comment By: Raymond Hettinger (rhettinger)
Date: 2002-09-08 18:11
Message:
Logged In: YES
user_id=80475
Okay, now I see what you're trying to do.
Still, it the strangest use of property that I've seen to-date.
Re-opening the bug report.
----------------------------------------------------------------------
Comment By: Raymond Hettinger (rhettinger)
Date: 2002-09-08 17:55
Message:
Logged In: YES
user_id=80475
I think this is based on a misunderstanding of how to use
property. Instead of inheriting from it, you use it as a
function call in a new-style class (derived from object):
This works fine in versions from 2.2 upto 2.3a:
>>> class Myprop(object):
a = property(None,None,None,'a sample docstring')
>>> Myprop.a.__doc__
'a sample docstring'
Marking as invalid and closing.
----------------------------------------------------------------------
Comment By: Roeland Rengelink (rengelink)
Date: 2002-07-09 07:52
Message:
Logged In: YES
user_id=302601
I think I found the problem,
Compare:
>>> property.__doc__
'property(fget=None,.... # the doc string
and
>>> property.__dict__['__doc__']
<member '__doc__' of 'property' objects>
Note that property.__doc__ and property.__dict__['__doc__']
are not the same. Python will go out of its way to prevent this
weird situation in user derived classes.,
1. type_new(name, bases, attrs) will copy attrs to
new_tp.tp_dict, and will also copy attrs['__doc__'] to tp.tp_doc
2. PyType_Ready(tp) will copy tp.tp_doc to
tp.tp_dict['__doc__'] if tp.tp_dict['__doc__'] is undefined
This guarantees that tp.tp_dict['__doc__'] will exist, usually
copying tp.tp_doc, and shadowing property.tp_dict['__doc__']
if tp is derived from property
The solution seems to be:
1. In type_new():
if possible copy attr['__doc__'] to tp.tp_doc, and delete
__doc__ from attr (to prevent ending up in tp_dict)
2. in PyType_Ready():
don't copy tp.tp_doc to tp_dict['__doc__']
These two steps make sure that, tp_dict['__doc__'] no longer
shadows properties.tp_dict['__doc__']. Unfortunately, this
means that tp.__doc__ doesn't generally return the docstrings
for user-defined types. Therefore:
3. in type_get_doc():
return tp.tp_doc also for heap types.
The result of this will be:
1. properties will be subclassable again. (good)
2. __doc__ string become read-only attributes (bad??)
3. test cases in test_descr that assume that
instance.__dict__['__doc__'] exists, will fail
4. a weird test_failure in test_module.py
Patches for this modification are attached, except for
(test_module.py), which I don't understand.
----------------------------------------------------------------------
Comment By: Roeland Rengelink (rengelink)
Date: 2002-07-08 08:23
Message:
Logged In: YES
user_id=302601
Some more details:
In fact 2.2.1 is consistently wrong, whereas 2.2 is
inconsistently right ;), compare:
Python 2.2.1 (#20, Jul 8 2002, 13:25:14)
[GCC 3.1] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> class myprop(property):pass
...
>>> class yourprop(property):
... "A doc string"
...
>>> print myprop(None, None, None, 'Hi there').__doc__
None
>>> print yourprop(None, None, None, 'Hi there').__doc__
A doc string
and
Python 2.2 (#4, Jan 7 2002, 11:59:25)
[GCC 2.95.2 19991024 (release)] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> class myprop(property):pass
...
>>> class yourprop(property):
... "A doc string"
...
>>> print myprop(None, None, None, 'Hi there').__doc__
Hi there
>>> print yourprop(None, None, None, 'Hi there').__doc__
A doc string
So, in 2.2.1 myprop(...).__doc__ will allways return
myprop.__doc__. In 2.2 myprop.__doc__ will return the
instance's
__doc__, iff myprop.__doc__ is None.
For the record: I was expecting 'Hi there' (i.e.
obj->prop_doc), as in:
>>> property(None, None, None, 'Hi there').__doc__
'Hi there'
Hope this helps,
Roeland
----------------------------------------------------------------------
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=576990&group_id=5470