Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7eea37e

Browse files
committed
At Guido's suggestion, here's a new C API function, PyObject_Dir(), like
__builtin__.dir(). Moved the guts from bltinmodule.c to object.c.
1 parent 2f760c3 commit 7eea37e

5 files changed

Lines changed: 167 additions & 138 deletions

File tree

Doc/api/api.tex

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,16 @@ \section{Object Protocol \label{object}}
17201720
descriptor value. Returns \code{-1} on failure.
17211721
\end{cfuncdesc}
17221722

1723+
\begin{cfuncdesc}{PyObject*}{PyObject_Dir}{PyObject *o}
1724+
This is equivalent to the Python expression \samp{dir(\var{o})},
1725+
returning a (possibly empty) list of strings appropriate for the
1726+
object argument, or \NULL{} in case of error.
1727+
If the argument is \NULL{}, this is like the Python \samp{dir()},
1728+
returning the names of the current locals; in this case, if no
1729+
execution frame is active then \NULL{} is returned but
1730+
\cfunction{PyErr_Occurred()} will return false.
1731+
\end{cfuncdesc}
1732+
17231733

17241734
\section{Number Protocol \label{number}}
17251735

Include/object.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,14 @@ extern DL_IMPORT(int) PyNumber_CoerceEx(PyObject **, PyObject **);
346346

347347
extern DL_IMPORT(void) (*PyObject_ClearWeakRefs)(PyObject *);
348348

349+
/* PyObject_Dir(obj) acts like Python __builtin__.dir(obj), returning a
350+
list of strings. PyObject_Dir(NULL) is like __builtin__.dir(),
351+
returning the names of the current locals. In this case, if there are
352+
no current locals, NULL is returned, and PyErr_Occurred() is false.
353+
*/
354+
extern DL_IMPORT(PyObject *) PyObject_Dir(PyObject *);
355+
356+
349357
/* Helpers for printing recursive container types */
350358
extern DL_IMPORT(int) Py_ReprEnter(PyObject *);
351359
extern DL_IMPORT(void) Py_ReprLeave(PyObject *);

Misc/NEWS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ Tools
9696

9797
Build
9898

99-
API
99+
C API
100+
101+
- New function PyObject_Dir(obj), like Python __builtin__.dir(obj).
100102

101103
- Note that PyLong_AsDouble can fail! This has always been true, but no
102104
callers checked for it. It's more likely to fail now, because overflow

Objects/object.c

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,6 +1357,151 @@ PyCallable_Check(PyObject *x)
13571357
}
13581358
}
13591359

1360+
/* Helper for PyObject_Dir.
1361+
Merge the __dict__ of aclass into dict, and recursively also all
1362+
the __dict__s of aclass's base classes. The order of merging isn't
1363+
defined, as it's expected that only the final set of dict keys is
1364+
interesting.
1365+
Return 0 on success, -1 on error.
1366+
*/
1367+
1368+
static int
1369+
merge_class_dict(PyObject* dict, PyObject* aclass)
1370+
{
1371+
PyObject *classdict;
1372+
PyObject *bases;
1373+
1374+
assert(PyDict_Check(dict));
1375+
assert(aclass);
1376+
1377+
/* Merge in the type's dict (if any). */
1378+
classdict = PyObject_GetAttrString(aclass, "__dict__");
1379+
if (classdict == NULL)
1380+
PyErr_Clear();
1381+
else {
1382+
int status = PyDict_Update(dict, classdict);
1383+
Py_DECREF(classdict);
1384+
if (status < 0)
1385+
return -1;
1386+
}
1387+
1388+
/* Recursively merge in the base types' (if any) dicts. */
1389+
bases = PyObject_GetAttrString(aclass, "__bases__");
1390+
if (bases != NULL) {
1391+
int i, n;
1392+
assert(PyTuple_Check(bases));
1393+
n = PyTuple_GET_SIZE(bases);
1394+
for (i = 0; i < n; i++) {
1395+
PyObject *base = PyTuple_GET_ITEM(bases, i);
1396+
if (merge_class_dict(dict, base) < 0) {
1397+
Py_DECREF(bases);
1398+
return -1;
1399+
}
1400+
}
1401+
Py_DECREF(bases);
1402+
}
1403+
return 0;
1404+
}
1405+
1406+
/* Like __builtin__.dir(arg). See bltinmodule.c's builtin_dir for the
1407+
docstring, which should be kept in synch with this implementation. */
1408+
1409+
PyObject *
1410+
PyObject_Dir(PyObject *arg)
1411+
{
1412+
/* Set exactly one of these non-NULL before the end. */
1413+
PyObject *result = NULL; /* result list */
1414+
PyObject *masterdict = NULL; /* result is masterdict.keys() */
1415+
1416+
/* If NULL arg, return the locals. */
1417+
if (arg == NULL) {
1418+
PyObject *locals = PyEval_GetLocals();
1419+
if (locals == NULL)
1420+
goto error;
1421+
result = PyDict_Keys(locals);
1422+
if (result == NULL)
1423+
goto error;
1424+
}
1425+
1426+
/* Elif this is some form of module, we only want its dict. */
1427+
else if (PyObject_TypeCheck(arg, &PyModule_Type)) {
1428+
masterdict = PyObject_GetAttrString(arg, "__dict__");
1429+
if (masterdict == NULL)
1430+
goto error;
1431+
assert(PyDict_Check(masterdict));
1432+
}
1433+
1434+
/* Elif some form of type or class, grab its dict and its bases.
1435+
We deliberately don't suck up its __class__, as methods belonging
1436+
to the metaclass would probably be more confusing than helpful. */
1437+
else if (PyType_Check(arg) || PyClass_Check(arg)) {
1438+
masterdict = PyDict_New();
1439+
if (masterdict == NULL)
1440+
goto error;
1441+
if (merge_class_dict(masterdict, arg) < 0)
1442+
goto error;
1443+
}
1444+
1445+
/* Else look at its dict, and the attrs reachable from its class. */
1446+
else {
1447+
PyObject *itsclass;
1448+
/* Create a dict to start with. CAUTION: Not everything
1449+
responding to __dict__ returns a dict! */
1450+
masterdict = PyObject_GetAttrString(arg, "__dict__");
1451+
if (masterdict == NULL) {
1452+
PyErr_Clear();
1453+
masterdict = PyDict_New();
1454+
}
1455+
else if (!PyDict_Check(masterdict)) {
1456+
Py_DECREF(masterdict);
1457+
masterdict = PyDict_New();
1458+
}
1459+
else {
1460+
/* The object may have returned a reference to its
1461+
dict, so copy it to avoid mutating it. */
1462+
PyObject *temp = PyDict_Copy(masterdict);
1463+
Py_DECREF(masterdict);
1464+
masterdict = temp;
1465+
}
1466+
if (masterdict == NULL)
1467+
goto error;
1468+
1469+
/* Merge in attrs reachable from its class.
1470+
CAUTION: Not all objects have a __class__ attr. */
1471+
itsclass = PyObject_GetAttrString(arg, "__class__");
1472+
if (itsclass == NULL)
1473+
PyErr_Clear();
1474+
else {
1475+
int status = merge_class_dict(masterdict, itsclass);
1476+
Py_DECREF(itsclass);
1477+
if (status < 0)
1478+
goto error;
1479+
}
1480+
}
1481+
1482+
assert((result == NULL) ^ (masterdict == NULL));
1483+
if (masterdict != NULL) {
1484+
/* The result comes from its keys. */
1485+
assert(result == NULL);
1486+
result = PyDict_Keys(masterdict);
1487+
if (result == NULL)
1488+
goto error;
1489+
}
1490+
1491+
assert(result);
1492+
if (PyList_Sort(result) != 0)
1493+
goto error;
1494+
else
1495+
goto normal_return;
1496+
1497+
error:
1498+
Py_XDECREF(result);
1499+
result = NULL;
1500+
/* fall through */
1501+
normal_return:
1502+
Py_XDECREF(masterdict);
1503+
return result;
1504+
}
13601505

13611506
/*
13621507
NoObject is usable as a non-NULL undefined value, used by the macro None.

Python/bltinmodule.c

Lines changed: 1 addition & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -426,150 +426,14 @@ the effects of any future statements in effect in the code calling\n\
426426
compile; if absent or zero these statements do influence the compilation,\n\
427427
in addition to any features explicitly specified.";
428428

429-
/* Merge the __dict__ of aclass into dict, and recursively also all
430-
the __dict__s of aclass's base classes. The order of merging isn't
431-
defined, as it's expected that only the final set of dict keys is
432-
interesting.
433-
Return 0 on success, -1 on error.
434-
*/
435-
436-
static int
437-
merge_class_dict(PyObject* dict, PyObject* aclass)
438-
{
439-
PyObject *classdict;
440-
PyObject *bases;
441-
442-
assert(PyDict_Check(dict));
443-
assert(aclass);
444-
445-
/* Merge in the type's dict (if any). */
446-
classdict = PyObject_GetAttrString(aclass, "__dict__");
447-
if (classdict == NULL)
448-
PyErr_Clear();
449-
else {
450-
int status = PyDict_Update(dict, classdict);
451-
Py_DECREF(classdict);
452-
if (status < 0)
453-
return -1;
454-
}
455-
456-
/* Recursively merge in the base types' (if any) dicts. */
457-
bases = PyObject_GetAttrString(aclass, "__bases__");
458-
if (bases != NULL) {
459-
int i, n;
460-
assert(PyTuple_Check(bases));
461-
n = PyTuple_GET_SIZE(bases);
462-
for (i = 0; i < n; i++) {
463-
PyObject *base = PyTuple_GET_ITEM(bases, i);
464-
if (merge_class_dict(dict, base) < 0) {
465-
Py_DECREF(bases);
466-
return -1;
467-
}
468-
}
469-
Py_DECREF(bases);
470-
}
471-
return 0;
472-
}
473-
474429
static PyObject *
475430
builtin_dir(PyObject *self, PyObject *args)
476431
{
477432
PyObject *arg = NULL;
478-
/* Set exactly one of these non-NULL before the end. */
479-
PyObject *result = NULL; /* result list */
480-
PyObject *masterdict = NULL; /* result is masterdict.keys() */
481433

482434
if (!PyArg_ParseTuple(args, "|O:dir", &arg))
483435
return NULL;
484-
485-
/* If no arg, return the locals. */
486-
if (arg == NULL) {
487-
PyObject *locals = PyEval_GetLocals();
488-
if (locals == NULL)
489-
goto error;
490-
result = PyDict_Keys(locals);
491-
if (result == NULL)
492-
goto error;
493-
}
494-
495-
/* Elif this is some form of module, we only want its dict. */
496-
else if (PyObject_TypeCheck(arg, &PyModule_Type)) {
497-
masterdict = PyObject_GetAttrString(arg, "__dict__");
498-
if (masterdict == NULL)
499-
goto error;
500-
assert(PyDict_Check(masterdict));
501-
}
502-
503-
/* Elif some form of type or class, grab its dict and its bases.
504-
We deliberately don't suck up its __class__, as methods belonging
505-
to the metaclass would probably be more confusing than helpful. */
506-
else if (PyType_Check(arg) || PyClass_Check(arg)) {
507-
masterdict = PyDict_New();
508-
if (masterdict == NULL)
509-
goto error;
510-
if (merge_class_dict(masterdict, arg) < 0)
511-
goto error;
512-
}
513-
514-
/* Else look at its dict, and the attrs reachable from its class. */
515-
else {
516-
PyObject *itsclass;
517-
/* Create a dict to start with. CAUTION: Not everything
518-
responding to __dict__ returns a dict! */
519-
masterdict = PyObject_GetAttrString(arg, "__dict__");
520-
if (masterdict == NULL) {
521-
PyErr_Clear();
522-
masterdict = PyDict_New();
523-
}
524-
else if (!PyDict_Check(masterdict)) {
525-
Py_DECREF(masterdict);
526-
masterdict = PyDict_New();
527-
}
528-
else {
529-
/* The object may have returned a reference to its
530-
dict, so copy it to avoid mutating it. */
531-
PyObject *temp = PyDict_Copy(masterdict);
532-
Py_DECREF(masterdict);
533-
masterdict = temp;
534-
}
535-
if (masterdict == NULL)
536-
goto error;
537-
538-
/* Merge in attrs reachable from its class.
539-
CAUTION: Not all objects have a __class__ attr. */
540-
itsclass = PyObject_GetAttrString(arg, "__class__");
541-
if (itsclass == NULL)
542-
PyErr_Clear();
543-
else {
544-
int status = merge_class_dict(masterdict, itsclass);
545-
Py_DECREF(itsclass);
546-
if (status < 0)
547-
goto error;
548-
}
549-
}
550-
551-
assert((result == NULL) ^ (masterdict == NULL));
552-
if (masterdict != NULL) {
553-
/* The result comes from its keys. */
554-
assert(result == NULL);
555-
result = PyDict_Keys(masterdict);
556-
if (result == NULL)
557-
goto error;
558-
}
559-
560-
assert(result);
561-
if (PyList_Sort(result) != 0)
562-
goto error;
563-
else
564-
goto normal_return;
565-
566-
error:
567-
Py_XDECREF(result);
568-
result = NULL;
569-
/* fall through */
570-
normal_return:
571-
Py_XDECREF(masterdict);
572-
return result;
436+
return PyObject_Dir(arg);
573437
}
574438

575439
static char dir_doc[] =

0 commit comments

Comments
 (0)