an oop question

Alan Gauld learn2program at gmail.com
Mon Oct 31 05:36:59 EDT 2022


On 30/10/2022 14:01, Julieta Shem wrote:

> I wrote the classes
> 
>   class Empty:
>     ...
>   class Pair:
>     ...
> 
> (*) How to build a stack?
> 
> These Lisp-like sequences are clearly a stack.  

That is a very important observation. A Pair IS-A Stack(sort of).
If you had a stack you could create a Pair from it certainly.

> So far so good, but when it comes to building a better user interface
> for it I have no idea how to do it.  I think one of the purposes of OOP
> is to organize code hierarchically so that we can reuse what we wrote.

One of the purposes of classes certainly. I'm not so sure it's a purpose
of OOP. They are not the same thing. A class is a programming construct
OOP is a programming style. Classes facilitate OOP but can be used
outside of OOP too.

> So I tried to make a Stack by inheriting Pair.

But you said above that a Pair was a Stack. Inheritance implies an
IS-A relationship, so Stack inheriting Pair would mean that a Stack
was a Pair. That is not really true.

A Stack could use a Pair (or many of them) but it is not a Pair.

Trying to use inheritance inappropriately is one of the
biggest (and commonest) mistakes in OOP. It invariably leads
to complications. If in doubt use delegation instead.


> class Stack(Pair):
>     pass
> 
>>>> Stack(1, Empty())
> Stack(1, Empty())
> 
> Then I wrote pop and push.
> 
>>>> Stack(1, Empty()).pop()
> 1
> 
>>>> Stack(1, Empty()).push(2)
> Stack(2, Stack(1, Empty()))
> 
> So far so good.  Now let me show you what I can't do.
> 
> (*) The difficulty of encapsulating a union
> 
> The Lisp-like sequences we're building here are union-like data
> structures.  A /sequence/ is either Empty() or Pair(..., /sequence/).  I
> have not found a way to represent this either-or datastructure with a
> class.  For example, there is no way right now to build an empty Stack
> by invoking the Stack constructor.
> 
>>>> Stack()
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> TypeError: Pair.__init__() missing 2 required positional arguments: 'first' and 'rest'
> 

The usual Python approach to such things is to put some default
values(often None but could be an Empty instance in your case)
in the init() method parameter list. Then test if the inputs
are None and if so take the appropriate action.

> class Pair:
>   def __init__(self, first=Empty(), rest=Empty()):

Like this.

>     if not isinstance(rest, Pair) and not isinstance(rest, Empty):
>       raise ValueError("rest must be Empty or Pair")
>     self.first = first
>     self.rest = rest
>   def fromIterable(it):
>     if len(it) == 0:
>       return Empty()
>     else:
>       return Pair(it[0], Pair.fromIterable(it[1:]))
>   def __str__(self):
>     return "{}({!r}, {})".format(self.__class__.__name__, self.first, str(self.rest))
>   def __repr__(self):
>     return str(self)
>   def __len__(self):
>     return 1 + self.rest.__len__()
> 
> class Empty:
>   def __len__(self):
>     return 0
>   def __str__(self):
>     return  "Empty()"
>   def __repr__(self):
>     return self.__str__()
>   def __new__(clss):
>     if not hasattr(clss, "saved"):
>       clss.saved = super().__new__(clss)
>     return clss.saved
> 
> class Stack(Pair):
>   def pop(self):
>     return self.first
>   def push(self, x):
>     return Stack(x, self)

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos




More information about the Python-list mailing list