Contains AutOperatio, a mixin which makes self-type-returning operations on instances of subclasses of general purpose built-in containers, dict, set, list, and tuple, return subclass instances.
Subclassing built-in general-purpose containers is messy because an instance of the subclass will often return an instance of the superclass instead of an instance of itself if an operation is performed on it.
Example:
class Foo(list):
pass
foo = Foo()
foo += [] # foo is still an instance of Foo, as it's mutated in place
foo2 = foo + [] # foo2 is just a list!
foo3 = foo[:] # foo3 is just a list!
This holds true for all built-in transformative operators which act on sequences and return a similar type: [slice], +, -, *, &, ^, |
As well as non-updating set methods: union, difference, intersection, symmetric_difference, union
Make subclasses of sets, lists, dicts, and tuples which employ default methods and dunders return an instance of their own class when these operations are performed.
Do this by including AutOperatio as a mixin when subclassing general purpose built-in containers.
Inherit from Autoperatio and the class you wish to subclass in the same subclass, like this:
class Foo(set, AutOperatio): # This works
...
class SubFoo(Foo): # This will work too, as will all inheritors if methods aren't overriden
...
class Bar(AutOperatio, set) # As will this
...
Built-in to use methods from must be last thing in in __mro__ other than object or AutoOperatio... or you need to specify superclass= in the signature of every subclass definition like this:
class Foo(list, AutOperatio, SomethingElse, superclass=list): # Must specify or SomethingElse will be used
...
class SubFoo(Foo, superclass=list): # Still required or SomethingElse will be used
...
class Bar:
...
class SubBar(AutOperatio, tuple, Bar, superclass=tuple): # Required here too and in all subclasses
...
By default, superclass __new__ and __init__ are used for producing new instances. This prevents overriding them from breaking anything. If this isn't desired behavior, use kwargs in signature of class definitions like this:
class Foo(list, AutOperatio, super_new=False, super_init=False):
...
- Not wrappers
- Methods do not have to rely on __new__ and __init__ of subclass
- No data, __cast, or any other extra class attributes
- The only apparent addition to subclass over built-ins is __closure__ in redefined methods
Coverage Report:
Name Stmts Miss Cover
-----------------------------------------
src\autoperatio.py 35 0 100%
test_autoperatio.py 115 0 100%
-----------------------------------------
TOTAL 150 0 100%