class_docstr: Keeps track of overall time and split/lap times.
  
  >>> import time
  >>> timer = Timer()
  >>> time.sleep(0.01)
  >>> print("First lap:", timer.split())
  First lap: ...
  >>> time.sleep(0.02)
  >>> print("Second lap:", timer.split())
  Second lap: ...
  >>> print("Overall time:", timer.time())
  Overall time: ...
  
  Can be used as a context manager inside with-statements.
  
  >>> with Timer() as t:
  ...     time.sleep(0.01)
  >>> print("%0.3f seconds" % t.elapsed)
  0... seconds
  
  If initialised with a logger, it can log the elapsed time automatically
  upon exiting the with-statement.
  
  >>> import logging
  >>> log = logging.getLogger("my-fancy-timer-logger")
  >>> configLogger(logger=log, level="DEBUG", format="%(message)s", stream=sys.stdout)
  >>> with Timer(log, 'do something'):
  ...     time.sleep(0.01)
  Took ... to do something
  
  The same Timer instance, holding a reference to a logger, can be reused
  in multiple with-statements, optionally with different messages or levels.
  
  >>> timer = Timer(log)
  >>> with timer():
  ...     time.sleep(0.01)
  elapsed time: ...s
  >>> with timer('redo it', level=logging.INFO):
  ...     time.sleep(0.02)
  Took ... to redo it
  
  It can also be used as a function decorator to log the time elapsed to run
  the decorated function.
  
  >>> @timer()
  ... def test1():
  ...    time.sleep(0.01)
  >>> @timer('run test 2', level=logging.INFO)
  ... def test2():
  ...    time.sleep(0.02)
  >>> test1()
  Took ... to run 'test1'
  >>> test2()
  Took ... to run test 2
docstr: If the first argument is a function, return a decorator which runs
  the wrapped function inside Timer's context manager.
  Otherwise, treat the first argument as a 'msg' string and return an updated
  Timer instance, referencing the same logger.
  A 'level' keyword can also be passed to override self.level.
docstr_tok: ["If","the","first","argument","is","a","function",",","return","a","decorator","which","runs","the","wrapped","function","inside","Timer","'s","context","manager",".","Otherwise",",","treat","the","first","argument","as","a","'msg","'","string","and","return","an","updated","Timer","instance",",","referencing","the","same","logger",".","A","'level","'","keyword","can","also","be","passed","to","override","self.level","."]
code: def __call__(self, func_or_msg=None, **kwargs):
      """If the first argument is a function, return a decorator which runs
      the wrapped function inside Timer's context manager.
      Otherwise, treat the first argument as a 'msg' string and return an updated
      Timer instance, referencing the same logger.
      A 'level' keyword can also be passed to override self.level.
      """
      if isinstance(func_or_msg, Callable):
          func = func_or_msg
          # use the function name when no explicit 'msg' is provided
          if not self.msg:
              self.msg = "run '%s'" % func.__name__
  
          @wraps(func)
          def wrapper(*args, **kwds):
              with self:
                  return func(*args, **kwds)
  
          return wrapper
      else:
          msg = func_or_msg or kwargs.get("msg")
          level = kwargs.get("level", self.level)
          return self.__class__(self.logger, msg, level)
  
imports: import sys
  import logging
  import timeit
  from functools import wraps
  from collections.abc import Mapping, Callable
  import warnings
  from logging import PercentStyle
label_desc: Use image node_id 8 for calling the Timer obj's underlying member method code with example usage: obj.__call__(func_or_msg) and returns: wrapper, self, func