On Tue, 06 Jan 2015 18:01:48 -0800, Andrew Robinson wrote: > but if you can't subclass a built in type -- you can't duck type it -- > for I seem to recall that Python forbids duck typing any built in class > nut not subclasses.
I fear that you have completely misunderstood the nature of duck-typing. The name comes from the phrase "if it walks like a duck and swims like a duck and quacks like a duck, it might as well be a duck". The idea with duck-typing is that you don't care whether an object *actually is* a bool (list, float, dict, etc.) but only whether it offers the same interface as a bool. Not necessarily the entire interface, but just the parts you need: if you need something that quacks, you shouldn't care whether or not it has a swim() method. In the case of bool, literally every object in Python can "quack like a bool", so to speak, unless you deliberately go out of your way to prevent it. Here is an example of duck-typing non-bools in a boolean context: py> values = [0, None, "hello", 23.0, TypeError, {'a': 42}, {}, len] py> for obj in values: ... typename = type(obj).__name__ ... if obj: ... print "%s %r is a truthy object" % (typename, obj) ... else: ... print "%s %r is a falsey object" % (typename, obj) ... int 0 is a falsey object NoneType None is a falsey object str 'hello' is a truthy object float 23.0 is a truthy object type <type 'exceptions.TypeError'> is a truthy object dict {'a': 42} is a truthy object dict {} is a falsey object builtin_function_or_method <built-in function len> is a truthy object You can see I didn't convert obj to a bool, I just used obj in an if- statement as if it were a bool. That's duck-typing. [...] >>> Why this is so important to Guido, I don't know ... but it's making it >>> VERY difficult to add named aliases of False which will still be >>> detected as False and type-checkable as a bool. That part is absolutely wrong. Given these three named aliases of False, I challenge you to find any way to distinguish them from the actual False: NOT_TRUE = False NICHTS = False WRONG = False That's a safe bet, of course, because those three aliases are just names bound to the False object. You can't distinguish the WRONG object from the False object because they are the same object. (You can, however, re-bind the WRONG *name* to a different object: WRONG = "something else" But that is another story.) >>> If my objects don't >>> type check right -- they will likely break some people's legacy >>> code... There's nothing you can do about that. You can't control what stupid things people might choose to do: if str(flag).lower() == 'false': print "flag is false" All you can do is offer to support some set of operations. It's up to your users whether or not they will limit themselves to the operations you promise to support. You can make an object which quacks like a bool (or list, tuple, dict, bool, str...), swims like a bool and walks like a bool, but ultimately Python's introspection powers are too strong for you to fool everybody that it *actually is* a bool. And you know, that's actually a good thing. [...] > In 'C++' I can define a subclass without ever instantiating it; and I > can define static member functions of the subclass that operate even > when there exists not a single instance of the class; and I can typecast > an instance of the base class as being an instance of the subclass. And in Python, we can do all those things too, except that what you call "static member function" we call "class method". But we hardly ever bother, because it's simply not needed or is an unnatural way to do things in Python. But to prove it can be done: from abc import ABCMeta class MyFloat(float): __metaclass__ = ABCMeta @classmethod def __subclasshook__(cls, C): if cls is MyFloat: if C is float: return True return NotImplemented @classmethod def spam(cls, n): return ' '.join(["spam"]*n) MyFloat.register(float) And in use: py> MyFloat.spam(5) 'spam spam spam spam spam' py> isinstance(23.0, MyFloat) True Should you do this? Almost certainly not. > So > -- (against what Guido seems to have considered) I can define a function > anywhere which returns my new subclass object as it's return value > without ever instantiating the subclass -- because my new function can > simply return a typecasting of a base class instance; The user of my > function would never need to know that the subclass itself was never > instantiated... for they would only be allowed to call static member > functions on the subclass anyway, but all the usual methods found in the > superclass(es) would still be available to them. All the benefits of > subclassing still exist, without ever needing to violate the singleton > character of the base class instance. This is all very well and good, but what exactly is the point of it all? What is the *actual problem* this convoluted mess is supposed to solve? An awful lot of programming idioms, including some language features, in Java and C++ exist only to allow the programmer to escape from the straight-jacket of other language features. When programming in Python, we simply don't need to use them, because the problem they solve doesn't come up. Now I don't know for sure that this is one of those cases, but so far it is looking like it: it appears to me that you're trying to solve a problem which occurs in C++ but not in Python, by using C++ idioms in Python. [...] > Yep. Python cuts off re-usability at the ankles... I have NO way to > signal to my users that my object is compatible with bool. In Python terms, the way to check whether something is compatible with a bool is to try it and catch the exception if it fails. Or don't bother catching the exception, and allow some higher piece of code to deal with the problem. py> CouldBeTrue = 0.75 py> if CouldBeTrue: ... print "seems likely to be true" ... seems likely to be true As for the rest of your post, I have run out of time so I'll have to come back to it later. -- Steven -- https://mail.python.org/mailman/listinfo/python-list