Horrible abuse of __init_subclass__, or elegant hack?

Chris Angelico rosuav at gmail.com
Sun Apr 4 05:13:28 EDT 2021


On Sun, Apr 4, 2021 at 6:26 PM jak <nospam at please.ty> wrote:
>
> Il 01/04/2021 01:14, Chris Angelico ha scritto:
> > I think this code makes some sort of argument in the debate about
> > whether Python has too much flexibility or if it's the best
> > metaprogramming toolset in the world. I'm not sure which side of the
> > debate it falls on, though.
> >
> > class Building:
> >      resource = None
> >      @classmethod
> >      def __init_subclass__(bldg):
> >          super().__init_subclass__()
> >          print("Building:", bldg.__name__)
> >          def make_recipe(recip):
> >              print(recip.__name__.replace("_", " "), "is made in a",
> > bldg.__name__.replace("_", " "))
> >          bldg.__init_subclass__ = classmethod(make_recipe)
> >
> >
> > class Extractor(Building): ...
> > class Refinery(Building): ...
> >
> > class Crude(Extractor):
> >      resource = "Oil"
> >      time: 1
> >      Crude: 1
> >
> > class Plastic(Refinery):
> >      Crude: 3
> >      time: 6
> >      Residue: 1
> >      Plastic: 2
> >
> > class Rubber(Refinery):
> >      Crude: 3
> >      time: 6
> >      Residue: 2
> >      Rubber: 2
> >
> > Full code is here if you want context:
> > https://github.com/Rosuav/shed/blob/master/satisfactory-production.py
> >
> > Subclassing Building defines a class that is a building. (The ellipsis
> > body is a placeholder; I haven't implemented stuff where the buildings
> > know about their power consumptions and such. Eventually they'll have
> > other attributes.) But subclassing a building defines a recipe that is
> > produced in that building. Markers placed before the "time" are
> > ingredients, those after the "time" are products.
> >
> > There are actually a lot of interesting wrinkles to trying to replace
> > __init_subclass__ on the fly. Things get quite entertaining if you
> > don't use the decorator, or if you define and decorate the function
> > outside of the class, or various other combinations.
> >
> > On a scale of 1 to "submit this to The Daily WTF immediately", how bad
> > is this code? :)
> >
> > ChrisA
> >
>
> Hi,
> from https://github.com/Rosuav/shed/blob/master/satisfactory-production.py
> I get this error:
>
> cmd console Win10:
> $> py -V
> Python 3.8.6
>
> $> py CrisAngelico.py
> Building: Extractor
> Building: Refinery
> Building: Blender
> Building: Packager
> Building: Assembler
> Crude is made in a Extractor
> Water is made in a Extractor
> Plastic is made in a Refinery
> Rubber is made in a Refinery
> Traceback (most recent call last):
>    File "CrisAngelico.py", line 123, in <module>
>      class Rubber(Refinery):
>    File "CrisAngelico.py", line 72, in make_recipe
>      if net <= alternate["makes"] and costs >= alternate["costs"]:
> TypeError: '<=' not supported between instances of 'Counter' and 'Counter'
>

Huh. I forget sometimes which version something was introduced in.
Apparently the comparison operators on Counters came in with Python
3.10. Sorry about that. As an alternative, subtraction is very
approximately equivalent (if subtracting one counter from another
yields nothing, then the first one is smaller in total content than
the second), so it should be possible to adjust it.

ChrisA


More information about the Python-list mailing list