code: def on_attribute(self, node):    # ('value', 'attr', 'ctx')
          
          ctx = node.ctx.__class__
          if ctx == ast.Store:
              msg = "attribute for storage: shouldn't be here!"
              self.raise_exception(node, exc=RuntimeError, msg=msg)
  
          sym = self.run(node.value)
          if ctx == ast.Del:
              return delattr(sym, node.attr)
  
          # ctx is ast.Load
          fmt = "cannnot access attribute '%s' for %s"
          if node.attr not in UNSAFE_ATTRS:
              fmt = "no attribute '%s' for %s"
              try:
                  return getattr(sym, node.attr)
              except AttributeError:
                  pass
  
          # AttributeError or accessed unsafe attribute
          obj = self.run(node.value)
          msg = fmt % (node.attr, obj)
          self.raise_exception(node, exc=AttributeError, msg=msg)
docs: Extract attribute.