
Hello all, Occasionally I build up tuples of types for passing as the second argument to isinstance. I've noticed on occasions having duplicates, for example the following code is Python 2 & 3 compatible but results in a duplicate on one of them: FunctionTypes = ( # python function type(create_autospec), # instance method type(ANY.__eq__), # unbound method type(_ANY.__eq__), ) It would feel cleaner to me if I could make FunctionTypes a set and use that as the second argument to isinstance. :-) Michael -- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On 4 July 2011 08:02, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
I don't care about any iterable. If a set would work then I'd be happy. :-) Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Mon, Jul 4, 2011 at 8:28 AM, Antoine Pitrou <solipsis@pitrou.net> wrote:
A set lookup should be faster than iteration for anything over ~3 types. I support the change even if it doesn't include all iterables. The use case for arbitrary iterables of types to isinstance seems low.

On Mon, Jul 4, 2011 at 10:51 AM, Gregory P. Smith <greg@krypto.org> wrote:
note that a fast lookup implies exact type and not subclass making my point silly... at which point you're back to iterating so I suspect supporting arbitrary iterables is actually how this will be implemented regardless.

On Mon, Jul 4, 2011 at 5:08 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Wasn't the suggestion only for flat iterables, like {int, float, complex}, rather than nested iterables? I'm ambivalent, as long as the implementation is careful to make sure one can still use isinstance on classes like these: class WeirdMetaclass(type): def __iter__(self): yield 1 class MyObject(metaclass=WeirdMetaclass): pass It still feels a little dirty though, to have to pick between options that are not mutually exclusive. Devin

On 4 July 2011 22:46, Devin Jeanpierre <jeanpierreda@gmail.com> wrote:
That's a more reasonable objection for not accepting arbitrary iterables (although iterable types are a little "specialised"). Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Mon, Jul 4, 2011 at 5:50 PM, Michael Foord <fuzzyman@gmail.com> wrote: ..
I don't see a problem here. If classinfo is a type, isinstance should not attempt to iterate over it. If one really wants to check for membership in the list that MyObject yields, it is always possible to do it explicitly: isinstance(x, list(MyObject)).

On 4 July 2011 22:08, Antoine Pitrou <solipsis@pitrou.net> wrote:
Why? Iteration doesn't imply recursing into contained iterators. Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Mon, Jul 4, 2011 at 2:55 PM, Amaury Forgeot d'Arc <amauryfa@gmail.com> wrote:
That doesn't mean it has to necessarily accept other nested containers; tuples can be left as a special case for backward compatibility. Why does it accept nested tuples in the first place for that matter? Cheers, Chris

On Mon, Jul 4, 2011 at 6:18 PM, Chris Rebert <pyideas@rebertia.com> wrote:
Why does it accept nested tuples in the first place for that matter?
Whoops, that was news to me too. Apparently it's so that if you have code that does isinstance(foo, bar) you can do isinstance(foo, (bar, baz)) no matter what bar is. It's the only way to do this generically given that isinstance must accept both types and collections of types. Devin

2011/7/5 Chris Rebert <pyideas@rebertia.com>:
All this has already been discussed: http://mail.python.org/pipermail/python-list/2009-January/1188226.html -- Amaury Forgeot d'Arc

Chris Rebert wrote:
Why does it accept nested tuples in the first place for that matter?
Probably so that tuples could be used to emulate a "set of types" before we had real sets. Now that we do have real sets, it doesn't seem necessary to continue with this and allow sets of sets, etc. So +1 on leaving tuple as a special case for this and treating all other iterables as flat. -- Greg

On Jul 4, 2011, at 6:26 PM, Greg Ewing wrote:
-1 on further garbaging this API by introducing yet another signature variant -- even worse, a signature variant with a special case for the tuple type (didn't we learn our lesson with old-style string formatting). I have to agree with Benjamin that this proposal would be utterly unnecessary software bloat. Raymond

Raymond Hettinger, 05.07.2011 03:55:
FWIW, another -1 from me. The current API is simple: you pass in either a type or a tuple of types. Distinguishing the two cases is easy and safe, and even the somewhat bloatish case of passing in a tuple of tuples of types is safe, although somewhat complicated already. This proposal will complicate the implementation for no obvious reason, and will introduce slightly weird corner cases, like the handling of iterable type objects. After all, testing for a type multiple times, just because it ended up in the type tuple multiple times, will still work correctly. And even if repeated testing is not desired for some reason, using tuple(set(x)) instead of set(x) won't make that a big difference. Stefan

On 2011-07-05, at 10:14 , Stefan Behnel wrote:
Yes, that's more or less what I wrote in the next sentence, right the first one that you discarded. ;)
Not quite. Your next sentence talks about tuples of tuples, but the nesting is entirely arbitrary. Talking about tuples of tuples is way simplifying what's truly accepted by `isinstance`.

Gregory P. Smith wrote:
A set lookup should be faster than iteration for anything over ~3 types.
But you can't use a set lookup. You have to do a subclass test against all the members of the set, so the fact that it's a set rather than some other iterable doesn't help you. -- Greg

On 4 July 2011 16:28, Antoine Pitrou <solipsis@pitrou.net> wrote:
I have no *objection* to it working for arbitrary iterables, I just don't care about it. So does this mean no-one has any objections to my suggested change? I'll create an issue. Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On 4 July 2011 21:26, Benjamin Peterson <benjamin@python.org> wrote:
What is x in that case? Do you mean in the isinstance call? That adds the runtime overhead of an extra tuple call every time - plus the mental overhead of reading it every time someone looks at the code. Small maybe, but it seems like you're suggesting adding bloat... Seriously though. Conceptually the second argument to isinstance is a set of types you want to check the object against. It would be nice if that set of types were permitted to actually be a set. Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Tue, Jul 5, 2011 at 6:36 PM, Guido van Rossum <guido@python.org> wrote:
FWIW, the restriction to tuples is to avoid burdening the recursive C code with checks for cycles. Please keep that property.
Keeping this property does not seem that hard: preserve the current behavior when classinfo is a type or a tuple and return any(_isinstance(object, type) for type in classinfo) for any other type of classinfo. (In the last expression, "_isinstance" accepts only types for the second argument.) It looks like in this discussion a useful feature is held hostage to an exotic corner case. I understand that it may sometimes be useful to write isinstance(x, (MyString, StringTypes)), but isinstance(x, (MyString,)+StringTypes) is just as readable. Furthermore, with str/unicode unification and addition of ABCs in py3k, I would expect nested classinfo to become even less useful. Note that the current error message from isinstance() does not mention a possibility of nested tuples:
Since no one has ever complained about this, I conclude that people rightfully consider nested tuple classinfo to be too exotic to mention in an error message. I don't see any problem with restricting recursive behavior to tuples. It is often recommended that lists be used for homogeneous collections and tuples for mixed-type collections. This rule will naturally lead users to choose tuples when they need a nested collection. On the other hand, some users may find isinstance(x, [int, float]) or isinstance(x, {int, float}) more readable than isinstance(x, (int, float)) either simply because [] or {} stand out better in the argument list or because they are used to seeing homogeneous collections displayed as lists.

Michael Foord <fuzzyman@...> writes:
It would feel cleaner to me if I could make FunctionTypes a set and use that as the second argument to isinstance.
I just had a another thought about abritrary collections. It was explode loudly if you made an class.

On 6 July 2011 17:55, Benjamin Peterson <benjamin@python.org> wrote:
Could you rephrase please? I have no idea what this means. :-) All the best, Michael Foord
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

Michael Foord <fuzzyman@...> writes:
best,Michael Foord Mm. I don't blame you. I'll speak code: class Evil(type): def __iter__(self): return range(42) class Accomplice(metaclass=Evil): pass isinstance(12, Accomplice()) # boom if arbitrary iterables are allowed

On Wed, Jul 6, 2011 at 7:35 PM, Benjamin Peterson <benjamin@python.org> wrote: ..
What is "boom"? If "boom" is a TypeError - it is to be expected. For example, with def better_isinstance(object, classinfo): if isinstance(classinfo, (type, tuple)): return isinstance(object, classinfo) else: return any(isinstance(object, cls) for cls in classinfo) I get:
better_isinstance(12, Accomplice) False
and

On 7 July 2011 01:02, Alexander Belopolsky <alexander.belopolsky@gmail.com>wrote:
I think the instantiation of Accompalice there is a typo. The point is that as Accompalice (the type) is an instance of Evil and is therefore an iterable type. So if isintance naively iterated over *anything iterable* it would attempt to iterate over Accomplice.
You avoid this problem by checking explicitly for type. Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Wed, Jul 6, 2011 at 7:35 PM, Benjamin Peterson <benjamin@python.org> wrote:
class Accomplice(metaclass=Evil): pass
... leading to isinstance(x, 42) rather than isinstance(x, Evil) if the iterable check is done too soon. So, at a minimum, this class should be in the test suite to guard against future ill-fated optimizations. -jJ

On Thu, 7 Jul 2011 13:22:33 -0400 Jim Jewett <jimjjewett@gmail.com> wrote:
In what way is that a problem? That you can trigger exceptions by writing malicious code doesn't sound like a particularly novel event ;) Regards Antoine.

On 7 July 2011 20:12, Antoine Pitrou <solipsis@pitrou.net> wrote:
I've used indexable types before. I've never created an iterable one, but it isn't unthinkable. :-) Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Thu, 2011-07-07 at 23:12 +0100, Michael Foord wrote:
I've created one, once. It was a metaclass for defining enumerations like this: class COLOURS(Enum): RED = 1 BLUE = 2 GREEN = 3 If you wanted to iterate over all the members of the enum, you could do: for colour in COLOURS: blah(colour) Of course, in this case it would be totally useless to pass COLOURS into isintance(). But I don't see what doing so should be capable of breaking things. Ryan -- Ryan Kelly http://www.rfk.id.au | This message is digitally signed. Please visit ryan@rfk.id.au | http://www.rfk.id.au/ramblings/gpg/ for details

Any of the changes I see would make isinstance work. This basic sort of API -- take a thing or a tuple-of-things (or often a list-of-things or precariously an iterable-of-things) is a poor, inflexible one I avoid in application code as I think do most Python programmers when they can. The builtins and stdlib have this scattered about, but for the most part it makes the relevant APIs less clear and simple. I wonder if it isn't time to rethink isinstance at a more basic level. The API SomeClass.isinstance(some_potential_instance) makes more sense to me than isinstance(some_potential_instance, SomeClass), since it is really an issue to do with the class. Indeed, recent Pythons are implemented this way. It seems attractive with metaclasses to be able to duck type this operation where your own metaclass which does not inherit type can look just like an instance of type. If you wanted to use an iterable of classes, you could use any(t.isinstance(o) for t in types) or we could introduce a utility ABC factory ComposeTypes such that we could do ComposeTypes(types).isinstance(o). I do hesitate to think this change is good for a few reasons. It introduces change and compatibility issues by introducing a new method for all classes and deprecating a builtin. Additionally, it could seem to encourage typechecking by improving it. Mike

Michael Foord wrote:
But if it checks whether something is a type first, it won't get as far as trying to iterate over it. This example illustrates that it's possible to create an object that is ambiguous with respect to the proposed API. But it's a case that is unlikely to arise in practice, so I think resolving it using the rule that type-ness takes precedence over iterable-ness is a reasonable solution. -- Greg

On 4 July 2011 08:02, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
I don't care about any iterable. If a set would work then I'd be happy. :-) Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Mon, Jul 4, 2011 at 8:28 AM, Antoine Pitrou <solipsis@pitrou.net> wrote:
A set lookup should be faster than iteration for anything over ~3 types. I support the change even if it doesn't include all iterables. The use case for arbitrary iterables of types to isinstance seems low.

On Mon, Jul 4, 2011 at 10:51 AM, Gregory P. Smith <greg@krypto.org> wrote:
note that a fast lookup implies exact type and not subclass making my point silly... at which point you're back to iterating so I suspect supporting arbitrary iterables is actually how this will be implemented regardless.

On Mon, Jul 4, 2011 at 5:08 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
Wasn't the suggestion only for flat iterables, like {int, float, complex}, rather than nested iterables? I'm ambivalent, as long as the implementation is careful to make sure one can still use isinstance on classes like these: class WeirdMetaclass(type): def __iter__(self): yield 1 class MyObject(metaclass=WeirdMetaclass): pass It still feels a little dirty though, to have to pick between options that are not mutually exclusive. Devin

On 4 July 2011 22:46, Devin Jeanpierre <jeanpierreda@gmail.com> wrote:
That's a more reasonable objection for not accepting arbitrary iterables (although iterable types are a little "specialised"). Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Mon, Jul 4, 2011 at 5:50 PM, Michael Foord <fuzzyman@gmail.com> wrote: ..
I don't see a problem here. If classinfo is a type, isinstance should not attempt to iterate over it. If one really wants to check for membership in the list that MyObject yields, it is always possible to do it explicitly: isinstance(x, list(MyObject)).

On 4 July 2011 22:08, Antoine Pitrou <solipsis@pitrou.net> wrote:
Why? Iteration doesn't imply recursing into contained iterators. Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Mon, Jul 4, 2011 at 2:55 PM, Amaury Forgeot d'Arc <amauryfa@gmail.com> wrote:
That doesn't mean it has to necessarily accept other nested containers; tuples can be left as a special case for backward compatibility. Why does it accept nested tuples in the first place for that matter? Cheers, Chris

On Mon, Jul 4, 2011 at 6:18 PM, Chris Rebert <pyideas@rebertia.com> wrote:
Why does it accept nested tuples in the first place for that matter?
Whoops, that was news to me too. Apparently it's so that if you have code that does isinstance(foo, bar) you can do isinstance(foo, (bar, baz)) no matter what bar is. It's the only way to do this generically given that isinstance must accept both types and collections of types. Devin

2011/7/5 Chris Rebert <pyideas@rebertia.com>:
All this has already been discussed: http://mail.python.org/pipermail/python-list/2009-January/1188226.html -- Amaury Forgeot d'Arc

Chris Rebert wrote:
Why does it accept nested tuples in the first place for that matter?
Probably so that tuples could be used to emulate a "set of types" before we had real sets. Now that we do have real sets, it doesn't seem necessary to continue with this and allow sets of sets, etc. So +1 on leaving tuple as a special case for this and treating all other iterables as flat. -- Greg

On Jul 4, 2011, at 6:26 PM, Greg Ewing wrote:
-1 on further garbaging this API by introducing yet another signature variant -- even worse, a signature variant with a special case for the tuple type (didn't we learn our lesson with old-style string formatting). I have to agree with Benjamin that this proposal would be utterly unnecessary software bloat. Raymond

Raymond Hettinger, 05.07.2011 03:55:
FWIW, another -1 from me. The current API is simple: you pass in either a type or a tuple of types. Distinguishing the two cases is easy and safe, and even the somewhat bloatish case of passing in a tuple of tuples of types is safe, although somewhat complicated already. This proposal will complicate the implementation for no obvious reason, and will introduce slightly weird corner cases, like the handling of iterable type objects. After all, testing for a type multiple times, just because it ended up in the type tuple multiple times, will still work correctly. And even if repeated testing is not desired for some reason, using tuple(set(x)) instead of set(x) won't make that a big difference. Stefan

On 2011-07-05, at 10:14 , Stefan Behnel wrote:
Yes, that's more or less what I wrote in the next sentence, right the first one that you discarded. ;)
Not quite. Your next sentence talks about tuples of tuples, but the nesting is entirely arbitrary. Talking about tuples of tuples is way simplifying what's truly accepted by `isinstance`.

Gregory P. Smith wrote:
A set lookup should be faster than iteration for anything over ~3 types.
But you can't use a set lookup. You have to do a subclass test against all the members of the set, so the fact that it's a set rather than some other iterable doesn't help you. -- Greg

On 4 July 2011 16:28, Antoine Pitrou <solipsis@pitrou.net> wrote:
I have no *objection* to it working for arbitrary iterables, I just don't care about it. So does this mean no-one has any objections to my suggested change? I'll create an issue. Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On 4 July 2011 21:26, Benjamin Peterson <benjamin@python.org> wrote:
What is x in that case? Do you mean in the isinstance call? That adds the runtime overhead of an extra tuple call every time - plus the mental overhead of reading it every time someone looks at the code. Small maybe, but it seems like you're suggesting adding bloat... Seriously though. Conceptually the second argument to isinstance is a set of types you want to check the object against. It would be nice if that set of types were permitted to actually be a set. Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

FWIW, the restriction to tuples is to avoid burdening the recursive C code with checks for cycles. Please keep that property. On Jul 3, 2011 3:47 PM, "Michael Foord" <fuzzyman@gmail.com> wrote: the that

On Tue, Jul 5, 2011 at 6:36 PM, Guido van Rossum <guido@python.org> wrote:
FWIW, the restriction to tuples is to avoid burdening the recursive C code with checks for cycles. Please keep that property.
Keeping this property does not seem that hard: preserve the current behavior when classinfo is a type or a tuple and return any(_isinstance(object, type) for type in classinfo) for any other type of classinfo. (In the last expression, "_isinstance" accepts only types for the second argument.) It looks like in this discussion a useful feature is held hostage to an exotic corner case. I understand that it may sometimes be useful to write isinstance(x, (MyString, StringTypes)), but isinstance(x, (MyString,)+StringTypes) is just as readable. Furthermore, with str/unicode unification and addition of ABCs in py3k, I would expect nested classinfo to become even less useful. Note that the current error message from isinstance() does not mention a possibility of nested tuples:
Since no one has ever complained about this, I conclude that people rightfully consider nested tuple classinfo to be too exotic to mention in an error message. I don't see any problem with restricting recursive behavior to tuples. It is often recommended that lists be used for homogeneous collections and tuples for mixed-type collections. This rule will naturally lead users to choose tuples when they need a nested collection. On the other hand, some users may find isinstance(x, [int, float]) or isinstance(x, {int, float}) more readable than isinstance(x, (int, float)) either simply because [] or {} stand out better in the argument list or because they are used to seeing homogeneous collections displayed as lists.

Michael Foord <fuzzyman@...> writes:
It would feel cleaner to me if I could make FunctionTypes a set and use that as the second argument to isinstance.
I just had a another thought about abritrary collections. It was explode loudly if you made an class.

On 6 July 2011 17:55, Benjamin Peterson <benjamin@python.org> wrote:
Could you rephrase please? I have no idea what this means. :-) All the best, Michael Foord
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

Michael Foord <fuzzyman@...> writes:
best,Michael Foord Mm. I don't blame you. I'll speak code: class Evil(type): def __iter__(self): return range(42) class Accomplice(metaclass=Evil): pass isinstance(12, Accomplice()) # boom if arbitrary iterables are allowed

On Wed, Jul 6, 2011 at 7:35 PM, Benjamin Peterson <benjamin@python.org> wrote: ..
What is "boom"? If "boom" is a TypeError - it is to be expected. For example, with def better_isinstance(object, classinfo): if isinstance(classinfo, (type, tuple)): return isinstance(object, classinfo) else: return any(isinstance(object, cls) for cls in classinfo) I get:
better_isinstance(12, Accomplice) False
and

On 7 July 2011 01:02, Alexander Belopolsky <alexander.belopolsky@gmail.com>wrote:
I think the instantiation of Accompalice there is a typo. The point is that as Accompalice (the type) is an instance of Evil and is therefore an iterable type. So if isintance naively iterated over *anything iterable* it would attempt to iterate over Accomplice.
You avoid this problem by checking explicitly for type. Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Wed, Jul 6, 2011 at 7:35 PM, Benjamin Peterson <benjamin@python.org> wrote:
class Accomplice(metaclass=Evil): pass
... leading to isinstance(x, 42) rather than isinstance(x, Evil) if the iterable check is done too soon. So, at a minimum, this class should be in the test suite to guard against future ill-fated optimizations. -jJ

On Thu, 7 Jul 2011 13:22:33 -0400 Jim Jewett <jimjjewett@gmail.com> wrote:
In what way is that a problem? That you can trigger exceptions by writing malicious code doesn't sound like a particularly novel event ;) Regards Antoine.

On 7 July 2011 20:12, Antoine Pitrou <solipsis@pitrou.net> wrote:
I've used indexable types before. I've never created an iterable one, but it isn't unthinkable. :-) Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Thu, 2011-07-07 at 23:12 +0100, Michael Foord wrote:
I've created one, once. It was a metaclass for defining enumerations like this: class COLOURS(Enum): RED = 1 BLUE = 2 GREEN = 3 If you wanted to iterate over all the members of the enum, you could do: for colour in COLOURS: blah(colour) Of course, in this case it would be totally useless to pass COLOURS into isintance(). But I don't see what doing so should be capable of breaking things. Ryan -- Ryan Kelly http://www.rfk.id.au | This message is digitally signed. Please visit ryan@rfk.id.au | http://www.rfk.id.au/ramblings/gpg/ for details

Any of the changes I see would make isinstance work. This basic sort of API -- take a thing or a tuple-of-things (or often a list-of-things or precariously an iterable-of-things) is a poor, inflexible one I avoid in application code as I think do most Python programmers when they can. The builtins and stdlib have this scattered about, but for the most part it makes the relevant APIs less clear and simple. I wonder if it isn't time to rethink isinstance at a more basic level. The API SomeClass.isinstance(some_potential_instance) makes more sense to me than isinstance(some_potential_instance, SomeClass), since it is really an issue to do with the class. Indeed, recent Pythons are implemented this way. It seems attractive with metaclasses to be able to duck type this operation where your own metaclass which does not inherit type can look just like an instance of type. If you wanted to use an iterable of classes, you could use any(t.isinstance(o) for t in types) or we could introduce a utility ABC factory ComposeTypes such that we could do ComposeTypes(types).isinstance(o). I do hesitate to think this change is good for a few reasons. It introduces change and compatibility issues by introducing a new method for all classes and deprecating a builtin. Additionally, it could seem to encourage typechecking by improving it. Mike

Michael Foord wrote:
But if it checks whether something is a type first, it won't get as far as trying to iterate over it. This example illustrates that it's possible to create an object that is ambiguous with respect to the proposed API. But it's a case that is unlikely to arise in practice, so I think resolving it using the rule that type-ness takes precedence over iterable-ness is a reasonable solution. -- Greg
participants (20)
-
Alexander Belopolsky
-
Amaury Forgeot d'Arc
-
Antoine Pitrou
-
Benjamin Peterson
-
Chris Rebert
-
Devin Jeanpierre
-
Georg Brandl
-
Greg Ewing
-
Gregory P. Smith
-
Guido van Rossum
-
Jim Jewett
-
Masklinn
-
Michael Foord
-
Mike Graham
-
MRAB
-
Raymond Hettinger
-
Robert Collins
-
Ryan Kelly
-
Stefan Behnel
-
Steven D'Aprano