Issue 4998: slots on Fraction is useless (original) (raw)

Created on 2009-01-19 12:41 by Somelauw, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
fractions.diff rhettinger,2009-01-20 19:10 Add __slots__ to numeric ABCs
Messages (18)
msg80161 - (view) Author: (Somelauw) Date: 2009-01-19 12:41
>>> f = Fraction() >>> f.a = 5 >>> f.__slots__ ('_numerator', '_denominator') >>> f.a 5 >>> f.__dict__ {} When I create my own object, this doesn't happen. >>> class Slots: __slots__ = ("slot1", "slot2") >>> a = Slots() >>> a.slot3 = 6 Traceback (most recent call last): File "<pyshell#4>", line 1, in a.slot3 = 6 AttributeError: 'Slots' object has no attribute 'slot3' >>> In python2 this only happens when __slots__ is a tuple. (When __slots__ is a list, it works correctly) >>> class Slots: __slots__ = ("slot1", "slot2") >>> a = Slots() >>> a.slot3 = 8 >>> Here is a copy-paste from the python3 documentation: Without a __dict__ variable, instances cannot be assigned new variables not listed in the __slots__ definition. Attempts to assign to an unlisted variable name raises AttributeError. If dynamic assignment of new variables is desired, then add '__dict__' to the sequence of strings in the __slots__ declaration. Any non-string iterable may be assigned to __slots__. Mappings may also be used; however, in the future, special meaning may be assigned to the values corresponding to each key.
msg80183 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2009-01-19 15:33
The problem is that Fraction inherits from a class without __slots__ (Rationale), so it's useless. I suggest that the __slots__ be removed or Rationale.register() is used instead of inheritance.
msg80212 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-01-19 21:35
I believe that __slots__ was used for performance (memory, speed) reasons here rather than for preventing random attribute assignments. But maybe inheriting from Rational invalidates those reasons as well...
msg80213 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-01-19 21:37
The Decimal class has the same issue in py3k (but not in the trunk).
msg80225 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2009-01-19 23:46
Arghh! Decimal is NOT supposed to inherit or register with numbers. Guido has pronounced on this and we've discussed it multiple times. See the comments in numbers.py which were supposed to serve as a reminder. Decimals are not interoperable with floats. All instances of Real are supposed to interoperate but Decimal('1.1') does not add to float(1.1). Please rip this out of Py3.0's Decimal module.
msg80226 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2009-01-20 00:03
For the Fractions issue, consider adding an empty __slots__ declaration to every level in numbers.py. That will preclude unintended dictionary creation for anything inheriting from the numbers abcs. We should also be an issue for the other abcs. The collections ABCs are less affected because they are not as granular as number objects. So their overall memory footprint only grows by a small percentage from the inclusion of an instance dictionary.
msg80227 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2009-01-20 00:03
Py3.0.1 should not go out without this being fixed.
msg80235 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2009-01-20 07:29
Fixed the decimal issue in r68800 and r68799 . Still needs a fix to Fractions, preferably adding an empty __slots__ to all levels of numbers.py.
msg80261 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-01-20 17:52
A random data point: just for fun, I just tried assessing the impact of __slots__ on Decimal instances, by the crude method of putting all of the Decimal instances that are created during a complete run of the Decimal test suite (over 100000 of them) into a list and watching memory usage. This was on a non-debug 32-bit build of py3k, with 16-bit Py_UNICODE (which is relevant because the coefficients of Decimal instances are strings). Results: (*) ~44 bytes per Decimal on average with __slots__ ~183 bytes per Decimal on average without __slots__ The effect on speed wasn't really significant: removing __slots__ gives at worst a 1-2% slowdown on a complete run of the test-suite. So please let's not remove __slots__ from Fraction! (*) raw numbers: 120343 total number of Decimals. The following are memory readings from the RSIZE column of top. with __slots__: putting 8 copies of each Decimal into list -> 33M total usage putting 4 copies of each Decimal into list -> 55M total usage without __slots__: putting 8 copies of each Decimal into list -> 182M total usage putting 4 copies of each Decimal into list -> 96M total usage. I took the liberty of subtracting 4 bytes per list entry, to compensate for the memory taken by the list itself.
msg80262 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-01-20 17:57
> ~44 bytes per Decimal on average with __slots__ > ~183 bytes per Decimal on average without __slots__ ...and of course a difference of 140 bytes shouldn't really be much of a surprise: Python 3.1a0 (py3k:68809M, Jan 20 2009, 16:55:13) [GCC 4.0.1 (Apple Inc. build 5490)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> sys.getsizeof(dict()) 140
msg80265 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-01-20 19:43
Thanks for the patch, Raymond. I'm don't really have any experience with ABCs. I've read the PEP (a few times), but am not convinced that I fully understand all the ideas involved. What are the practical differences between having Fraction inherit from Rational directly, and registering Fraction as a subclass of Rational?
msg80267 - (view) Author: Jeffrey Yasskin (jyasskin) * (Python committer) Date: 2009-01-20 19:55
Rational has default definitions for some of its methods and properties. If Fraction inherits from Rational, it gets those definitions implicitly. If it's registered with Rational, it has to define them itself. I don't know that much about __slots__ (or I'd have known that just defining it on Fraction wouldn't work :-/) but if it doesn't prevent subclasses from having dicts, it seems like a good idea to add an empty __slots__ to most classes in the ABC hierarchy, and definitely the numeric ones.
msg80269 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-01-20 20:19
Got it. Thanks, Jeffrey. The patch looks good to me---please go ahead and apply.
msg80272 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2009-01-20 20:35
Fixed in the trunk: r68813. Benjamin, can you please apply to 2.6, 3.0 and 3.1.
msg80276 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-01-20 20:49
BTW, Raymond, it looks as though your earlier commit, r68799, changed distutils/command/wininst-8.0.exe. Was that deliberate?
msg80282 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2009-01-20 21:27
Thanks Mark. Fixed in r68819 .
msg81762 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-02-12 13:23
This needs to be merged before 3.0.1 goes out. I can't do it right now since I don't have ssh access; will do it when I get home if no-one beats me to it.
msg81790 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-02-12 18:07
Merged (manually) to py3k in r69547; svnmerged to 3.0 and 2.6 in r69548, r69549.
History
Date User Action Args
2022-04-11 14:56:44 admin set nosy: + barrygithub: 49248
2009-02-12 18:07:08 mark.dickinson set status: open -> closedmessages: +
2009-02-12 13:23:27 mark.dickinson set priority: critical -> release blockermessages: +
2009-01-20 21:27:46 rhettinger set messages: +
2009-01-20 20:49:37 mark.dickinson set messages: +
2009-01-20 20:35:16 rhettinger set assignee: rhettinger -> benjamin.petersonresolution: fixedmessages: +
2009-01-20 20:19:44 mark.dickinson set assignee: mark.dickinson -> rhettingermessages: +
2009-01-20 19:55:17 jyasskin set messages: +
2009-01-20 19:43:23 mark.dickinson set messages: +
2009-01-20 19:10:42 rhettinger set files: + fractions.diffversions: + Python 2.6, Python 3.1, Python 2.7priority: release blocker -> criticalassignee: jyasskin -> mark.dickinsonkeywords: + patchtype: behavior
2009-01-20 17:57:23 mark.dickinson set messages: +
2009-01-20 17:52:39 mark.dickinson set messages: +
2009-01-20 07:29:25 rhettinger set messages: +
2009-01-20 00:03:31 rhettinger set priority: critical -> release blockermessages: +
2009-01-20 00:03:07 rhettinger set messages: +
2009-01-19 23:46:27 rhettinger set priority: criticalnosy: + rhettingermessages: +
2009-01-19 21:37:22 mark.dickinson set messages: +
2009-01-19 21:35:40 mark.dickinson set nosy: + mark.dickinsonmessages: +
2009-01-19 15:33:36 benjamin.peterson set assignee: jyasskinmessages: + nosy: + jyasskin, benjamin.petersontitle: fractions are mutable -> __slots__ on Fraction is useless
2009-01-19 12:41:22 Somelauw create