# How do I alias member functions in Python?

In Python, one can save bytes by aliasing functions that are used repeatedly. For example:

r=range
a=r(100)
b=r(200)
c=r(300)


However, when the functions are member functions together, I don't know how to alias them in a way that allows chaining. For example:

s='Hello'

// Plain code
s=s.replace('H','J').replace('e','i').replace('l','m').replace('o','y')

// What I am trying to do
q=replace
s=s.q('H','J').q('e','i').q('l','m').q('o','y')


Obviously, what I am trying to do is not valid. And neither is this:

q=s.replace
s=q('H','J') // Replaces the 'H' in 'Hello'
s=q('e','i') // Replaces the 'e' in 'Hello'... and the J is gone.
s=q('l','m')
s=q('o','y')


Is there a another way to alias member functions and chained functions that saves characters?

• Define your own class, with its method q meaning what replace means in the class your using. – Ypnypn May 8 '14 at 21:07
• I'm glad this hasn't been downvoted :) – TheDoctor May 8 '14 at 23:08
• I've unwikied all the answers for now, but we haven't reached a strong enough consensus to call for unwiki-ing this and similar questions. See also: meta.codegolf.stackexchange.com/q/1555/3808 – Doorknob May 10 '14 at 14:34
• Now that the aforementioned meta discussion is semi-official (or at least most of us agree), I've gone ahead and removed the wiki on this post. – Doorknob May 13 '14 at 21:58
• Your last version doesn't work. q is bound to the replace method of that specific str instance. Also, remember you can do single char replacements with "Hello".replace(*"HJ") – gnibbler May 14 '14 at 1:40

No problemo! You can alias a method, but you have to know how to use it:

>>> r=str.replace
>>> a='hello'
>>> r(r(r(r(a,'h','j'),'e','i'),'l','m'),'o','y')
'jimmy'


The key is that you have to pass self explicitly, because the alias is a kind of function that takes an extra argument that takes self:

>>> type(r)
<type 'method_descriptor'>

• How did I not see this before? – Rainbolt May 14 '14 at 14:44

Define your own class, with a shorter method name.

For example, if you're using the method replace() belonging to the String class, you could make your own class S have a method called q which does the same thing.

Here is one implementation:

class m(str):
def q(a,b,c):return m(a.replace(b,c))


Here is a much better implementation:

class m(str):q=lambda a,b,c:m(a.replace(b,c))


Use it like so:

s="Hello"
s=m(s).q('H','J').q('e','i').q('l','m').q('o','y')


This is a few characters shorter anyway

j=iter('HJeilmoy')
for i in j:s=s.replace(i,next(j))


even shorter for a small number of replacements is

for i in['HJ','ei','lm','oy']:s=s.replace(*i)


of course this just covers one particular case. However code golf is all about finding those special cases that can save you bytes.

It's possible to write a wrapper function that handles the general case, but the code will be too large to have a place in most code golf challenges.

You instead need to think "I can do this transformation efficiently (strokewise) with str.replace. Can I shift the internal representation of my solution to take advantage of that? (without wasting so many strokes to negate the advantage)"

• I do like this answer because it describes good habits when golfing and definitely solves the specific example presented. I accepted another answer because it is applicable to the more general case. – Rainbolt May 14 '14 at 14:47

You may use the reduce function.

reduce(lambda s,(a,b):s.replace(a,b),[('H','J'),('e','i'),('l','m'),('o','y')],'Hello')

• If your answer different from this answer (as far as technique used, not necessarily written in the exact same form)? – Rainbolt May 10 '14 at 18:54
• @Rusher It is different. E.g. the number of invocations is hard-coded in the linked answer while here it is given only by the length of the second argument (which can be any iterator). – Howard May 10 '14 at 20:36

If you're doing a lot of replaces, you could do this:

s=''.join({'H':'J','e':'i','l':'m','o':'y'}[a] for a in list(s))

• I was hoping for an answer that wasn't specific to replace. I just used that as an example. – Rainbolt May 8 '14 at 21:14
• This can only replace 1 char at a time, but it can insert multi-char replacements. And this is not fully golfed (remove the space after [a]) – Justin May 9 '14 at 2:54
• Doesn't the [a] have to be replaced with .get(a,a) (otherwise, we get some Key Error thing)? And why have list(s) instead of s? – Justin May 9 '14 at 3:32

How about defining a lambda function?

r=lambda s,a,b:s.replace(a,b)

s=r(r(r(r(s,'H','J'),'e','i'),'l','m'),'o','y')

• No need: str.replace /is/ that lambda! See my answer. – MtnViewMark May 14 '14 at 14:34

If your replacements don't need to be chained, you can use str.translate'. The numbers are the ASCII ordinals. Using it this way requires Python 3:

print("Hello".translate({72:74,101:105,108:109,111:121}))
`

Try it online