Redefine \texttt{} to allow underscore

renewcommandtypewriter

I use underscore inside \texttt{} quite often to represent python functions, and I get quite tired of escaping every single underscore with \_. I tried the following to redefine the \texttt{} command to allow unescaped underscores, based on these answers:

Can I redefine a command to contain itself?

To escape underscore without \verb and \texttt

For some reason, it doesn't work. If I write the three lines inside the command directly in my text, it works. Any ideas to why this doesn't work?

\usepackage[T1]{fontenc}

\let\oldtexttt\texttt #'Copy' command

\renewcommand{\texttt}[1]{
\catcode`_ 12\relax    
\oldtexttt{#1}
\catcode`_ 8\relax}

\texttt{hello_world}

Best Answer

You should define your own command for Python functions, to which apply a character substitution.

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand{\pyf}{m}
 {
  \texttt
   {
    \tl_set:Nn \l_tmpa_tl { #1 }
    \tl_replace_all:Nen \l_tmpa_tl { \char_generate:nn { `_ } { 8 } } { \_ }
    \tl_use:N \l_tmpa_tl
   }
 }
\cs_generate_variant:Nn \tl_replace_all:Nnn { Ne }
\ExplSyntaxOff

\begin{document}

\pyf{my_var}

\texttt{my\_var}

\end{document}

There is a little complication due to the fact that _ is special in the expl3 programming environment, so we need to generate the underscore with its usual meaning of “subscript”.

enter image description here

Your approach cannot work because when you absorb the argument the category codes are frozen. You might do it by not absorbing the argument before the category code change

\makeatletter
\newcommand{\pyf}{%
  \begingroup\catcode`_=12
  \pyf@
}
\newcommand{\pyf@}[1]{\texttt{#1}\endgroup}
\makeatother

but this will not work if you use \pyf in the argument to another command.

The code I showed at the beginning is free from this defect.

Related Question