String representation of an identifier's name

Inyeol Lee inyeol.lee at siimage.com
Mon Jan 13 15:09:26 EST 2003


On Sun, Jan 12, 2003 at 01:34:47PM -0800, Boethius wrote:
> I think it easier to explain with an example, so here it goes:
> Assuming there's a function fn that does what I want, it would work like this:
> 
> g = 23
> foo = {'a':56}
> 
> fn(g) => 'g'
> fn(foo) => 'foo'
> 
> How can I write fn? O:-)
> -- 
> http://mail.python.org/mailman/listinfo/python-list

Attached code is part of my debugging utils. Sometimes it
goes wrong, but I know why, so It's fine.

Inyeol Lee

---

def XXX(*args):
    """
    Print debug information on each argument.

    It parses source line to get the variable names passed to it.
    If two or more debug calls are in the same line, it may not work
    correctly since it cannot tell which is which. For example;

    >>> XXX(a, b["foo"], "hi")      ##  OK.
    >>> XXX(locals())               ##  OK. inspect all local variables.
    >>> XXX(a); XXX(b)              ##  Error!
    >>> XXX(XXX(a))                 ##  Error!
    """
    import tokenize

    ##  Get caller's stack frame.
    frame = sys._getframe(1)

    ##  Parse source line to get argument names of XXX_.
    depth = -1
    varname = ""
    varnames = []
    for tok in _getsrcline(frame, frame.f_lineno, tknize=True):
        if tok[0] == tokenize.NL:
        ##  Newline for breaking long statement ignored.
            continue
        if depth > 0:
        ##  Args of XXX_().
            if tok[0] == tokenize.OP:
                if depth == 1 and tok[1] in [",", ")"]:
                    varnames.append(varname)
                    varname = ""
                    if tok[1] == ")": break
                    else: continue
                elif tok[1] in ["(", "{", "["]:
                    depth += 1
                elif tok[1] in [")", "}", "]"]:
                    depth -= 1
            varname += tok[1]
        elif depth == 0:
        ##  Args tuple of function XXX_.
            if tok[0] == tokenize.OP and tok[1] == "(":
                depth = 1
            else:
                depth = -1
        elif tok[0] == tokenize.NAME and tok[1] == "XXX":
        ##  Start of function XXX_.
            depth = 0
    else:
        varnames = [""] * len(args)

    ##  Print debug information.
    sys.stderr.write("DEBUG: frame %s in '%s' at line %d\n" %
        (frame.f_code.co_name, frame.f_code.co_filename, frame.f_lineno))
    if not args:
        sys.stderr.write("  nothing to inspect.\n")
        return
    for arg in args:
        sys.stderr.write("  %s <%s> = %s\n" %
            (varnames.pop(0), arg.__class__.__name__, repr(arg)))

def _getsrcline(frame, lineno, tknize=False):
    """
    Return source line set by lineno of given stack frame.

    It is almost equivalent to 'traceback.extract_stack(frame)[3]', but
    returns complete statement, rather than the first physical line of it.
    If 'tknize' is True, it returns token list instead of raw source.
    """
    import linecache
    import tokenize

    ##  Get frame source from lineno to end of given frame.
    src = linecache.getlines(frame.f_code.co_filename)[lineno-1:]
    ##  To emulate file.readline() using list.pop().
    src.append("")
    src.reverse()
    ##  Tokenize source up to the first logical newline, which indicates
    ##  end of current statement.
    toks = []
    for tok in tokenize.generate_tokens(src.pop):
        toks.append(tok)
        if tok[0] == tokenize.NEWLINE: break
    ##  Return source line.
    if tknize:
        return toks
    return "".join([tok[1] for tok in toks])





More information about the Python-list mailing list