Arno-Can Uestuensoez <[email protected]> added the comment:
Hey,
first of all thank you for the fast reply.
Your examples reinforce exactly my issue. I prefer the KISS principle in
providing isolated use-cases for transparency without extras. Which is
seperated reduced flat calls only.
The other point is, I develop and test shared code for Python2.7(which will be
out there for a while...) and Python3.5+, thus prefer shared syntax whenever
possible. The "super()" interface has changed, using the shared syntax from
2.7.16:
- Python2.7.16: super(type[, object-or-type])
- Python3.7.4: super([type[, object-or-type]])
The test of your code with Python 2.7.16 requires modification.
You are right with the case 4, this is the actual issue related to the MRO and
the parameter passing. I did not ask for the number of calls of the common base
classes, but the passing of the parameters. The call order/MRO is OK, but I
doubt the passed parameter signatures. My basic assumption here is that the
call routing by MRO should or even must not be intermixed with the actually
passed call parameters.
So I added the output of your example for "mixin_tests2.py" for Python3.6.5,
tested for Python3.7.0 too.
#--------------
(3.6.5) [acue@lap001 test-modified]$ python mixin_tests2.py
==============================
C MRO: ['C', 'A_With_Arg', 'B_With_Arg', 'MyBase', 'object']
C:C True
A_With_Arg:C True
call super().__init__ with argument
B_With_Arg:C True
call super().__init__ with argument
MyBase received 1 arguments
TypeError('object.__init__() takes no parameters',)
==============================
C MRO: ['C', 'B_With_Arg', 'A_With_Arg', 'MyBase', 'object']
C:C True
B_With_Arg:C True
call super().__init__ with argument
A_With_Arg:C True
call super().__init__ with argument
MyBase received 1 arguments
TypeError('object.__init__() takes no parameters',)
==============================
C MRO: ['C', 'A_With_Arg', 'B_Without_Arg', 'MyBase', 'object']
C:C True
A_With_Arg:C True
call super().__init__ with argument
B_Without_Arg:C True
call super().__init__ without argument
MyBase received 0 arguments
success
==============================
C MRO: ['C', 'B_Without_Arg', 'A_With_Arg', 'MyBase', 'object']
C:C True
B_Without_Arg:C True
call super().__init__ without argument
A_With_Arg:C False
success
(3.6.5) [acue@lap001 test-modified]$
#-----------------------
Or reduced to the focus of the actual issue and depicted the actual passed
parameters. See the following "Case 4 - same as mixin_C_is_B0A1" for the
essential question.
==============================
Case 0 - same as mixin_C_is_A1B1
A_With_Arg:C True
B_With_Arg:C True
TypeError('object.__init__() takes no parameters',)
Resulting in:
C.__init__(True)
A_With_Arg.__init__(True)
B_With_Arg.__init__(True)
MyBase.__init__(True)
object.__init__(True)
Comment:
The TypeError is expected and OK.
==============================
Case 1 - same as mixin_C_is_B1A1
B_With_Arg:C True
A_With_Arg:C True
TypeError('object.__init__() takes no parameters',)
Resulting in:
C.__init__(True)
B_With_Arg.__init__(True)
A_With_Arg.__init__(True)
MyBase.__init__(True)
object.__init__(True)
Comment:
The TypeError is expected and OK.
==============================
Case 2 - same as mixin_C_is_A1B0
A_With_Arg:C True
B_Without_Arg:C True
MyBase received 0 arguments
success
Comment:
The success is expected and OK.
The actual call due to MRO is:
C(A_With_Arg(), B_Without_Arg())
Resulting in:
C.__init__(True)
A_With_Arg.__init__(True)
B_Without_Arg.__init__(True)
MyBase.__init__(False)
object.__init__()
Remark: I assume, that the single call of "object.__init__()" is here
intentional.
==============================
Case 4 - same as mixin_C_is_B0A1
B_Without_Arg:C True
A_With_Arg:C False
success
Comment:
The success is NOT expected and as far as I can see should be treated as an
Error so NOK.
The actual call is:
C(B_Without_Arg(), A_With_Arg())
Resulting in:
Seemingly the behaviour is:
C.__init__(True)
B_Without_Arg.__init__(True)
A_With_Arg.__init__(False)
This means the call of "super(B, self).__init__()" within
"B.__init__()" defines the call parameters of "A.__init__()".
Even though I expect the call order as routed by the MRO,
I did not expected the parameters of A to be passed from the
sibling class B, but as defined by the base class C. Thus the
following:
C.__init__(True)
B_Without_Arg()
A_With_Arg.__init__(True)
object.__init__(True) # this is the behaviour I expect
# due to the MRO and the
# parameters passed from the
# base class
Remark: I assume, that the single call of "object.__init__()" is here
intentional.
#-----------------------
The essential part I doubt is given by the case 4 / same as mixin_C_is_B0A1,
where the call parameter of A is defined by the sibling B, instead of by the
base class C. The routing of the call order is OK.
My remark with "standalone call" depicts the fact, that instanciating e.g. only
your class "A_With_Arg(True)" will raise in any case a TypeError, but using it
in the context "C(A_With_Arg(), B_Without_Arg())" may not because the call of
the "object" class follows the right-most mixin. But anyhow, this means
different parameters by the "suppressed" left-side classes/alls would be
silently suppressed.
Resulting from the case 4, I tend to see the aspect of the parameter passing as
erroneous.
----------
Added file: https://bugs.python.org/file48624/mixin_C_is_B0A1.py
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue38262>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com