Subclassing Expression in python with multiple arguments in __init__ is erroneous.

Issue #681 resolved
Matthias Liertzer created an issue

When subclassing Expression in python and providing a constructor with more than one argument, one can no longer explicitly provide an ufl element. Depending on the number of arguments of the constructor, other arguments (of the Expression constructor) cannot be passed either. Furthermore, the number of arguments, that are allowed for a custom constructor is limited by the number of arguments of the Expression constructor. For example, the following python script

from dolfin import *
mesh = UnitSquareMesh(10, 10)
V=FunctionSpace(mesh, "CG", 1)

class MyExpression(Expression):
    def __init__(self, arg1, arg2, **kwargs):
        pass

    def eval(self, values, x):
        values[0] = 1

expr = MyExpression(1.0, 2.0, element=V.ufl_element())

unexpectedly fails with the error message TypeError: __new__() got multiple values for keyword argument 'element'

The same is also true when only one argument is used in __init__ and passing cppcode="....". However, since cppcode is not used when subclassing Expression, this is not really problematic.

Hence, I'd suggest the following route to solve this issue:

Define __new__ for Expression as

def __new__(self, cppcode, *args, **kwargs):

This way, writing

Expression("x[0]**2", degree=2)

is still allowed and the mentioned error case does not occur either. However, it's no longer possible to provide the additional arguments (degree,element, mesh, domain,...) as positional arguments, but only as keyword arguments. Since all unit tests and demos already use this convention, user code should not be affected. In my opinion forcing the user to use keyword arguments, makes their code probably much nicer to read anyway.

Comments (10)

  1. Log in to comment