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 ethan.furman
Recipients Jim.Jewett, Joshua.Chin, ethan.furman, pitrou, r.david.murray, rhettinger
Date 2014-11-03.17:38:24
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1415036305.25.0.181235090408.issue22766@psf.upfronthosting.co.za>
In-reply-to
Content
Ethan stated:
>> The only problem with the design is that it does not play well with others.  For
>> duck-typeable just do a check on 'other' to see if it has an .items() method, and
>> return NotImplemented if it does not.  Oh, and check that 'self' is Counter, and
>> also return NotImplemented if that fails.

R. David Murray replied:
> No, that doesn't support duck typing.  Duck typing is not putting arbitrary
> restrictions on what objects you accept, but only essential restrictions.

__iadd__ will raise an AttributeError if 'other' doesn't have an 'items' method -- how is that an arbitrary restriction?

If 'other' doesn't have an 'items' but does know how to add itself to Counter, it won't matter because Counter is raising an exception instead of returning NotImplemented.  

What other types return NotImplemented when 'other' is not the expected (sub)type?  bytes, bytearray, int, float, string, dict, list, tuple, Enum, deque, defaultdict, OrderedDict, Decimal, Fraction, and Counter itself for every binary method /except/ the four inplace ops it supplies itself.

> And as noted above, if you return NotImplemented, then you get an error message
> that essentially says "this is impossible" instead of "this is what didn't work".

Correct implementation should not be sacrificed for a nicer error message.

>> Here's proof of subclass trouble -- the idea is to make an immutable Counter:
>> [snip example]

> Your subclass doesn't override __iadd__ or any of the other mutation methods.  Why
> would you expect it to be immutable if it doesn't?

You're right, that was a bad example.  A subclass would need to override any method whose behavior it wants to change.

What does not seem correct to me is raising an exception because the type of 'other' is not correct, instead of returning NotImplemented, and in 14 other core datatypes it does work that way, and even in Counter it works that way for any in-place method that Counter itself doesn't override, and it does work that way /in/ Counter for the normal binary ops that it /does/ override.

> For subclassing to work, the fix is:
> 
>         if not hasattr(other, 'items') or type(self) is not Counter:
>             return NotImplemented

>> I've never seen a type check like that in a Python class, and I hope I never do.  *That*
>> breaks subclassing.

Explanations and examples go a lot further than bare statements.

[Jim Jewitt posts an explanation.]

Ah, I see.  Thank you, Jim.

Okay, I agree that the check against the base class is ill-advised (and I modified some of the above reply to match that understanding).

However, I am still unconvinced that 'other' should not be checked.  Hopefully the python-dev thread will shed more light on this.
History
Date User Action Args
2014-11-03 17:38:25ethan.furmansetrecipients: + ethan.furman, rhettinger, pitrou, r.david.murray, Jim.Jewett, Joshua.Chin
2014-11-03 17:38:25ethan.furmansetmessageid: <1415036305.25.0.181235090408.issue22766@psf.upfronthosting.co.za>
2014-11-03 17:38:25ethan.furmanlinkissue22766 messages
2014-11-03 17:38:24ethan.furmancreate