This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author ncoghlan
Recipients Omer.Katz, alex, carljm, eric.araujo, madison.may, ncoghlan, pitrou, pydanny, r.david.murray, rhettinger, serhiy.storchaka, vstinner
Date 2016-11-11.16:55:50
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1478883350.84.0.801600523568.issue21145@psf.upfronthosting.co.za>
In-reply-to
Content
Carl's patch looks good to me, but my one request in relation to the __slots__ situation would be to give it a custom error message better indicating that lazy initialization of pre-assigned instance slots isn't supported.

Currently that case just lets the underlying AttributeError escape, which is going to be thoroughly cryptic for folks that try it and may look like an accidental oversight rather than a deliberate design decision:

    >>> class NoDict:
    ...     __slots__ = ()
    ... 
    >>> NoDict().__dict__
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'NoDict' object has no attribute '__dict__'

Suggested error message:

    TypeError: No '__dict__' attribute on 'objtype' instance to cache 'attrname' property.

Essentially, this line:

    val = instance.__dict__[self.func.__name__] = self.func(instance)

would become:

    attrname = self.func.__name__
    try:
        cache = instance.__dict__
    except AttributeError:
        msg = f"No '__dict__' attribute on {type(instance).__name__!r} instance to cache {attrname!r} property."
        raise TypeError(msg) from None
    val = cache[attrname] = self.func(instance)


I believe a future C implementation could potentially be reworked to be __slots__ compatible, but I'd have to go read the source code to be sure, and I don't think that's necessary.

Note: the class machinery itself already detects actual name conflicts between slot and method definitions:

    >>> class SlotConflict:
    ...     __slots__ = ("attr")
    ...     @property
    ...     def attr(self):
    ...         return 42
    ... 
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: 'attr' in __slots__ conflicts with class variable

The requested runtime check for the `__dict__` AttributeError covers the case where __slots__ is defined, and the cached property *isn't* listed as one of the instance attributes, but neither is __dict__.
History
Date User Action Args
2016-11-11 16:55:50ncoghlansetrecipients: + ncoghlan, rhettinger, pitrou, vstinner, carljm, pydanny, eric.araujo, alex, r.david.murray, serhiy.storchaka, madison.may, Omer.Katz
2016-11-11 16:55:50ncoghlansetmessageid: <1478883350.84.0.801600523568.issue21145@psf.upfronthosting.co.za>
2016-11-11 16:55:50ncoghlanlinkissue21145 messages
2016-11-11 16:55:50ncoghlancreate