Add new feature "python:cdefaultargs"
Controls default argument code generation to obtain the default arguments from the C++ layer instead of the Python layer.
This commit is contained in:
parent
986a13f1a0
commit
b8e1a66a38
5 changed files with 153 additions and 3 deletions
|
|
@ -5,7 +5,41 @@ See the RELEASENOTES file for a summary of changes in each release.
|
||||||
Version 3.0.6 (in progress)
|
Version 3.0.6 (in progress)
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
2015-05-07: wsfulton
|
2015-05-28: wsfulton
|
||||||
|
[Python] Add new feature "python:cdefaultargs" to control default argument
|
||||||
|
code generation. By default, SWIG attempts to convert C/C++ default argument values
|
||||||
|
into Python values and generates code into the Python layer with these values.
|
||||||
|
Recent versions of SWIG are able to convert more of these values, however, the
|
||||||
|
new behaviour can be circumvented if desired via this new feature, such that
|
||||||
|
the default argument values are obtained from the C layer and not the Python layer.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
struct CDA {
|
||||||
|
int fff(int a = 1, bool b = false);
|
||||||
|
};
|
||||||
|
|
||||||
|
The default code generation in the Python layer is:
|
||||||
|
|
||||||
|
class CDA(_object):
|
||||||
|
...
|
||||||
|
def fff(self, a=1, b=False):
|
||||||
|
return _default_args.CDA_fff(self, a, b)
|
||||||
|
|
||||||
|
Adding the feature:
|
||||||
|
|
||||||
|
%feature("python:cdefaultargs") CDA::fff;
|
||||||
|
|
||||||
|
Results in:
|
||||||
|
|
||||||
|
class CDA(_object):
|
||||||
|
...
|
||||||
|
def fff(self, *args):
|
||||||
|
return _default_args.CDA_fff(self, *args)
|
||||||
|
|
||||||
|
Some code generation modes, eg -builtin and -fastproxy, are unaffected by this as
|
||||||
|
the default values are always obtained from the C layer.
|
||||||
|
|
||||||
|
2015-05-27: wsfulton
|
||||||
[Python] Deal with an integer as the default value of a typedef to bool
|
[Python] Deal with an integer as the default value of a typedef to bool
|
||||||
parameter in the C++ prototype. See #327. Regression from 3.0.0 onwards.
|
parameter in the C++ prototype. See #327. Regression from 3.0.0 onwards.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4147,6 +4147,105 @@ If you need to return binary data, you might use the
|
||||||
also be used to extra binary data from arbitrary pointers.
|
also be used to extra binary data from arbitrary pointers.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<H3><a name="Python_default_args"></a>Default arguments</H3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
C++ default argument code generation is documented in the main
|
||||||
|
<a href="SWIG.html#SWIGPlus_default_args">Default arguments</a> section.
|
||||||
|
There is also an optional Python specific feature that can be used called the <tt>python:cdefaultargs</tt>
|
||||||
|
<a href="Customization.html#Customization_feature_flags">feature flag</a>.
|
||||||
|
By default, SWIG attempts to convert C++ default argument values
|
||||||
|
into Python values and generates code into the Python layer containing these values.
|
||||||
|
For example:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
struct CDA {
|
||||||
|
int fff(int a = 1, bool b = false);
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
From Python this can be called as follows:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="targetlang">
|
||||||
|
<pre>
|
||||||
|
>>> CDA().fff() # C++ layer receives a=1 and b=false
|
||||||
|
>>> CDA().fff(2) # C++ layer receives a=2 and b=false
|
||||||
|
>>> CDA().fff(3, True) # C++ layer receives a=3 and b=true
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The default code generation in the Python layer is:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="targetlang">
|
||||||
|
<pre>
|
||||||
|
class CDA(object):
|
||||||
|
...
|
||||||
|
def fff(self, a=1, b=False):
|
||||||
|
return _default_args.CDA_fff(self, a, b)
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Adding the feature:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
%feature("python:cdefaultargs") CDA::fff;
|
||||||
|
struct CDA {
|
||||||
|
int fff(int a = 1, bool b = false);
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
results in identical behaviour when called from Python, however, it results in different code generation:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="targetlang">
|
||||||
|
<pre>
|
||||||
|
class CDA(object):
|
||||||
|
...
|
||||||
|
def fff(self, *args):
|
||||||
|
return _default_args.CDA_fff(self, *args)
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The default arguments are obtained in the C++ wrapper layer instead of the Python layer.
|
||||||
|
Some code generation modes are quite different, eg <tt>-builtin</tt> and <tt>-fastproxy</tt>,
|
||||||
|
and are unaffected by <tt>python:cdefaultargs</tt> as the default values are always obtained from the C++ layer.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Note that not all default arguments can be converted into a Python equivalent.
|
||||||
|
When SWIG does not convert them, it will generate code to obtain them from the C++ layer as if
|
||||||
|
<tt>python:cdefaultargs</tt> was specified.
|
||||||
|
This will happen if just one argument cannot be converted into a Python equivalent.
|
||||||
|
This occurs typically when the argument is not fully numeric, such as <tt>int(1)</tt>:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code">
|
||||||
|
<pre>
|
||||||
|
struct CDA {
|
||||||
|
int fff(int a = int(1), bool b = false);
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Compatibility Note:</b> SWIG-3.0.6 introduced the <tt>python:cdefaultargs</tt> feature.
|
||||||
|
Versions of SWIG prior to this varied in their ability to convert C++ default values into
|
||||||
|
equivalent Python default argument values.
|
||||||
|
</p>
|
||||||
|
|
||||||
<H2><a name="Python_nn53"></a>36.8 Typemaps</H2>
|
<H2><a name="Python_nn53"></a>36.8 Typemaps</H2>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -292,3 +292,12 @@ struct ConstMethods {
|
||||||
inline int slightly_off_square(int square_error, int def17) { return def17*def17 + square_error; }
|
inline int slightly_off_square(int square_error, int def17) { return def17*def17 + square_error; }
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
// Python C default args
|
||||||
|
%feature("python:cdefaultargs") CDA::cdefaultargs_test1;
|
||||||
|
%inline %{
|
||||||
|
struct CDA {
|
||||||
|
int cdefaultargs_test1(int a = 1) { return a; }
|
||||||
|
int cdefaultargs_test2(int a = 1) { return a; }
|
||||||
|
};
|
||||||
|
%}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,13 @@ def run(module_name):
|
||||||
if default_args.slightly_off_square() != 291:
|
if default_args.slightly_off_square() != 291:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|
||||||
|
# It is difficult to test the python:cdefaultargs feature properly as -builtin
|
||||||
|
# and -fastproxy do not use the Python layer for default args
|
||||||
|
if default_args.CDA().cdefaultargs_test1() != 1:
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
if default_args.CDA().cdefaultargs_test2() != 1:
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run('default_args')
|
run('default_args')
|
||||||
|
|
|
||||||
|
|
@ -2082,9 +2082,10 @@ public:
|
||||||
|
|
||||||
1. The function is overloaded as Python doesn't support this.
|
1. The function is overloaded as Python doesn't support this.
|
||||||
2. We were explicitly asked to use the "compact" arguments form.
|
2. We were explicitly asked to use the "compact" arguments form.
|
||||||
3. One of the default argument values can't be represented in Python.
|
3. We were explicitly asked to use default args from C via the "python:cdefaultargs" feature.
|
||||||
|
4. One of the default argument values can't be represented in Python.
|
||||||
*/
|
*/
|
||||||
if (is_real_overloaded(n) || GetFlag(n, "feature:compactdefaultargs") || !is_representable_as_pyargs(n)) {
|
if (is_real_overloaded(n) || GetFlag(n, "feature:compactdefaultargs") || GetFlag(n, "feature:python:cdefaultargs") || !is_representable_as_pyargs(n)) {
|
||||||
String *parms = NewString("");
|
String *parms = NewString("");
|
||||||
if (in_class)
|
if (in_class)
|
||||||
Printf(parms, "self, ");
|
Printf(parms, "self, ");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue