In the first case, the class D, B, C, A, the path through B symbolizes that A's attribute should be used. But As the attribute itself is shadowed by the attribute in C - that is, the declaration in C overrides the attr declared in A. Therefore it is the one used.
In the second case, D, B, C, A, E, B coming first than C, again shows that A.attr should be used. This time, though, A's own parameter had not been shadowed by different classes in the hierarchy - rather C.attr comes from another "lineage" - so the language picks the first it encounters.
For your second example, you have D(B, C) - the linearizations for B and C are: [B, A, object] and [C, E, object] and the linearization of D starts by taking "B", checking it is not on the tail of any other lists (and it is not on [C, E, object]), then B is taken. The left out lists are [A, object] and [C, E, object] - the algorithm then picks A it is not in the other list, then A is appended to the MRO of D. It then picks object. It is on the other list. So the algorithm neglects the first list intact and takes C, E, and eventually the object, for D, B, A, C, E, object linearization.
In your first example, the linearization of both bases are [B, A, object] and [C, A, object] when the algorithm checks for A, it is on the tail of the second list - so, C is picked first then A from the second list - the final linearization is D, B, C, A, object.
Join this Python Training course now if you want to gain more knowledge in Python.