docs: def replace(self, *args, **kwargs):
          """
          replace(lower=None, upper=None, lower_inc=None, upper_inc=None)
  
          Returns a new instance of self with the given arguments replaced. It
          takes the exact same arguments as the constructor.
  
              >>> intrange(1, 5).replace(upper=10)
              intrange([1,10))
              >>> intrange(1, 10).replace(lower_inc=False)
              intrange([2,10))
              >>> intrange(1, 10).replace(5)
              intrange([5,10))
  
          Note that range objects are immutable and are never modified in place.
          """
  
          replacements = {
              "lower" : self.lower,
              "upper" : self.upper,
              "lower_inc" : self.lower_inc,
              "upper_inc" : self.upper_inc
          }
          replacements.update(
              dict(zip(("lower", "upper", "lower_inc", "upper_inc"), args)))
          replacements.update(kwargs)
  
          return self.__class__(**replacements)