sergzach
sergzach

Reputation: 6764

PDB: Variable can be printed but is undefined

It looks strange. A variable with a name classes is printed but is undefined when trying to execute filter(...) contruction.

Here is a code:

def start(self, tag, attrib):
    classes = attrib[self._CLASS_ATTR] if self._CLASS_ATTR in attrib else None

    if tag == self._TAG_P:
        p = self._doc.add_paragraph('')

        self._cur_p = p

        if classes is not None:
            alignments = [self._left_align, self._center_align, self._right_align]
            import pdb; pdb.set_trace()
            alignments = filter(lambda x: partial(x.is_in, classes), alignments)
            if len(alignments) > 0:
                p.alignment = alignments[0].get()

            assert len(alignments) < 2

Pdb stops on it's break. When I try to execute filter():

(Pdb) print filter(lambda x: partial(x.is_in, classes), alignments)
*** NameError: global name 'classes' is not defined

But:

(Pdb) print classes
center title
(Pdb) classes
u'center title'

Why the filter(...) instruction could not be executed normally?

Let's reproduce it in short code:

from functools import partial

def f():
    classes = 'my_classes'

    def my_bool(obj, _):
        return True

    if classes is not None:
        import pdb; pdb.set_trace() # point a
        alignments = filter(lambda x: my_bool(x, classes), ['1', '2', '3'])
        import pdb; pdb.set_trace() # point b
        pass

f()

...

(Pdb) filter(lambda x: my_bool(x, classes), ['1', '2', '3'])
*** NameError: global name 'my_bool' is not defined

However, the command c (continue) of pdb in point a does not generate an exception.

Upvotes: 2

Views: 1030

Answers (1)

anthony sottile
anthony sottile

Reputation: 70147

pdb is an eval loop. An eval loop essentially takes what you write to the prompt line by line and eval(...)s it. This means it doesn't bind closure-scoped variables in defined functions (lambdas). eval (which is a function) has its own scope and doesn't participate in the closure you are evaluating in.

You can see the equivalent problem from this example code:

def f():
    x = 1
    return eval('lambda: x')

>>> f()()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <lambda>
NameError: name 'x' is not defined

An (unfortunate) workaround is to define any lambdas up-front and use them in your pdb expression.

Upvotes: 2

Related Questions