Changing a character in a string at a specified index position Could you please tell me what you liked or may have disliked about this code? What can be made better?

#!/usr/bin/python3

def change_char_at(ch, s, indx):
    """
    Strings in Python are immutable objects. So, it is not possible to change a
    certain character in a string in place. For example, an attempt to run the
    following code will fail with a TypeError:

        s = "spam"
        s[1] = "z" # TypeError: 'str' object does not support item assignment

    What this function does is it provides you with a nice interface when you
    want to change a character in a string at a certain index position. So, use
    this function instead of doing everything manually which can sometimes be
    tricky. Notice that the character parameter does not necessarily have to be
    one character long. It can be an empty string which means that a character
    at a certain position will effectively be deleted from the string. If it's
    more than one character long, then they all will be inserted into the string
    starting at the specified index position.

    Parameters:
    ch:   character to insert
    s:    string to insert into
    indx: index position where to insert the character
    """
    # Error handling
    if type(ch) is not str:
        raise TypeError("first argument must be a string")
    if type(s) is not str or not len(s) &gt; 0:
        raise TypeError("second argument must be a non-empty string")

    length = len(s) - 1
    if not(indx &gt;= 0 and indx &lt;= length):
        msg  = "string index out of range; "
        msg += "attempt to access index at {0}; ".format(indx)
        msg += "allowable index range 0 to {0}".format(length)
        raise IndexError(msg)

    # Actual function logic
    return s[:indx] + ch + s[indx + 1:]
    """
    Another possible implementation:

        ls       = list(s)
        ls[indx] = ch
        return ''.join(ls)

    This works well too and is equally good, but might be conspired unpythonic
    by some compared to the one right above it.
    """


def main():
    my_string = "spam"
    my_string = change_char_at("z", my_string, 1)
    print(my_string) # prints "szam"


if __name__ == "__main__": main()
The fact that your function is named change_char_at and the first parameter is named ch both suggest that ch should be a single character.  However, the function could easily be abused to splice in any number of characters at that location, including zero.  So, you might as well make it obvious and rename the function to string_splice() or something.

I'm not a fan of this function, though.  Basically, it's a long-winded way to do s[:indx] + ch + s[indx + 1:] with some validation.


if type(ch) is not str seems pointless.  If ch is not a string, it would naturally fail with a TypeError anyway during concatenation.
if type(s) is not str might be useful validation, but it also goes against Python's duck-typing philosophy.
if … not len(s) &gt; 0 is an unjustified special case.  If you're going to allow splicing in an arbitrary number of characters, then why shouldn't one be allowed to add something to an empty string?  As a consequence of this failure case, the caller will also need to put in a special case to work around this restriction.
if not(indx &gt;= 0 and indx &lt;= length) is weird because length isn't actually the length of the string; it's one less than that.  It could be more succinctly written as if not 0 &lt;= indx &lt; len(s).  But Python's negative indexing is a feature, not a bug.  Why would you want to defeat the convenience?


In summary, if you want to do s[:indx] + ch + s[indx + 1:], then it's probably best to just write that.  If you want to write this function anyway, I recommend dropping most, if not all, of the validation.

If you want to do a lot of single-character replacements, then you would probably want to convert the string to a list or bytestring instead.