
I'm currently writing a class that can take either a str of bytes object, and is meant to work with either type. For my purpose, it makes sense to return the underlying bytes object when calling bytes() on it. However, defining __bytes__ on the class means that I also have to return bytes even if the underlying object is a str. The obvious way to fix this is to define two different classes, one which handles str and one which handles bytes. However, I was wondering if returning NotImplemented from __bytes__ would be a viable alternative. I'm not sure if there'd be any performance hit (there is probably some optimized C code that simply checks for the existence of __bytes__ in the namespace without calling it), but hopefully there aren't. Another alternative would be to define object.__bytes__, which one can call to fall back to the default behaviour. While I'm at it, maybe other methods could use that, too (thinking mainly of __int__, __float__, __abs__, __complex__, __round__, __index__, and maybe __len__ and __iter__). Thoughts? Is it reasonable to define a single class that can work with both str and bytes, or should I fix my code? -Emanuel

Can't you just raise an exception when __bytes__() is called if the underlying representation uses str? Returning NotImplemented is not the right thing here -- that's not supposed to make it into user code, it's only meant to be used when there's a binary operation, to give the other argument a chance at providing an implementation. (And if they both return NotImplemented, Python will always turn that into a TypeError or a default answer.) But for unary operators like bytes() there's no such thing, and the NotImplemented would leak into user code, where it can do more damage than good. On Mon, Jun 6, 2016 at 10:05 AM, Émanuel Barry <vgr255@live.ca> wrote:
-- --Guido van Rossum (python.org/~guido)

Sure (that's what I'm doing right now), but my intention was that returning NotImplemented would make bytes() fall back to the default behaviour. But for my use case, it makes no difference as an error is raised either way, just a different one.
My understanding was that returning NotImplemented would tell the caller (here, bytes()) "I can't do that, figure it out yourself" like binary operations do, which would eventually become an error. It made sense to me at the time, but now I realize that it doesn't make sense if there's only one argument, so I'll raise the error myself. Thanks for the reply, -Emanuel

On Mon, Jun 6, 2016 at 11:36 AM, Émanuel Barry <vgr255@live.ca> wrote:
To invoke the default behavior just return super().__bytes().
Right. NotImplemented is frequently misunderstood (and it doesn't help that there's also a completely unrelated exception NotImplementedError). If you want to contribute some docs about this we'd be delighted! (bugs.python.org) -- --Guido van Rossum (python.org/~guido)

Well, object.__bytes__() doesn't exist, so that would just be another unhelpful error.
Done! http://bugs.python.org/issue27242 -Emanuel

On Mon, Jun 6, 2016 at 3:01 PM Émanuel Barry <vgr255@live.ca> wrote:
"The appropriate way to signal that an operation is unsupported is to leave the relevant method undefined." +1 Thanks for writing that. It's unfortunate that some folks see things like __hash__ returning None and they assume that's the appropriate pattern for signaling an operation is not supported.

On 06.06.16 20:05, Émanuel Barry wrote:
This would break a lot of code that just checks the existence of corresponding methods. Even if change all this code to call corresponding methods and check the result, this would affect the performance.
Thoughts? Is it reasonable to define a single class that can work with both str and bytes, or should I fix my code?
Define tree classes. A base class, its constructor returns an instance of appropriate child class, and two child classes for str and bytes.

Can't you just raise an exception when __bytes__() is called if the underlying representation uses str? Returning NotImplemented is not the right thing here -- that's not supposed to make it into user code, it's only meant to be used when there's a binary operation, to give the other argument a chance at providing an implementation. (And if they both return NotImplemented, Python will always turn that into a TypeError or a default answer.) But for unary operators like bytes() there's no such thing, and the NotImplemented would leak into user code, where it can do more damage than good. On Mon, Jun 6, 2016 at 10:05 AM, Émanuel Barry <vgr255@live.ca> wrote:
-- --Guido van Rossum (python.org/~guido)

Sure (that's what I'm doing right now), but my intention was that returning NotImplemented would make bytes() fall back to the default behaviour. But for my use case, it makes no difference as an error is raised either way, just a different one.
My understanding was that returning NotImplemented would tell the caller (here, bytes()) "I can't do that, figure it out yourself" like binary operations do, which would eventually become an error. It made sense to me at the time, but now I realize that it doesn't make sense if there's only one argument, so I'll raise the error myself. Thanks for the reply, -Emanuel

On Mon, Jun 6, 2016 at 11:36 AM, Émanuel Barry <vgr255@live.ca> wrote:
To invoke the default behavior just return super().__bytes().
Right. NotImplemented is frequently misunderstood (and it doesn't help that there's also a completely unrelated exception NotImplementedError). If you want to contribute some docs about this we'd be delighted! (bugs.python.org) -- --Guido van Rossum (python.org/~guido)

Well, object.__bytes__() doesn't exist, so that would just be another unhelpful error.
Done! http://bugs.python.org/issue27242 -Emanuel

On Mon, Jun 6, 2016 at 3:01 PM Émanuel Barry <vgr255@live.ca> wrote:
"The appropriate way to signal that an operation is unsupported is to leave the relevant method undefined." +1 Thanks for writing that. It's unfortunate that some folks see things like __hash__ returning None and they assume that's the appropriate pattern for signaling an operation is not supported.

On 06.06.16 20:05, Émanuel Barry wrote:
This would break a lot of code that just checks the existence of corresponding methods. Even if change all this code to call corresponding methods and check the result, this would affect the performance.
Thoughts? Is it reasonable to define a single class that can work with both str and bytes, or should I fix my code?
Define tree classes. A base class, its constructor returns an instance of appropriate child class, and two child classes for str and bytes.
participants (4)
-
Guido van Rossum
-
Michael Selik
-
Serhiy Storchaka
-
Émanuel Barry