[Python-Dev] defaultdict proposal round three

Alex Martelli aleaxit at gmail.com
Tue Feb 21 01:55:34 CET 2006


On Feb 20, 2006, at 3:04 PM, Brett Cannon wrote:
 ...
>> - "Yes and it should be the only constructor argument." This is my
 ...
> While #3 is my preferred solution as well, it does pose a Liskov
> violation if this is a direct dict subclass instead of storing a dict

How so? Liskov's principle is (in her own words):
If for each object o1 of type S there is an object o2 of type T such 
that for all programs P defined in terms of T, the behavior of P is 
unchanged when o1 is substituted for o2 then S is a subtype of T.
How can this ever be broken by the mere presence of incompatible 
signatures for T's and S's ctors?
I believe the principle, as stated above, was imperfectly stated, btw 
(it WAS preceded by "something like the following substitution 
property", indicating that Liskov was groping towards a good 
formulation), but that's an aside -- the point is that the principle 
is about substitution of _objects_, i.e., _instances_ of the types S 
and T, not about substitution of the _types_ themselves for each 
other. Instances exist and are supposed to satisfy their invariants 
_after_ ctors are done executing; ctor's signatures don't matter.
In Python, of course, you _could_ call type(o2)(...) and possibly get 
different behavior if that was changed into type(o1)(...) -- the 
curse of powerful introspection;-). But then, isn't it trivial to 
obtain cases in which the behavior is NOT unchanged? If it was 
always unchanged, what would be the point of ever subclassing?-) Say 
that o2 is an int and o1 is a bool -- just a "print o2" already 
breaks the principle as stated (it's harder to get a simpler P than 
this...).
Unless you have explicitly documented invariants (such as "any 'print 
o' must emit 1+ digits followed by a newline" for integers), you 
cannot say that some alleged subclass is breaking Liskov's property, 
in general. Mere "change of behavior" in the most general case cannot 
qualify, if method overriding is to be any use; such change IS 
traditionally allowed as long as preconditions are looser and 
postconditions are stricter; and I believe than in any real-world 
subclassing, with sufficient introspection you'll always find a 
violation E.g., a subtype IS allowed to add methods, by Liskov's 
specific example; but then, len(dir(o1)) cannot fail to be a higher 
number than len(dir(o2)), from which you can easily construct a P 
which "changes behavior" for any definition you care to choose. 
E.g., pick constant N as the len(dir(...)) for instances of type T, 
and say that M>N is the len(dir(...)) for instances of S. Well, 
then, math.sqrt(N-len(dir(o2))) is well defined -- but change o2 into 
o1, and since N-M is <0, you'll get an exception.
If you can give an introspection-free example showing how Liskov 
substitution would be broken by a mere change to incompatible 
signature in the ctor, I'll be grateful; but I don't think it can be 
done.
Alex


More information about the Python-Dev mailing list

AltStyle によって変換されたページ (->オリジナル) /