I want to press - on my keyboard and have _ be inserted and vice-versa only for a particular mode.

The following does this globally using the post-self-insert-hook, It checks the character just inserted and makes a replacement accordingly:

(defun my-swap-dash ()
  "Make dash insert and underscore and vice-versa."
  (let ((just-inserted (char-before (point))))
     ((equal just-inserted 45) ;; '-'
    (delete-backward-char 1)
    (insert "_")))
     ((equal just-inserted 95) ;; '_'
    (delete-backward-char 1)
    (insert "-"))))))

(add-hook 'post-self-insert-hook #'my-swap-dash)

How could I get this same behavior for only python-mode?

My first thought is to define a minor mode and then enable it through the python-mode-hook. However, using the post-self-insert-hook means the replacement must happen globally.

As a work-around, I created a method of toggling the behavior manually:

(defvar swap-dash-state-p nil
  "Is swap-undash enabled?")

(defun toggle-swap-dash ()
  "Toggle `my-swap-dash'."
  (if swap-dash-state-p
        (remove-hook 'post-self-insert-hook #'my-swap-dash)
        (setq swap-dash-state-p nil))
      (add-hook 'post-self-insert-hook #'my-swap-dash)
      (setq swap-dash-state-p t))))

Thoughts and coding style comments welcome!

3 Answers 3


You can simply map the keys - and _ to do what you want in python mode:

(defun insert-underscore ()
  "Guess what!"
  (insert "_"))

(defun insert-hyphen ()
   "You know it!"
   (insert "-"))

(defun python-remap-hyphen-and-underscore ()
  (define-key python-mode-map "-" 'insert-underscore)
  (define-key python-mode-map "_" 'insert-hyphen))

(if (boundp 'python-mode-map)
  (add-hook 'python-mode-hook 'python-remap-hyphen-and-underscore))

What we do here is to define two commands to insert an underscore and an hyphen, then a function to associate these commands to the - and _ keys in python-mode-map (the variable that holds the key bindings in python-mode).

If you insert this snippet in your init file, before python-mode is loaded, you can replace the last three lines simply by

(add-hook 'python-mode-hook 'python-remap-hyphen-and-underscore)

What I actually implemented is a modification of @JeanPierre's solution:

(defun my-remap-dash-and-underscore ()
  (define-key python-mode-map "-" #'(lambda () (interactive) (insert "_")))
  (define-key python-mode-map "_" #'(lambda () (interactive) (insert "-"))))

(defun my-undo-remap-dash-and-underscore ()
  (define-key python-mode-map "-" 'self-insert-command)
  (define-key python-mode-map "_" 'self-insert-command))

(add-hook 'python-mode-hook 'my-remap-dash-and-underscore)

This sets the swap up by default in python-mode. It can be toggled manually via the appropriate function with M-x.


you can achieve this with evil-swap-keys.el (which is not tied to evil):

(add-hook 'python-mode-hook #'evil-swap-keys-swap-underscore-dash)

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.