1 (2,) {}
1 (2, 3) {}
1 (2, 3, 4, 5) {}
+0 (1, 2) {}
+1 () {'d': 4, 'b': 2, 'c': 3, 'a': 1}
+{'b': 2, 'c': 3, 'a': 1}
+{'b': 2, 'c': 3, 'a': 1}
keyword parameter redefined: x
keyword parameter redefined: b
keywords must be strings
g(1, 2)
g(1, 2, 3)
g(1, 2, 3, *(4, 5))
+class Nothing: pass
+try:
+ g(*Nothing())
+except AttributeError, attr:
+ assert attr[0] == '__len__'
+else:
+ print "should raise AttributeError: __len__"
+
+class Nothing:
+ def __len__(self):
+ return 5
+try:
+ g(*Nothing())
+except AttributeError, attr:
+ assert attr[0] == '__getitem__'
+else:
+ print "should raise AttributeError: __getitem__"
+
+class Nothing:
+ def __len__(self):
+ return 5
+ def __getitem__(self, i):
+ if i < 3:
+ return i
+ else:
+ raise IndexError, i
+g(*Nothing())
+
+# make sure the function call doesn't stomp on the dictionary?
+d = {'a': 1, 'b': 2, 'c': 3}
+d2 = d.copy()
+assert d == d2
+g(1, d=4, **d)
+print d
+print d2
+assert d == d2, "function call modified dictionary"
+
+# what about willful misconduct?
+def saboteur(**kw):
+ kw['x'] = locals()
+d = {}
+saboteur(a=1, **d)
+assert d == {}
+
try:
g(1, 2, 3, **{'x':4, 'y':5})
except TypeError, err:
x = NULL;
break;
}
- nstar = PySequence_Length(stararg);
+ /* Convert abstract sequence to concrete tuple */
+ if (!PyTuple_Check(stararg)) {
+ PyObject *t = NULL;
+ t = PySequence_Tuple(stararg);
+ if (t == NULL) {
+ x = NULL;
+ break;
+ }
+ Py_DECREF(stararg);
+ stararg = t;
+ }
+ nstar = PyTuple_GET_SIZE(stararg);
if (nstar < 0) {
x = NULL;
break;
break;
}
}
+ else {
+ PyObject *d = PyDict_Copy(kwdict);
+ if (d == NULL) {
+ x = NULL;
+ break;
+ }
+ Py_DECREF(kwdict);
+ kwdict = d;
+ }
err = 0;
while (--nk >= 0) {
PyObject *value = POP();
break;
}
if (stararg) {
- PyObject *t = NULL;
int i;
- if (!PyTuple_Check(stararg)) {
- /* must be sequence to pass earlier test */
- t = PySequence_Tuple(stararg);
- if (t == NULL) {
- x = NULL;
- break;
- }
- Py_DECREF(stararg);
- stararg = t;
- }
for (i = 0; i < nstar; i++) {
PyObject *a = PyTuple_GET_ITEM(stararg, i);
Py_INCREF(a);