Finding Functions Defined in a with: Block

后端 未结 2 1191
无人及你
无人及你 2021-02-01 09:54

Here\'s some code from Richard Jones\' Blog:

with gui.vertical:
    text = gui.label(\'hello!\')
    items = gui.selection([\'one\', \'two\', \'three\'])
    wit         


        
2条回答
  •  不思量自难忘°
    2021-02-01 10:19

    Here's one way:

    from __future__ import with_statement
    import inspect
    
    class button(object):
      def __enter__(self):
        # keep track of all that's already defined BEFORE the `with`
        f = inspect.currentframe(1)
        self.mustignore = dict(f.f_locals)
    
      def __exit__(self, exc_type, exc_value, traceback):
        f = inspect.currentframe(1)
        # see what's been bound anew in the body of the `with`
        interesting = dict()
        for n in f.f_locals:
          newf = f.f_locals[n]
          if n not in self.mustignore:
            interesting[n] = newf
            continue
          anf = self.mustignore[n]
          if id(newf) != id(anf):
            interesting[n] = newf
        if interesting:
          print 'interesting new things: %s' % ', '.join(sorted(interesting))
          for n, v in interesting.items():
            if isinstance(v, type(lambda:None)):
              print 'function %r' % n
              print v()
        else:
          print 'nothing interesting'
    
    def main():
      for i in (1, 2):
        def ignorebefore():
          pass
        with button():
          def testing(i=i):
            return i
        def ignoreafter():
          pass
    
    main()
    

    Edit: stretched code a bit more, added some explanation...:

    Catching caller's locals at __exit__ is easy -- trickier is avoiding those locals that were already defined before the with block, which is why I added to main two local functions that the with should ignore. I'm not 100% happy with this solution, which looks a bit complicated, but I couldn't get equality testing correct with either == or is, so I resorted to this rather complicated approach.

    I've also added a loop (to make more strongly sure the defs before / within / after are being properly handled) and a type-check and function-call to make sure the right incarnation of testing is the one that's identified (everything seems to work fine) -- of course the code as written only works if the def inside the with is for a function callable without arguments, it's not hard to get the signature with inspect to ward against that (but since I'm doing the call only for the purpose of checking that the right function objects are identified, I didn't bother about this last refinement;-).

提交回复
热议问题