Horrible abuse of __init_subclass__, or elegant hack?

jak nospam at please.ty
Sun Apr 4 12:18:55 EDT 2021


Il 04/04/2021 11:13, Chris Angelico ha scritto:
> 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
> 
I modified your code in the following way:

line 65-66:
from:

     if (qty <= alternate["per_minute"]
	and (costs[Extractor], costs) > (alternate["costs"][Extractor], 
alternate["costs"])

to:
     if (qty <= alternate["per_minute"]
         and (costs[Extractor], set(costs)) > 
(alternate["costs"][Extractor], set(alternate["costs"]))

and line 72:
from:
     if net <= alternate["makes"] and costs >= alternate["costs"]:

to:
     if set(net) <= set(alternate["makes"]) and set(costs) >= 
set(alternate["costs"]):
					

The program runs now. Is the result correct?

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
Fuel is made in a Refinery
Heavy Oil Residue is made in a Refinery
Polymer Resin is made in a Refinery
Residual Fuel is made in a Refinery
Diluted Fuel is made in a Blender
Canister is made in a Extractor
Package Water is made in a Packager
Diluted Packaged Fuel is made in a Refinery
Unpackage Fuel is made in a Packager
Petroleum Coke is made in a Refinery
Residual Plastic is made in a Refinery
Residual Rubber is made in a Refinery
Recycled Plastic is made in a Refinery
Recycled Rubber is made in a Refinery
Sulfur is made in a Extractor
Coal is made in a Extractor
Compacted is made in a Assembler
Turbofuel is made in a Refinery
Turbo Heavy Fuel is made in a Refinery
Turbo Blend Fuel is made in a Blender
Specify one or more target items
Exit code:  0

(forgive me your trouble)
cheers


More information about the Python-list mailing list