[Tutor] str.replace error

Steven D'Aprano steve at pearwood.info
Fri Apr 26 00:29:01 EDT 2019


On Thu, Apr 25, 2019 at 10:46:31AM -0700, Roger Lea Scherer wrote:

> with open('somefile') as csvDataFile:
>     csvReader = csv.reader(csvDataFile)
>     for row in range(100):
>         a = "Basic P1"
>         str.replace(a, "")
>         print(next(csvReader))


I'm not quite sure what you expected this to do, but you've 
(deliberately? accidently?) run into one of the slightly advanced 
corners of Python: unbound methods. Apologies in advance, but this may 
be a bit technical. For a suggestion on how to fix the problem, see 
right at the end.

Normally when you call a string method, you do something like this:

mystring = "Something here"
newstring = mystring.replace("here", "there")

The technical name for the mystring.replace call is a "bound method", as 
the method is "bound" to a string instance (mystring). The method 
actually takes *three* arguments: the string to operate on, the 
substring to be replaced, and the replacement string:

   (string to operate on) . replace ( substring to be replaced, replacement )

But under the hood, what that turns into is an "unbound method" that 
calls the method attached to the *class* "str":

    str.replace(string to operate on, substring to replace, replacement)

Alas, when you call an *unbound* method like this:

    str.replace(a, "")

the interpreter may get a bit confused and report a slightly inaccurate 
error message:

> TypeError: replace() takes at least 2 arguments (1 given)

For technical reasons, all the counts are off by one. The error message 
should say:

    TypeError: replace() takes at least 3 arguments (2 given)

but because the same error message gets used for both bound and unbound 
methods, the counts are off for unbound methods. This is an annoyance, 
but given that unbound methods are relatively rare, not a large one.

So how do you fix your code?

(1) First of all, you need a string to operate on. I'm not sure which 
string that should be -- do you want to check *every* cell? Just the 
first cell in each row? Every second row? That's up to you to decide.

(2) Secondly, strings in Python are "immutable" -- that is to say, they 
cannot be changed in place. Unlike languages like (say) Pascal, if you 
want to change the value of a string, you need to re-assign a new 
string:

    a = "Hello World!"
    a.upper()  # Doesn't work!!!
    print(a)  # Still gives "Hello World!"

Instead you need to say a = a.upper().

(3) Unbound methods are a slightly advanced technique which you don't 
need here, so you should just use normal method call.



Putting those three changes together gives something like this:


with open('somefile') as csvDataFile:
    csvReader = csv.reader(csvDataFile)
    for row in range(100):  # How do you know there are only 100 rows?
        mystring = "Something here? ~Basic P1~ but I don't know what"
        print("Before:", mystring)
        mystring = mystring.replace("Basic P1", "")
        print("After:", mystring)
        print(next(csvReader))



Hopefully that's enough to set you on the right track. If not, please 
feel free to write back to the list and ask more questions!




-- 
Steven


More information about the Tutor mailing list