Python supports LSP, does it?

M

Mike Meyer

Andy Leszczynski said:
wikipedia
(http://en.wikipedia.org/wiki/Python_programming_language#Object-oriented_programming)
says:
"""
Python's support for object oriented programming paradigm is vast. It
supports polymorphism [...] fully in the Liskov substitution
principle-sense for all objects.
"""

Just wondering if it is true statement. Is not LSP more a quality of
the desing of class hierachy rather then language itslef? Comments?

It's not a true statement. Nothing in the language enforces LSP. In
fact, there's not even a when a function/method is invoked to make
sure the type passed in is a subtype of the type you expect; there's
currently no way to even declare what that type is.

What it does have is duck typing. You can pass any object to any
function/method, and it will work so long as it has the right set of
features and attributes.

The wikipedia was really abusing the phrase LSP. I've corrected the
wikipedia.

<mike
 
J

Jules Dubois

wikipedia
(http://en.wikipedia.org/wiki/Python_programming_language#Object-oriented_programming)
says:
"""
Python's support for object oriented programming paradigm is vast. It
supports polymorphism [...] fully in the Liskov substitution
principle-sense for all objects.
"""

Just wondering if it is true statement.

It's true if not particularly insightful.

"What is wanted here is something like the following substitution
property [6]: 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."
Is not LSP more a quality of the desing of class hierachy rather then
language itslef?

In a statically-typed language, polymorphism is based on the class hierarchy
(through inheritance). Because Python uses dynamically-checked typing, its
polymorphism is structural rather than nominative.
Comments?

Discussions like these might be more appropriate for the comp.object
newsgroup.
 
R

Roy Smith

Andy Leszczynski said:
Is not LSP more a quality of the desing of class hierachy rather then
language itslef? Comments?

I do agree that LSP is more a class hierarchy thing than a language thing.
For example, it's easy in Python to write a LSP-violating set of classes:

class base:
def f(self):
print "I am base"

class child (base):
f = "not a function"

Since you can call base.f(), LSP says you should also be able to call
child.f(). Well, I suppose you can, but most people would not consider
throwing a TypeError to satisfy the LSP :).

Mike Meyer said:
It's not a true statement. Nothing in the language enforces LSP. In
fact, there's not even a [way?] when a function/method is invoked to make
sure the type passed in is a subtype of the type you expect

Well, that's not entirely true. I could write:

def func (self, obj):
assert (isinstance (obj, baseClass))

It's sort of un-pythonic, but the language certainly lets you do it if you
really want to.
 
B

bruno modulix

Roy said:
Andy Leszczynski <leszczynscyATnospam.yahoo.com.nospam> writes:
(snip)
It's not a true statement. Nothing in the language enforces LSP. In
fact, there's not even a [way?] when a function/method is invoked to make
sure the type passed in is a subtype of the type you expect


Well, that's not entirely true. I could write:

def func (self, obj):
assert (isinstance (obj, baseClass))

It's sort of un-pythonic, but the language certainly lets you do it if you
really want to.

It doesn't inforce LSP anyway.

class baseClass(object):
def f(self):
print "in %s f" % self
return 42

class derivedClass(baseClass):
f = "gotcha"

class somethingElse(object)
def f(self):
return 42

def func1(obj):
assert isinstance (obj, baseClass)
obj.f()

def func2(obj):
assert(callable(getAttr(obj, f))
obj.f()

b = baseClass()
d = derivedClass()
s = somethingElse()

func1(b) # ok
func1(d) # TypeError
func1(s) # AssertionError

func2(b) # ok
func2(d) # AssertionError
func2(s) # ok

Clearly, somethingElse is a subtype of baseClass, when derivedClass is
not. Don't confuse suclassing with subtyping. issinstance() let you
check for subclassing, not for subtyping. The only language-level
mechanism I know of that more or less inforce LSP is Eiffel's contracts.
 
A

Andy Leszczynski

Mike Meyer wrote:
[...]
The wikipedia was really abusing the phrase LSP. I've corrected the
wikipedia.
<mike

thx for changing. The credit for pointing it out blongs to me friend
from work.

Cheers, A.
 
P

phil hunt

wikipedia
(http://en.wikipedia.org/wiki/Python_programming_language#Object-oriented_programming)
says:
"""
Python's support for object oriented programming paradigm is vast. It
supports polymorphism [...] fully in the Liskov substitution
principle-sense for all objects.
"""

Just wondering if it is true statement. Is not LSP more a quality of the
desing of class hierachy rather then language itslef? Comments?

According to Wikipedia, the Liskov substitution principle is:

Let q(x) be a property provable about objects x of type T. Then
q(y) should be true for objects y of type S where S is a subtype of T

To me, this is nonsense. Under this definition any subtype must
behave the same as its parent type, becausde if it doesn't there
will be some q(y) that are different to q(x).

But if it behaves the same, what's the point of having a subtype?

Am I missing something?
 
M

Mike Meyer

bruno modulix said:
Clearly, somethingElse is a subtype of baseClass, when derivedClass is
not. Don't confuse suclassing with subtyping. issinstance() let you
check for subclassing, not for subtyping. The only language-level
mechanism I know of that more or less inforce LSP is Eiffel's contracts.

Eiffel's DbC has been picked up by other languages. D and SPARK come
to mind.

In a broader sense, a couple of Python frameworks support interfaces,
which basically guarantee subtyping at the same level as Liskov's CLU
language does.

<mike
 
G

Gregory Bond

phil said:
To me, this is nonsense. Under this definition any subtype must
behave the same as its parent type, becausde if it doesn't there
will be some q(y) that are different to q(x).

Not necessarily..... the set of operations on y could be a superset of
the set of operations on x. So you could have q(y) == q(x) (for all q
applicable to x) but there could be w(y) that has no w(x). In C++
terms, this implies no virtual functions.

Which is not to say that I'm disagreeing with your basic point:
insisting on q(y) == q(x) for all q will greatly limit your use of
polymorphism, unless you are 'sensible' (or perhaps what a mathematician
would call 'loose') about how you define your "q"s!
 
G

Guest

According to Wikipedia, the Liskov substitution principle is:

Let q(x) be a property provable about objects x of type T. Then
q(y) should be true for objects y of type S where S is a subtype of T

To me, this is nonsense. Under this definition any subtype must
behave the same as its parent type, becausde if it doesn't there
will be some q(y) that are different to q(x).

But if it behaves the same, what's the point of having a subtype?

It does not behave the same, it has the same properties.

In other words, if there is some true assertion about _any_ object of type
x, then it's true about any object of type y, if y is derived from x.

Quick-and-dirty example: any object of type "list" is iterable, and it is true
as well for any object of some type derived from list.
 
T

Terry Reedy

It does not behave the same, it has the same properties.

In other words, if there is some true assertion about _any_ object of
type
x, then it's true about any object of type y, if y is derived from x.

Quick-and-dirty example: any object of type "list" is iterable, and it is
true
as well for any object of some type derived from list.

I remember discussion of the LSP on comp.object some years ago when I was
reading it. (I presume there still are, just don't read it anymore.). One
of the problems is that biology and evolution do not obey it. Birds (in
general) can fly, but those in the ratite family, evolved later than order
aves, cannot. Nor can some birds in zoos after their wings have been
(un)fixed. In a quite literal sense, the 'fly' method got disabled.

The list goes on. In some cave-dwelling taxa, the 'see' method gets
genetically disabled. Bones breaks. Artifacts also get disabled by
accident or intention. So LSP conflicts with both scientific and everyday
classification.

Python lets one choose which hierarchy principle to adhere to.

Terry J. Reedy
 
K

Kay Schluehr

It does not behave the same, it has the same properties.

Doesn't it?

"What is wanted here is something like the following substitution
property: 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."

Barbara Liskov, "Data Abstraction and Hierarchy" SIGPLAN Notices,
23,5 (May, 1988).

IOW if an arbitrary program P works with objects of type T and you
replace each object of type T by an object of type S and each P works
still the same way one can imply that S is a subtype of T.

It is a funny aspect of this definition that it doesn't work for
reflective programming languages. If you have access to properties AS
properties ( on the meta-level ) it is easy to break LSP. Preserving
LSP becomes a challenge or a requirement.

Example:

The statement

if type(obj) == T:
...

breaks LSP. One might say that that T has no subtypes at all. But since
T is arbitrary chosen no type in Python has a subtype in a strict
sense.

On the other hand this statement preserves LSP:

if isinstance(obj,T):
...

Therefore one can write programs that work as if LSP was valid and
subtypes indeed exist.

Kay
 
M

Mike Meyer

Gregory Bond said:
Not necessarily..... the set of operations on y could be a superset of
the set of operations on x. So you could have q(y) == q(x) (for all q
applicable to x) but there could be w(y) that has no w(x). In C++
terms, this implies no virtual functions.

No, it doesn't imply no virtual functions. It just restrains their
behavior severely. You do have to agree that you can't prove things
about code that raises exceptions, though. To deal with that in q(x),
you provide a domain for x over which q(x) doesn't raise exceptions.

You can then implement a subclass that overrides methods involved in
q(x), so long as they behave the same for all x. However, for some y
not in x, q(y) may now be a provable property rather than an
exception.

For instance, a class that has a method that takes the square root of
an argument could have properties that can only be proven for
non-complex values of that argument. A subclass could extend the
method to deal with complex values for that argument without violating
the LSP.
Which is not to say that I'm disagreeing with your basic point:
insisting on q(y) == q(x) for all q will greatly limit your use of
polymorphism, unless you are 'sensible' (or perhaps what a
mathematician would call 'loose') about how you define your "q"s!

Well, insisting that all existing program remain correct in the face
of introducing new types will greatly limit your use of
polymorphism. The LSP is more strict than that.

<mike
 
G

Guest

I remember discussion of the LSP on comp.object some years ago when I
was reading it. (I presume there still are, just don't read it
anymore.). One of the problems is that biology and evolution do not
obey it. Birds (in general) can fly,

I suspect it is not the exact scientific criteria used in the biology whether an
animal ISA bird, is it? I mean, flying is not bird property in the biological sense,
so it is nothing against the LSP here.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top