Functions ######### Before proceeding with this section, make sure that you are already familiar with the basics of binding functions and classes, as explained in :doc:`/basics` and :doc:`/classes`. The following guide is applicable to both free and member functions, i.e. *methods* in Python. .. _return_value_policies: Return value policies ===================== Python and SystemVerilog use fundamentally different ways of managing the memory and lifetime of objects managed by them. This can lead to issues when creating bindings for functions that return a non-trivial type. When non-trivial type returned SystemVerilog should manage the object life time and deallocate the memory occupied by the object with :func:`py_object::delete` when the object is no longer needed. Return value policies are tricky, and it's very important to get them right. Just to illustrate what can go wrong, consider the following simple example: .. code-block:: systemverilog //equivalent to: from decimal import Decimal py_object Decimal = py_module::import_("decimal").attr("Decimal").obtain(); py_object decimal_exp = Decimal.attr("exp"); // Compute the e^n for n=0..4 for (int n = 0; n < 5; n++) begin py_object d = Decimal.call(py::int_(n)); py::print(py::str_("Result: "), decimal_exp.call(d)); end What's going on here? When ``decimal_exp.call(d)`` is called and the result object passed to ``py::print()`` function, the handler the result of ``decimal_exp.call(d)`` no longer available. Therefore it is not possible to access the result of ``decimal_exp.call(d)`` and deallocate the memory occupied by the object. The same issue occurs for the object ``d``. The the ``d.delete()`` function not called to deallocate the memory occupied by the object during the loop. Non trivial type objects should be deallocated by calling the :func:`py_object::delete` function. The Python garbage collector will not deallocate the memory occupied by the this objects since the object reference count is not zero. The proper way to write to the above code is to deallocate the memory occupied by the object ``d`` and the result of ``decimal_exp.call(d)``. .. code-block:: systemverilog //equivalent to: from decimal import Decimal py_object Decimal = py_module::import_("decimal").attr("Decimal").obtain(); py_object decimal_exp = Decimal.attr("exp"); // Compute the e^n for n=0..4 for (int n = 0; n < 5; n++) begin py_object d = Decimal.call(py::int_(n)); py_object result = decimal_exp.call(d); py::print(py::str_("Result: "), result); result.delete(); d.delete(); end .. _python_objects_as_args: Python objects as arguments =========================== PyStim exposes all major Python types using thin SystemVerilog wrapper classes. These wrapper classes can also be used as parameters of functions in bindings, which makes it possible to directly work with native Python types on the SystemVerilog side. For instance, the following statement iterates over a Python ``dict``: .. code-block:: systemverilog function void print_dict(py::py_dict dict); /* Easily interact with Python types */ iterator it = students_dict.get_iterator(); while(it.has_next())begin py_pair p = it.next().cast_dict_pair(); py_object key = p.get_key(); py_object value = p.get_value(); $display("Key: %s, Value: %s", key.cast_string().get_value(), value.cast_uint().get_value()); end endfunction .. note:: Currently, the SystemVerilog ``dict`` wrapper class supports only keys of type ``string``. For more information on using Python objects in SystemVerilog, see :doc:`/advanced/pysv/index`. Accepting \*args and \*\*kwargs =============================== Python provides a useful mechanism to define functions that accept arbitrary numbers of arguments and keyword arguments: .. code-block:: python def generic(*args, **kwargs): ... # do something with args and kwargs To call the Python function with args and kwargs, use SystemVerilog named arguments mapping: .. code-block:: systemverilog py_tuple args = ...; py_dict kwargs = ...; ... // do something with args and kwargs some_attribute.call(.args(args), .kwargs(kwargs)); The class ``py_args`` derives from ``py_tuple`` and ``py_kwargs`` derives from ``py_dict``. You may also use just one or the other, and may combine these with other arguments. Note, however, that ``args`` and ``kwargs`` must always be named mapped arguments. A demonstration of ``args`` and ``kwargs`` is available in ``examples/misc/test_args_and_kwargs.sv``.