diff --git a/aidge_core/unit_tests/test_operator_binding.py b/aidge_core/unit_tests/test_operator_binding.py
index fcf4b0483869c9e9b006fe66db0778ab959aa7fc..437c10ad8b7c24349726b14f492bcf4e86360ffa 100644
--- a/aidge_core/unit_tests/test_operator_binding.py
+++ b/aidge_core/unit_tests/test_operator_binding.py
@@ -67,6 +67,29 @@ class test_operator_binding(unittest.TestCase):
         self.generic_operator.add_attr("l_str", ["ok"])
         self.assertEqual(self.generic_operator.get_attr("l_str"), ["ok"])
 
+    def test_dynamicattribute_binding(self):
+        # Check original C++ attributes are binded
+        attrs = aidge_core.test_DynamicAttributes_binding()
+        self.assertEqual(attrs.has_attr("a"), True)
+        self.assertEqual(attrs.get_attr("a"), 42)
+        self.assertEqual(attrs.has_attr("b"), True)
+        self.assertEqual(attrs.get_attr("b"), "test")
+        self.assertEqual(attrs.has_attr("c"), True)
+        self.assertEqual(attrs.get_attr("c"), [True, False, True])
+        self.assertEqual(attrs.get_attrs_name(), {"a", "b", "c"})
+        self.assertEqual(attrs.has_attr("d"), False)
+
+        # Add Python attributes
+        attrs.add_attr("d", 18.56)
+        self.assertEqual(attrs.get_attr("d"), 18.56)
+        self.assertEqual(attrs.has_attr("d"), True)
+        self.assertEqual(attrs.get_attrs_name(), {"a", "b", "c", "d"})
+        self.assertEqual(attrs.has_attr("e"), False)
+
+        # Check that added Python attribute is accessible in C++
+        # Return the value of an attribute named "d" of type float64 (double in C++)
+        self.assertEqual(aidge_core.test_DynamicAttributes_binding_check(attrs), 18.56)
+
     def test_compute_output_dims(self):
         in_dims=[25, 25]
         input = aidge_core.Producer(in_dims, name="In")
diff --git a/include/aidge/utils/DynamicAttributes.hpp b/include/aidge/utils/DynamicAttributes.hpp
index 0e91f0a5351807eb16ea4c1abf6b25330a9d8f0b..24800428ff842efbddbd9645d5515b790f9592c1 100644
--- a/include/aidge/utils/DynamicAttributes.hpp
+++ b/include/aidge/utils/DynamicAttributes.hpp
@@ -84,16 +84,16 @@ public:
     ///\tparam T expected Attribute type
     ///\param name Attribute name
     ///\param value Attribute value
-    template<class T> void addAttr(const std::string& name, T&& value)
+    template<class T> void addAttr(const std::string& name, const T& value)
     {
-        const auto& res = mAttrs.emplace(std::make_pair(name, libany::any(std::forward<T>(value))));
+        const auto& res = mAttrs.emplace(std::make_pair(name, libany::any(value)));
         assert(res.second && "attribute already exists");
 
 #ifdef PYBIND
         // We cannot handle Python object if the Python interpreter is not running
         if (Py_IsInitialized()) {
             // Keep a copy of the attribute in py::object that is updated everytime
-            mAttrsPy.emplace(std::make_pair(name, py::cast(std::forward<T>(value))));
+            mAttrsPy.emplace(std::make_pair(name, py::cast(value)));
         }
 #endif
     }
@@ -102,19 +102,19 @@ public:
     ///\tparam T expected Attribute type
     ///\param name Attribute name
     ///\param value Attribute value
-    template<class T> void setAttr(const std::string& name, T&& value)
+    template<class T> void setAttr(const std::string& name, const T& value)
     {
-        auto res = mAttrs.emplace(std::make_pair(name, libany::any(std::forward<T>(value))));
+        auto res = mAttrs.emplace(std::make_pair(name, libany::any(value)));
         if (!res.second)
-            res.first->second = std::move(libany::any(std::forward<T>(value)));
+            res.first->second = libany::any(value);
 
 #ifdef PYBIND
         // We cannot handle Python object if the Python interpreter is not running
         if (Py_IsInitialized()) {
             // Keep a copy of the attribute in py::object that is updated everytime
-            auto resPy = mAttrsPy.emplace(std::make_pair(name, py::cast(std::forward<T>(value))));
+            auto resPy = mAttrsPy.emplace(std::make_pair(name, py::cast(value)));
             if (!resPy.second)
-                resPy.first->second = std::move(py::cast(std::forward<T>(value)));
+                resPy.first->second = std::move(py::cast(value));
         }
 #endif
     }
diff --git a/python_binding/utils/pybind_Parameter.cpp b/python_binding/utils/pybind_Parameter.cpp
index a15a7fc2f9a7c8e7cf3d916b574aed91ac3ef21c..2957876f31ad0781a36905cef3a5ae88934b6a8a 100644
--- a/python_binding/utils/pybind_Parameter.cpp
+++ b/python_binding/utils/pybind_Parameter.cpp
@@ -4,6 +4,18 @@
 
 namespace py = pybind11;
 namespace Aidge {
+DynamicAttributes test_DynamicAttributes_binding() {
+    DynamicAttributes attrs;
+    attrs.addAttr<int>("a", 42);
+    attrs.addAttr<std::string>("b", "test");
+    attrs.addAttr<std::vector<bool>>("c", {true, false, true});
+    return attrs;
+}
+
+double test_DynamicAttributes_binding_check(DynamicAttributes& attrs) {
+    return attrs.getAttr<double>("d");
+}
+
 void init_Attributes(py::module& m){
     py::class_<Attributes, std::shared_ptr<Attributes>>(m, "Attributes")
     .def("has_attr", &Attributes::hasAttr, py::arg("name"))
@@ -15,6 +27,10 @@ void init_Attributes(py::module& m){
     .def("add_attr", &DynamicAttributes::addAttrPy, py::arg("name"), py::arg("value"))
     .def("set_attr", &DynamicAttributes::setAttrPy, py::arg("name"), py::arg("value"))
     .def("del_attr", &DynamicAttributes::delAttr, py::arg("name"));
+
+    m.def("test_DynamicAttributes_binding", &test_DynamicAttributes_binding);
+    m.def("test_DynamicAttributes_binding_check", &test_DynamicAttributes_binding_check, py::arg("attrs"));
 }
+
 }