Skip to content

Commit 5f66fd1

Browse files
author
AlexanderMueller
committed
changes from review
1 parent 7b9d61f commit 5f66fd1

File tree

2 files changed

+29
-15
lines changed

2 files changed

+29
-15
lines changed

include/pybind11/functional.h

+18-15
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ struct type_caster<std::function<Return(Args...)>> {
5959
rec = c.get_pointer<function_record>();
6060
}
6161
while (rec != nullptr) {
62-
const int correctingSelfArgument = rec->is_method ? 1 : 0;
63-
if (rec->nargs - correctingSelfArgument != sizeof...(Args)) {
62+
const int self_offset = rec->is_method ? 1 : 0;
63+
if (rec->nargs != sizeof...(Args) + self_offset) {
6464
rec = rec->next;
6565
// if the overload is not feasible in terms of number of arguments, we
6666
// continue to the next one. If there is no next one, we return false.
@@ -86,31 +86,34 @@ struct type_caster<std::function<Return(Args...)>> {
8686
// See PR #1413 for full details
8787
} else {
8888
// Check number of arguments of Python function
89-
auto getArgCount = [&](PyObject *obj) {
90-
// This is faster then doing import inspect and inspect.signature(obj).parameters
91-
auto *t = PyObject_GetAttrString(obj, "__code__");
92-
auto *argCount = PyObject_GetAttrString(t, "co_argcount");
93-
return PyLong_AsLong(argCount);
89+
auto argCountFromFuncCode = [&](handle &obj) {
90+
// This is faster then doing import inspect and
91+
// inspect.signature(obj).parameters
92+
93+
object argCount = obj.attr("co_argcount");
94+
return argCount.template cast<long>();
9495
};
9596
long argCount = -1;
9697

97-
if (static_cast<bool>(PyObject_HasAttrString(src.ptr(), "__code__"))) {
98-
argCount = getArgCount(src.ptr());
98+
handle codeAttr = PyObject_GetAttrString(src.ptr(), "__code__");
99+
if (codeAttr) {
100+
argCount = argCountFromFuncCode(codeAttr);
99101
} else {
100-
if (static_cast<bool>(PyObject_HasAttrString(src.ptr(), "__call__"))) {
101-
auto *t2 = PyObject_GetAttrString(src.ptr(), "__call__");
102-
argCount = getArgCount(t2) - 1; // we have to remove the self argument
102+
handle callAttr = PyObject_GetAttrString(src.ptr(), "__call__");
103+
if (callAttr) {
104+
handle codeAttr2 = callAttr.attr("__code__");
105+
argCount = argCountFromFuncCode(codeAttr2)
106+
- 1; // we have to remove the self argument
103107
} else {
104108
// No __code__ or __call__ attribute, this is not a proper Python function
105109
return false;
106110
}
107111
}
108112
// if we are a method, we have to correct the argument count since we are not counting
109113
// the self argument
110-
const int correctingSelfArgument
111-
= static_cast<bool>(PyMethod_Check(src.ptr())) ? 1 : 0;
114+
const int self_offset = static_cast<bool>(PyMethod_Check(src.ptr())) ? 1 : 0;
112115

113-
argCount -= correctingSelfArgument;
116+
argCount -= self_offset;
114117
if (argCount != sizeof...(Args)) {
115118
return false;
116119
}

tests/test_callbacks.py

+11
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,24 @@ def test_cpp_correct_overload_resolution():
107107
def f(a):
108108
return a
109109

110+
class A:
111+
def __call__(self, a):
112+
return a
113+
110114
assert m.dummy_function_overloaded_std_func_arg(f) == 9
115+
assert m.dummy_function_overloaded_std_func_arg(A()) == 9
111116
assert m.dummy_function_overloaded_std_func_arg(lambda i: i) == 9
112117

118+
113119
def f2(a, b):
114120
return a + b
115121

122+
class B:
123+
def __call__(self, a, b):
124+
return a + b
125+
116126
assert m.dummy_function_overloaded_std_func_arg(f2) == 14
127+
assert m.dummy_function_overloaded_std_func_arg(B()) == 14
117128
assert m.dummy_function_overloaded_std_func_arg(lambda i, j: i + j) == 14
118129

119130

0 commit comments

Comments
 (0)