diff --git a/python/dune/xt/functions/expression.cc b/python/dune/xt/functions/expression.cc
index 6938bdd87502b6fd25ecad836e660f5aa0f89472..770510b1b5013afc6f6f301e9372839727a81bad 100644
--- a/python/dune/xt/functions/expression.cc
+++ b/python/dune/xt/functions/expression.cc
@@ -19,10 +19,244 @@
 #include <dune/pybindxi/pybind11.h>
 #include <dune/pybindxi/stl.h>
 
+#include <dune/xt/common/string.hh>
+#include <dune/xt/grid/gridprovider/provider.hh>
+#include <dune/xt/grid/type_traits.hh>
+#include <dune/xt/functions/expression.hh>
+
+#include <python/dune/xt/common/fvector.hh>
+#include <python/dune/xt/common/fmatrix.hh>
 #include <python/dune/xt/common/bindings.hh>
+#include <python/dune/xt/grid/traits.hh>
 #include <python/dune/xt/common/exceptions.bindings.hh>
 
-#include "expression.hh"
+namespace Dune {
+namespace XT {
+namespace Functions {
+namespace bindings {
+
+
+template <size_t d, size_t r = 1, size_t rC = 1, class R = double>
+class ExpressionFunction
+{
+  using type = Functions::ExpressionFunction<d, r, rC, R>;
+  using base_type = Functions::FunctionInterface<d, r, rC, R>;
+  using bound_type = pybind11::class_<type, base_type>;
+
+  template <size_t r_ = r, size_t rC_ = rC, bool anything = true> // the matrix-valued case
+  struct addbind
+  {
+    static void ctor(bound_type& c)
+    {
+      namespace py = pybind11;
+      using namespace pybind11::literals;
+
+      c.def(py::init<const std::string&,
+                     const Common::FieldMatrix<std::string, r, rC>&,
+                     const Common::FieldVector<Common::FieldMatrix<std::string, rC, d>, r>&,
+                     const size_t,
+                     const std::string>(),
+            "variable"_a,
+            "expressions"_a,
+            "gradient_expressions"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+      c.def(py::init<const std::string&,
+                     const Common::FieldMatrix<std::string, r, rC>&,
+                     const size_t,
+                     const std::string>(),
+            "variable"_a,
+            "expressions"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+    } // ... ctor(...)
+
+    static void factory(pybind11::module& m, const std::string& ClassId)
+    {
+      namespace py = pybind11;
+      using namespace pybind11::literals;
+
+      m.def(ClassId.c_str(),
+            [](Grid::bindings::Dimension<d> /*dim_domain*/,
+               const std::string& variable,
+               const Common::FieldMatrix<std::string, r, rC>& expressions,
+               const Common::FieldVector<Common::FieldMatrix<std::string, rC, d>, r>& gradient_expressions,
+               const size_t order,
+               const std::string& name) { return type(variable, expressions, gradient_expressions, order, name); },
+            "dim_domain"_a,
+            "variable"_a,
+            "expressions"_a,
+            "gradient_expressions"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+      m.def(ClassId.c_str(),
+            [](Grid::bindings::Dimension<d> /*dim_domain*/,
+               const std::string& variable,
+               const Common::FieldMatrix<std::string, r, rC>& expressions,
+               const size_t order,
+               const std::string& name) { return type(variable, expressions, order, name); },
+            "dim_domain"_a,
+            "variable"_a,
+            "expressions"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+    } // ... factory(...)
+  }; // struct addbind, the matrix-valued case
+
+  template <size_t r_, bool anything> // the vector-valued case
+  struct addbind<r_, 1, anything>
+  {
+    static void ctor(bound_type& c)
+    {
+      namespace py = pybind11;
+      using namespace pybind11::literals;
+
+      c.def(py::init<const std::string&,
+                     const Common::FieldVector<std::string, r>&,
+                     const Common::FieldMatrix<std::string, r, d>&,
+                     const size_t,
+                     const std::string>(),
+            "variable"_a,
+            "expressions"_a,
+            "gradient_expressions"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+      c.def(py::init<const std::string&, const Common::FieldVector<std::string, r>&, const size_t, const std::string>(),
+            "variable"_a,
+            "expressions"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+    } // ... ctor(...)
+
+    static void factory(pybind11::module& m, const std::string& ClassId)
+    {
+      namespace py = pybind11;
+      using namespace pybind11::literals;
+
+      m.def(ClassId.c_str(),
+            [](Grid::bindings::Dimension<d> /*dim_domain*/,
+               const std::string& variable,
+               const Common::FieldVector<std::string, r>& expressions,
+               const Common::FieldMatrix<std::string, r, d>& gradient_expressions,
+               const size_t order,
+               const std::string& name) { return type(variable, expressions, gradient_expressions, order, name); },
+            "dim_domain"_a,
+            "variable"_a,
+            "expressions"_a,
+            "gradient_expressions"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+      m.def(ClassId.c_str(),
+            [](Grid::bindings::Dimension<d> /*dim_domain*/,
+               const std::string& variable,
+               const Common::FieldVector<std::string, r>& expressions,
+               const size_t order,
+               const std::string& name) { return type(variable, expressions, order, name); },
+            "dim_domain"_a,
+            "variable"_a,
+            "expressions"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+    } // ... factory(...)
+  }; // struct addbind, the vector-valued case
+
+  template <bool anything>
+  struct addbind<1, 1, anything> // the scalar case
+  {
+    static void ctor(bound_type& c)
+    {
+      namespace py = pybind11;
+      using namespace pybind11::literals;
+
+      c.def(py::init([](const std::string& variable,
+                        const std::string& expression,
+                        const Common::FieldVector<std::string, d>& gradient_expressions,
+                        const size_t order,
+                        const std::string& name) {
+              Common::FieldMatrix<std::string, 1, d> gradient_expressions_mat;
+              gradient_expressions_mat[0] = gradient_expressions;
+              return new type(
+                  variable, Common::FieldVector<std::string, 1>(expression), gradient_expressions_mat, order, name);
+            }),
+            "variable"_a,
+            "expression"_a,
+            "gradient_expressions"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+      c.def(py::init([](const std::string& variable,
+                        const std::string& expression,
+                        const size_t order,
+                        const std::string& name) {
+              return new type(variable, Common::FieldVector<std::string, 1>(expression), order, name);
+            }),
+            "variable"_a,
+            "expression"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+    } // ... ctor(...)
+
+    static void factory(pybind11::module& m, const std::string& ClassId)
+    {
+      namespace py = pybind11;
+      using namespace pybind11::literals;
+
+      m.def(ClassId.c_str(),
+            [](Grid::bindings::Dimension<d> /*dim_domain*/,
+               const std::string& variable,
+               const std::string& expression,
+               const Common::FieldVector<std::string, d>& gradient_expressions,
+               const size_t order,
+               const std::string& name) {
+              Common::FieldMatrix<std::string, 1, d> gradient_expressions_mat;
+              gradient_expressions_mat[0] = gradient_expressions;
+              return new type(
+                  variable, Common::FieldVector<std::string, 1>(expression), gradient_expressions_mat, order, name);
+            },
+            "dim_domain"_a,
+            "variable"_a,
+            "expression"_a,
+            "gradient_expressions"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+      m.def(ClassId.c_str(),
+            [](Grid::bindings::Dimension<d> /*dim_domain*/,
+               const std::string& variable,
+               const std::string& expression,
+               const size_t order,
+               const std::string& name) { return new type(variable, expression, order, name); },
+            "dim_domain"_a,
+            "variable"_a,
+            "expression"_a,
+            "order"_a,
+            "name"_a = type::static_id());
+    } // ... factory(...)
+  }; // struct addbind, the scalar case
+
+public:
+  static bound_type bind(pybind11::module& m, const std::string& class_id = "expression_function")
+  {
+    namespace py = pybind11;
+    using namespace pybind11::literals;
+
+    std::string class_name = class_id + "_" + Common::to_string(d) + "_to_" + Common::to_string(r);
+    if (rC > 1)
+      class_name += "x" + Common::to_string(rC);
+    class_name += "d";
+    const auto ClassName = Common::to_camel_case(class_name);
+    bound_type c(m, ClassName.c_str(), XT::Common::to_camel_case(class_id).c_str());
+    addbind<>::ctor(c);
+
+    addbind<>::factory(m, Common::to_camel_case(class_id));
+
+    return c;
+  }
+}; // class ExpressionFunction
+
+
+} // namespace bindings
+} // namespace Functions
+} // namespace XT
+} // namespace Dune
 
 
 PYBIND11_MODULE(_functions_expression, m)
@@ -30,28 +264,27 @@ PYBIND11_MODULE(_functions_expression, m)
   namespace py = pybind11;
 
   py::module::import("dune.xt.common");
+  py::module::import("dune.xt.grid");
   py::module::import("dune.xt.la");
   py::module::import("dune.xt.functions._functions_function_interface_1d");
   py::module::import("dune.xt.functions._functions_function_interface_2d");
   py::module::import("dune.xt.functions._functions_function_interface_3d");
 
-  using namespace Dune::XT::Functions;
-
-  bind_ExpressionFunction<1, 1, 1>(m);
-  bind_ExpressionFunction<1, 2, 1>(m);
-  bind_ExpressionFunction<1, 2, 2>(m);
-  bind_ExpressionFunction<1, 3, 1>(m);
-  bind_ExpressionFunction<1, 3, 3>(m);
-
-  bind_ExpressionFunction<2, 1, 1>(m);
-  bind_ExpressionFunction<2, 2, 1>(m);
-  bind_ExpressionFunction<2, 2, 2>(m);
-  bind_ExpressionFunction<2, 3, 1>(m);
-  bind_ExpressionFunction<2, 3, 3>(m);
-
-  bind_ExpressionFunction<3, 1, 1>(m);
-  bind_ExpressionFunction<3, 2, 1>(m);
-  bind_ExpressionFunction<3, 2, 2>(m);
-  bind_ExpressionFunction<3, 3, 1>(m);
-  bind_ExpressionFunction<3, 3, 3>(m);
-}
+  Dune::XT::Functions::bindings::ExpressionFunction<1, 1, 1>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<1, 2, 1>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<1, 2, 2>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<1, 3, 1>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<1, 3, 3>::bind(m);
+
+  Dune::XT::Functions::bindings::ExpressionFunction<2, 1, 1>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<2, 2, 1>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<2, 2, 2>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<2, 3, 1>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<2, 3, 3>::bind(m);
+
+  Dune::XT::Functions::bindings::ExpressionFunction<3, 1, 1>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<3, 2, 1>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<3, 2, 2>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<3, 3, 1>::bind(m);
+  Dune::XT::Functions::bindings::ExpressionFunction<3, 3, 3>::bind(m);
+} // PYBIND11_MODULE(...)
diff --git a/python/dune/xt/functions/expression.hh b/python/dune/xt/functions/expression.hh
deleted file mode 100644
index 9fb741bf714cc839dcc19cd0d02f1d5df9e182a2..0000000000000000000000000000000000000000
--- a/python/dune/xt/functions/expression.hh
+++ /dev/null
@@ -1,280 +0,0 @@
-// This file is part of the dune-xt project:
-//   https://github.com/dune-community/dune-xt
-// Copyright 2009-2020 dune-xt developers and contributors. All rights reserved.
-// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
-//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
-//          with "runtime exception" (http://www.dune-project.org/license.html)
-// Authors:
-//   Felix Schindler (2016 - 2017, 2019)
-//   René Fritze     (2018 - 2019)
-//   Tim Keil        (2018)
-//   Tobias Leibner  (2018 - 2020)
-
-#ifndef PYTHON_DUNE_XT_FUNCTIONS_EXPRESSION_HH
-#define PYTHON_DUNE_XT_FUNCTIONS_EXPRESSION_HH
-
-#include <dune/pybindxi/pybind11.h>
-#include <dune/pybindxi/stl.h>
-
-#include <dune/xt/common/string.hh>
-#include <dune/xt/grid/type_traits.hh>
-#include <dune/xt/grid/gridprovider/provider.hh>
-#include <dune/xt/functions/expression.hh>
-#include <python/dune/xt/common/fvector.hh>
-#include <python/dune/xt/common/fmatrix.hh>
-
-namespace Dune {
-namespace XT {
-namespace Functions {
-namespace internal {
-
-
-template <size_t d, size_t r, size_t rC>
-struct addbind_ExpressionFunction_scalar_ctor
-{
-  template <class C>
-  void operator()(C& /*c*/, const std::string& /*static_id*/)
-  {}
-};
-
-template <size_t d, size_t r>
-struct addbind_ExpressionFunction_scalar_ctor<d, r, 1>
-{
-  template <class C>
-  void operator()(C& c, const std::string& static_id)
-  {
-    namespace py = pybind11;
-    using namespace pybind11::literals;
-
-    c.def(py::init<const std::string,
-                   const Common::FieldVector<std::string, r>,
-                   const Common::FieldMatrix<std::string, r, d>,
-                   const size_t,
-                   const std::string>(),
-          "variable"_a,
-          "expressions"_a,
-          "gradient_expressions"_a,
-          "order"_a,
-          "name"_a = static_id);
-
-    c.def(py::init<const std::string, const Common::FieldVector<std::string, r>, const size_t, const std::string>(),
-          "variable"_a,
-          "expressions"_a,
-          "order"_a,
-          "name"_a = static_id);
-  }
-}; // struct addbind_ExpressionFunction_scalar_ctor<1, 1>
-
-
-} // namespace internal
-
-
-/**
- * \note We would like to drop the d template paremter and use either of
-\code
-static const           size_t d = G::dimension;
-static const constexpr size_t d = G::dimension;
-\endcode
- *       but this triggers a bug in gcc-4.9 and we thus need to use G::dimension
- *       everywhere: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59937
- */
-template <size_t d, size_t r>
-pybind11::class_<ExpressionFunction<d, r, 3, double>, FunctionInterface<d, r, 3, double>>
-bind_ExpressionFunction(pybind11::module& m, std::integral_constant<int, 3>)
-{
-  namespace py = pybind11;
-  using namespace pybind11::literals;
-  const size_t rC = 3;
-  using R = double;
-
-  using I = FunctionInterface<d, r, rC, R>;
-  using C = ExpressionFunction<d, r, rC, R>;
-
-  const std::string c_name =
-      "ExpressionFunction__" + Common::to_string(d) + "d_to_" + Common::to_string(r) + "x" + Common::to_string(rC);
-  py::class_<C, I> c(m, std::string(c_name).c_str(), std::string(c_name).c_str());
-
-  internal::addbind_ExpressionFunction_scalar_ctor<d, r, rC>()(c, C::static_id());
-  c.def(py::init<const std::string,
-                 const Common::FieldMatrix<std::string, r, rC>,
-                 const Common::FieldVector<Common::FieldMatrix<std::string, rC, d>, r>,
-                 const size_t,
-                 const std::string>(),
-        "variable"_a,
-        "expressions"_a,
-        "gradient_expressions"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  c.def(py::init<const std::string, const Common::FieldMatrix<std::string, r, rC>, const size_t, const std::string>(),
-        "variable"_a,
-        "expressions"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  c.def_property_readonly("static_id", [](const C& /*self*/) { return C::static_id(); });
-
-  const std::string make_name = "make_expression_function_" + Common::to_string(r) + "x" + Common::to_string(rC);
-  m.def(std::string(make_name).c_str(),
-        [](const std::string& variable,
-           const Common::FieldMatrix<std::string, r, rC>& expression,
-           const Common::FieldVector<Common::FieldMatrix<std::string, rC, d>, r>& gradient_expressions,
-           const size_t& order,
-           const std::string& name) { return C(variable, expression, gradient_expressions, order, name); },
-        "variable"_a,
-        "expression"_a,
-        "gradient_expressions"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  m.def(std::string(make_name).c_str(),
-        [](const std::string& variable,
-           const Common::FieldMatrix<std::string, r, rC>& expression,
-           const size_t& order,
-           const std::string& name) { return C(variable, expression, order, name); },
-        "variable"_a,
-        "expression"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  return c;
-} // ... bind_ExpressionFunction(...)
-
-template <size_t d, size_t r>
-pybind11::class_<ExpressionFunction<d, r, 2, double>, FunctionInterface<d, r, 2, double>>
-bind_ExpressionFunction(pybind11::module& m, std::integral_constant<int, 2>)
-{
-  namespace py = pybind11;
-  using namespace pybind11::literals;
-
-  const size_t rC = 2;
-  using R = double;
-
-  using I = FunctionInterface<d, r, rC, R>;
-  using C = ExpressionFunction<d, r, rC, R>;
-
-  const std::string c_name =
-      "ExpressionFunction__" + Common::to_string(d) + "d_to_" + Common::to_string(r) + "x" + Common::to_string(rC);
-  py::class_<C, I> c(m, std::string(c_name).c_str(), std::string(c_name).c_str());
-
-  internal::addbind_ExpressionFunction_scalar_ctor<d, r, rC>()(c, C::static_id());
-  c.def(py::init<const std::string,
-                 const Common::FieldMatrix<std::string, r, rC>,
-                 const Common::FieldVector<Common::FieldMatrix<std::string, rC, d>, r>,
-                 const size_t,
-                 const std::string>(),
-        "variable"_a,
-        "expressions"_a,
-        "gradient_expressions"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  c.def(py::init<const std::string, const Common::FieldMatrix<std::string, r, rC>, const size_t, const std::string>(),
-        "variable"_a,
-        "expressions"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  c.def_property_readonly("static_id", [](const C& /*self*/) { return C::static_id(); });
-
-  const std::string make_name = "make_expression_function_" + Common::to_string(r) + "x" + Common::to_string(rC);
-  m.def(std::string(make_name).c_str(),
-        [](const std::string& variable,
-           const Common::FieldMatrix<std::string, r, rC>& expression,
-           const Common::FieldVector<Common::FieldMatrix<std::string, rC, d>, r>& gradient_expressions,
-           const size_t& order,
-           const std::string& name) { return C(variable, expression, gradient_expressions, order, name); },
-        "variable"_a,
-        "expression"_a,
-        "gradient_expressions"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  m.def(std::string(make_name).c_str(),
-        [](const std::string& variable,
-           const Common::FieldMatrix<std::string, r, rC>& expression,
-           const size_t& order,
-           const std::string& name) { return C(variable, expression, order, name); },
-        "variable"_a,
-        "expression"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  return c;
-} // ... bind_ExpressionFunction(...)
-
-template <size_t d, size_t r>
-pybind11::class_<ExpressionFunction<d, r, 1, double>, FunctionInterface<d, r, 1, double>>
-bind_ExpressionFunction(pybind11::module& m, std::integral_constant<int, 1>)
-{
-  namespace py = pybind11;
-  using namespace pybind11::literals;
-  const size_t rC = 1;
-  using R = double;
-
-  using I = FunctionInterface<d, r, rC, R>;
-  using C = ExpressionFunction<d, r, rC, R>;
-
-  const std::string c_name =
-      "ExpressionFunction__" + Common::to_string(d) + "d_to_" + Common::to_string(r) + "x" + Common::to_string(1);
-  py::class_<C, I> c(m, std::string(c_name).c_str(), std::string(c_name).c_str());
-
-  internal::addbind_ExpressionFunction_scalar_ctor<d, r, 1>()(c, C::static_id());
-  c.def(py::init<const std::string,
-                 const Common::FieldVector<std::string, r>,
-                 const Common::FieldMatrix<std::string, r, d>,
-                 const size_t,
-                 const std::string>(),
-        "variable"_a,
-        "expressions"_a,
-        "gradient_expressions"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  c.def(py::init<const std::string, const Common::FieldVector<std::string, r>, const size_t, const std::string>(),
-        "variable"_a,
-        "expressions"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  c.def_property_readonly("static_id", [](const C& /*self*/) { return C::static_id(); });
-
-  const std::string make_name = "make_expression_function_" + Common::to_string(r) + "x" + Common::to_string(1);
-  m.def(std::string(make_name).c_str(),
-        [](const std::string& variable,
-           const Common::FieldVector<std::string, r>& expression,
-           const Common::FieldMatrix<std::string, r, d>& gradient_expressions,
-           const size_t& order,
-           const std::string& name) { return C(variable, expression, gradient_expressions, order, name); },
-        "variable"_a,
-        "expression"_a,
-        "gradient_expressions"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  m.def(std::string(make_name).c_str(),
-        [](const std::string& variable,
-           const Common::FieldVector<std::string, r>& expression,
-           const size_t& order,
-           const std::string& name) { return C(variable, expression, order, name); },
-        "variable"_a,
-        "expression"_a,
-        "order"_a,
-        "name"_a = C::static_id());
-
-  return c;
-}
-
-
-template <size_t d, size_t r, size_t rC>
-pybind11::class_<ExpressionFunction<d, r, rC, double>> bind_ExpressionFunction(pybind11::module& m)
-{
-  return bind_ExpressionFunction<d, r>(m, std::integral_constant<int, rC>());
-} // ... bind_ExpressionFunction(...)
-
-
-} // namespace Functions
-} // namespace XT
-} // namespace Dune
-
-#endif // PYTHON_DUNE_XT_FUNCTIONS_EXPRESSION_HH