on implementing a toy oop-system

Meredith Montgomery mmontgomery at levado.to
Wed Sep 28 14:25:50 EDT 2022


Meredith Montgomery <mmontgomery at levado.to> writes:

> ram at zedat.fu-berlin.de (Stefan Ram) writes:
>
>> Meredith Montgomery <mmontgomery at levado.to> writes:
>>>Is that at all possible somehow?  Alternatively, how would you do your
>>>toy oop-system?
>>
>>   Maybe something along those lines:
>>
>> from functools import partial
>>
>> def counter_create( object ):
>>     object[ "n" ]= 0
>> def counter_increment( object ):
>>     object[ "n" ]+= 1
>> def counter_value( object ):
>>     return object[ "n" ]
>>
>> counter_class =( counter_create, counter_increment, counter_value )
>>
>> def inherit_from( class_, target ):
>>     class_[ 0 ]( target )
>>     for method in class_[ 1: ]:
>>         target[ method.__name__ ]= partial( method, target )
>>
>> car = dict()
>>
>> inherit_from( counter_class, car )
>>
>> print( car[ "counter_value" ]() )
>> car[ "counter_increment" ]()
>> print( car[ "counter_value" ]() )
>>
>>   . The "create" part is simplified. I just wanted to show how
>>   to make methods like "counter_increment" act on the object
>>   that inherited them using "partial".
>
> I really liked this idea.  I organized it my way.  Have a look.  (Thank
> you for the lecture!)

But it lacks consistency.

> from functools import partial
>
> def Counter(name = None):
>   o = {"name": name if name else "untitled", "n": 0}
>   def inc(o):
>     o["n"] += 1
>     return o
>   o["inc"] = inc
>   def get(o):
>     return o["n"]
>   o["get"] = get
>   return o

This parent class is not defined in the same way as the child class
below.  The class below uses partial to fix the object in the method,
but the parent one does not.  We need consistency.  

But if we curry the parent class's methods (that is, if we apply partial
on it to fix the object in its first argument), we will curry them a
second time in inherit_from.  That won't work.  I can't see an elegant
solution there, so what I'm going to do is to keep a copy of the
uncurried original method.

The code below works, but you can see it's kinda ugly.  I wish I could
uncurry a procedure, but I don't think this is possible.  (Is it?)

# -*- mode: python; python-indent-offset: 2 -*-
def Counter(name = None):
  self = {"name": name if name else "untitled", "n": 0}
  def inc(self):
    self["n"] += 1
    return self
  self["inc_uncurried"] = inc
  self["inc"] = curry(inc, self)
  def get(self):
    return self["n"]
  self["get_uncurried"] = get
  self["get"] = curry(get, self)
  return self

def Car(maker):
  self = {"maker": maker, "state": "off"}
  inherit_from(Counter, self)
  def on(self):
    if self["is_on"]():
      raise ValueError("oh, no: car is already on")
    self["inc"]()
    print(f"{self['maker']}: bruum!")
    self["state"] = "on"
    return self
  self["on_uncurried"] = on
  self["on"] = curry(on, self)
  def off(self):
    if self["is_off"]():
      raise ValueError("oh, no: car is already off")
    print(f"{self['maker']}: spat!")
    self["state"] = "off"
    return self
  self["off_uncurried"] = off
  self["off"] = curry(off, self)
  def is_on(self):
    return self["state"] == "on"
  self["is_on_uncurried"] = is_on
  self["is_on"] = curry(is_on, self)
  def is_off(self):
    return self["state"] == "off"
  self["is_off_uncurried"] = is_off
  self["is_off"] = curry(is_off, self)
  return self

def main():
  car1 = Car("Ford")
  car2 = Car("VW")
  for i in range(5):
    car1["on"](); car1["off"]()
  for i in range(3):
    car2["on"](); car2["off"]()
  print(f"car turned on = {car1['get']()} ({car1['maker']})")
  print(f"car turned on = {car2['get']()} ({car2['maker']})")

>>> main()
Ford: bruum!
Ford: spat!
Ford: bruum!
Ford: spat!
Ford: bruum!
Ford: spat!
Ford: bruum!
Ford: spat!
Ford: bruum!
Ford: spat!
VW: bruum!
VW: spat!
VW: bruum!
VW: spat!
VW: bruum!
VW: spat!
car turned on = 5 (Ford)
car turned on = 3 (VW)


More information about the Python-list mailing list