Comment puis-je alias les fonctions membres en Python?

23

En Python, on peut enregistrer des octets en aliasant des fonctions qui sont utilisées à plusieurs reprises. Par exemple:

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

Cependant, lorsque les fonctions sont des fonctions membres ensemble, je ne sais pas comment les alias d'une manière qui permette le chaînage. Par exemple:

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')

De toute évidence, ce que j'essaie de faire n'est pas valide. Et ce n'est pas non plus:

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')

Existe-t-il une autre façon d'alias les fonctions membres et les fonctions chaînées qui enregistre les caractères?

Rainbolt
la source
Définissez votre propre classe, sa méthode qsignifiant ce que replacesignifie dans la classe que vous utilisez.
Ypnypn
3
Je suis content que cela n'ait pas été rétrogradé :)
TheDoctor
2
Je n'ai pas sollicité toutes les réponses pour l'instant, mais nous ne sommes pas parvenus à un consensus suffisamment fort pour demander la suppression de cette question et d'autres questions similaires. Voir aussi: meta.codegolf.stackexchange.com/q/1555/3808
Doorknob
3
Maintenant que la méta-discussion susmentionnée est semi-officielle (ou du moins la plupart d'entre nous sommes d'accord), j'ai continué et supprimé le wiki de ce post.
Poignée de porte
1
Votre dernière version ne fonctionne pas. qest lié à la méthode replace de cette strinstance spécifique . N'oubliez pas non plus que vous pouvez effectuer des remplacements avec un seul caractère avec"Hello".replace(*"HJ")
gnibbler

Réponses:

28

Pas de problème! Vous pouvez alias une méthode, mais vous devez savoir comment l'utiliser:

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

La clé est que vous devez passer selfexplicitement, car l'alias est une sorte de fonction qui prend un argument supplémentaire qui prend self:

>>> type(r)
<type 'method_descriptor'>
MtnViewMark
la source
3
Comment n'ai-je pas vu ça avant?
Rainbolt
6

Définissez votre propre classe, avec un nom de méthode plus court.

Par exemple, si vous utilisez la méthode replace()appartenant à la Stringclasse, vous pouvez faire en sorte que votre propre classe Sait une méthode appelée qqui fait la même chose.

Voici une implémentation:

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

Voici une bien meilleure implémentation:

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

Utilisez-le comme ceci:

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

C'est quand même quelques caractères plus courts

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

encore plus court pour un petit nombre de remplacements est

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

bien sûr, cela ne couvre qu'un cas particulier. Cependant, le golf de code consiste à trouver ces cas spéciaux qui peuvent vous faire économiser des octets.

Il est possible d'écrire une fonction wrapper qui gère le cas général, mais le code sera trop volumineux pour avoir une place dans la plupart des défis de golf de code.

Au lieu de cela, vous devez penser "Je peux effectuer cette transformation efficacement (en traits) avec str.replace. Puis-je changer la représentation interne de ma solution pour en profiter? (Sans gaspiller autant de traits pour annuler l'avantage)"

grignoteur
la source
J'aime cette réponse car elle décrit les bonnes habitudes au golf et résout définitivement l'exemple spécifique présenté. J'ai accepté une autre réponse car elle s'applique au cas plus général.
Rainbolt
4

Vous pouvez utiliser la reducefonction.

reduce(lambda s,(a,b):s.replace(a,b),[('H','J'),('e','i'),('l','m'),('o','y')],'Hello')
Howard
la source
Si votre réponse est différente de cette réponse (en ce qui concerne la technique utilisée, pas nécessairement écrite exactement sous la même forme)?
Rainbolt
1
@Rusher C'est différent. Par exemple, le nombre d'appels est codé en dur dans la réponse liée alors qu'ici, il n'est donné que par la longueur du deuxième argument (qui peut être n'importe quel itérateur).
Howard
1

Si vous faites beaucoup de remplacements, vous pouvez le faire:

s=''.join({'H':'J','e':'i','l':'m','o':'y'}[a] for a in list(s))
Le docteur
la source
J'espérais une réponse qui n'était pas spécifique à remplacer. Je viens de l'utiliser comme exemple.
Rainbolt
Cela ne peut remplacer qu'un seul caractère à la fois, mais il peut insérer des remplacements multi-caractères. Et ce n'est pas entièrement joué (supprimez l'espace après [a])
Justin
2
Ne doit-il pas [a]être remplacé par .get(a,a)(sinon, nous obtenons une erreur clé)? Et pourquoi avoir list(s)au lieu de s?
Justin
1

Que diriez-vous de définir une fonction lambda?

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

s=r(r(r(r(s,'H','J'),'e','i'),'l','m'),'o','y')
Justin
la source
1
Pas besoin: str.replace/ c'est / que lambda! Voir ma réponse.
MtnViewMark
1

Si vos remplacements n'ont pas besoin d'être enchaînés, vous pouvez utiliser `str.translate '. Les nombres sont les ordinaux ASCII. Son utilisation de cette façon nécessite Python 3:

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

Essayez-le en ligne

mbomb007
la source