3

I am writing a python script that uses the string.replace() method a lot. I know that if I was importing a python method from a module I could change its name using from like so:

from time import sleep as x

And then, x(5) would be the same as time.sleep(5). But how can I do that to the replace() function? It isn't from any external module, and I have tried to do this:

x = replace()

But it doesn't work. It says NameError: name 'replace' is not defined.

So please tell me how to "rename" the built-in replace function.

3
  • 1
    Why would you use string.replace instead of the method replace on str objects? Unless you're writing Python 1.5… Commented Sep 16, 2014 at 0:33
  • Do you mean you want to change the use of replace in contexts like: s = "hello world"; s = s.replace('hello', 'goodbye') Commented Sep 16, 2014 at 0:35
  • The str class is a built-in extension, so you can't edit its namespace. You can, however, subclass it and define functionality however you like in the derived class. Commented Sep 16, 2014 at 0:40

3 Answers 3

5

First, you should almost never be using string.replace. As the docs say:

The following list of functions are also defined as methods of string and Unicode objects; see section String Methods for more information on those. You should consider these functions as deprecated…

Second, this is wrong for two separate reasons:

x = replace()

First, there is no builtin named replace, and there's no global in your module named replace either. If you did from string import * or from string import replace, then you wouldn't get this error—but if you were doing that, you could just do from string import replace as x, exactly as you're already doing for time.sleep.

Second, those parentheses mean that you're calling the function, and assigning its return value to x, not using the function itself as a value.


So, I think what you want is this:

x = str.replace

That's accessing the replace method on str objects, and storing it in x. An "unbound method" like this can be called by passing an instance of str (that is, any normal string) as the first argument. So:

x(my_string, ' ', '_')

If you want to add the name x as a method on the str class itself, what you want is called "monkeypatching", and normally, it's very simple:

str.x = str.replace

Unfortunately, it doesn't work with most of the built-in types, at least in CPython; you'll get an error like this:

TypeError: can't set attributes of built-in/extension type 'str'

You could of course create your own subclass of str, and use that all over the place instead of str… but that won't help with string literals, strings you get back from other functions, etc., unless you wrap them explicitly. And I'm not sure it's worth the effort. But if you want to:

class s(str):
    x = str.replace

Now you can do this:

z = s(function_returning_a_string())
z = z.x(' ', '_')

But notice that at the end, z is back to being a str rather than an s, so if you want to keep using x, you have to do this:

z = s(z.x(' ', '_'))

… and at a certain point, even if you're saving a few keystrokes, you're not saving nearly enough for the cost in readabiity and idiomaticitalnessity.

Sign up to request clarification or add additional context in comments.

1 Comment

" str.x = str.replace Unfortunately, it doesn't work with most of the built-in types,..." That statement was the best help on this issue. It sure is easy to monkey patch if it is not built-in. But it seems that when I really want to do this, it is usually a built-in type.
0

You can sort of do what you want:

a = 'asdf'

a_replace = a.replace

Now a_replace is a bound method object that does a.replace(whatever) when you call a_replace(whatever). You can also do

my_replace = str.replace

my_replace('asdf', 'a', 'f') # calls 'asdf'.replace('a', 'f')

However, what you probably want is

some_magic()
'asdf'.my_replace('a', 'f') # calls 'asdf'.replace('a', 'f')

and that's not possible without messing with things you're really not supposed to mess with:

# Awful hack. Last resort only.
import gc
for referrer in gc.get_referrers(str.replace):
    if type(referrer) is dict and str.__dict__ in gc.get_referrers(referrer):
        # Almost certainly the dict behind str's dictproxy.
        referrer['my_replace'] = str.replace
        break

Comments

0

This is absolutely NOT advisable to do in any of your projects. But this is possible: We could do some metahacking - replacing the builtin str with our custom one

class myStr(str):
    def def my_replace(self, __old, __new, __count):
        return self.replace(__old, __new, __count)

__builtins__.__dict__['str'] = myStr

Now the all usages of str are replaced with our implementation. You can add or change whatever you want. In our case both replace methods will work, one inherited from str and one created by us:

print('dsadas'.replace('d', '_'))
>>> _sa_as
print('dsadas'.my_replace('d', '_'))
>>> _sa_as

But remember this is fun, but using those technics in real project could ruin a lot of other functionality.

1 Comment

Really like this solution, will implement in my production code. It will just be mentioned in the documentation of the program and I'll be good!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.