Help with changes in traceback stack from Python 2.7 to Python 3.x

Andrew Konstantaras akonsta at icloud.com
Sun Apr 27 14:56:39 EDT 2014


Thanks for the response and I can certainly see that this old code can be improved, but I respectfully disagree on the utility of this function.  The flexibility of passing any number of arguments to the function and returning a dictionary is much easier than writing out dict(x=x, y=y, ...n=n).  I also believe that "makeDict" makes my code very readable.

My question is around finding the names of the variables passed to a function from within the function.  I have spent many hours looking on the web looking for where in the frames and stacks this information is stored.  Does anyone have any insight where/how I can find the variables associated with the arguments in

      dctA = makeDict(strA, intA)

from within the function

      def makeDict(*args):
            .... #need to find the variable names "strA" and "intA" in this context

---Andrew


On Apr 26, 2014, at 05:10 AM, Ned Batchelder <ned at nedbatchelder.com> wrote:

> On 4/26/14 1:50 AM, Andrew Konstantaras wrote:
>        > I wrote the following code that works in Python 2.7 that takes the
>        > variables passed to the function into a dictionary. The following call:
>        >
>        > strA = 'a'
>        > intA = 1
>        > dctA = makeDict(strA, intA)
>        >
>        > produces the following dictionary:
>        >
>        > {'strA':'a', 'intA':1}
>        >
>        > To access the names passed into the function, I had to find the
>        > information by parsing through the stack. The code that used to work is:
>        >
>        > from traceback import extract_stack
>        >
>        > def makeDict(*args):
>        > strAllStack = str(extract_stack())
>        > intNumLevels = len(extract_stack())
>        > intLevel = 0
>        > blnFinished = False
>        > while not blnFinished:
>        > strStack = str(extract_stack()[intLevel])
>        > if strStack.find("makeDict(")  >0:
>        > blnFinished = True
>        > intLevel += 1
>        > if intLevel    >= intNumLevels:
>        > blnFinished = True
>        > strStartText = "= makeDict("
>        > intLen = len(strStartText)
>        > intOpenParenLoc = strStack.find(strStartText)
>        > intCloseParenLoc = strStack.find(")", intOpenParenLoc)
>        > strArgs = strStack[ intOpenParenLoc+intLen : intCloseParenLoc ].strip()
>        > lstVarNames = strArgs.split(",")
>        > lstVarNames = [ s.strip() for s in lstVarNames ]
>        > if len(lstVarNames) == len(args):
>        > tplArgs = map(None, lstVarNames, args)
>        > newDict = dict(tplArgs)
>        > return newDict
>        > else:
>        > return "Error, argument name-value mismatch in function 'makeDict'.
>        > lstVarNames: " + str(lstVarNames) + "\n args: " + str(args), strAllStack
>        >
>        > The same code does not work in Python 3.3.4. I have tried parsing
>        > through the stack information and frames and I can't find any reference
>        > to the names of the arguments passed to the function. I have tried
>        > inspecting the function and other functions in the standard modules, but
>        > I can't seem to find anything that will provide this information.
>
> 1) This is a very strange function. Instead of going to all this
> trouble, why not use:
>
> dctA = dict(strA=strA, intA=intA)
>
> Yes, you have to repeat the names, but you'd be done by now, it works on
> both versions of Python, and people reading your code would understand
> what it does.
>
> 2) Why is your code examining the entire stack? The frame you want is
> the one just above you. Why are you stringifying the tuple produced by
> extract_stack when the source line you want is the fourth element? Why
> are you using a while loop and a counter to iterate over elements of a list?
>
> 3) In the error case you return a tuple when the caller is expecting a
> dict? Why not raise an exception?
>
> 4) Your code only works if makeDict is assigned to a name. When I first
> tried it, I used "print(makeDict(...))", and it failed completely.
>
> 5) You haven't mentioned what goes wrong on Python 3, but when I tried
> it, I got:
>
> Traceback (most recent call last):
> File "foo3.py", line 34, in <module      >
> d = makeDict(a, b)
> File "foo3.py", line 27, in makeDict
> newDict = dict(list(tplArgs))
> TypeError: 'NoneType' object is not callable
>
> Looking at your code, I see:
>
> tplArgs = map(None, lstVarNames, args)
>
> I didn't realize map accepted a callable of None (TIL!), but it no
> longer does in Python 3. You'll have to do this a different way.
>
> But seriously: just use dict() and be done with it. There's a lot here
> that can be much simpler if you learn to use Python as it was meant to
> be used. You are swimming upstream, there are easier ways.
>
>        >
>        > Can anyone point me in the direction to find this information? Any help
>        > is appreciated.
>        >
>        > ---Andrew
>        >
>        >
>        >
>
>
> -- 
> Ned Batchelder, http://nedbatchelder.com
>
> -- 
> https://mail.python.org/mailman/listinfo/python-list
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20140427/811bd63a/attachment.html>


More information about the Python-list mailing list