Як перенести два аргументи функції в Python?


11

Як я можу поміняти два аргументи під час виклику функції Python?

Якщо я поставлю pointпробіл між цими двома аргументами:

self.assertEqual(json.loads(some.data), json_data)

а потім M-t( transpose-words) я отримую:

self.assertEqual(json.loads(some.json), data_data)

З іншого боку, з CMt ( transpose-sexps) я отримую:

self.assertEqual(json.loadsjson_data, (some.data))

Що я хочу:

self.assertEqual(json_data, json.loads(some.data))

Чи є команда, яка це зробить?


2
Я не пробував, але для цього можна використовувати прив’язаний перенос ; це, однак, двоетапний процес.
— Каушал Моді

Існує основна функція, transpose-subrяка називається, яка приймає forwardфункцію і переводить її у transposeфункцію. Отже, якби у нас була c-forward-arglist(функція переходити від однієї аргументації функції до іншої - AFAICT ця не існує) у нас була б c-transpose-arglist.
— Брендан

Відповіді:


4

Це я теж давно хотів мати, і тут я знайшов певну мотивацію працювати над цим. Напевно, це не дуже надійно, але при першій спробі, здається, висвітлюються випадки, які я намагався:

(defun my/calculate-stops ()
  (save-excursion
    (let ((start
           (condition-case e
               (while t (backward-sexp))
             (error (point))))
          stops)
      (push start stops)
      (condition-case e
          (while t
            (forward-sexp)
            (when (looking-at "\\s-*,")
              (push (point) stops)))
        (error (push (point) stops)))
      (nreverse stops))))

(defun my/transpose-args ()
  (interactive)
  (when (looking-at "\\s-") (backward-sexp))
  (cl-loop with p = (point)
           with previous = nil
           for stop on (my/calculate-stops)
           for i upfrom 0
           when (<= p (car stop)) do
           (when previous
             (let* ((end (cadr stop))
                    (whole (buffer-substring previous end))
                    middle last)
               (delete-region previous end)
               (goto-char previous)
               (setf middle (if (> i 1) (- (car stop) previous)
                              (string-match "[^, \\t]" whole 
                                            (- (car stop) previous)))
                     last (if (> i 1) (substring whole 0 middle)
                            (concat (substring whole (- (car stop) previous) middle)
                                    (substring whole 0 (- (car stop) previous)))))
               (insert (substring whole middle) last)))
           (cl-return)
           end do (setf previous (car stop))))

Я отримую це, коли точка знаходиться на пробілі (працює, коли на кому): let *: Неправильний аргумент типу: integer-or-marker-p, nil
— Croad Langshan

@CroadLangshan виправлення було відносно легким (див. Вище). Найцікавіше, що я намагався виконувати поради Стефана, написавши альтернативу forward-sexp-function, і це виявилося занадто громіздким через коми. Потім я спробував копіювати, traspose-sexpщоб зробити те саме, і, знову ж таки, необхідність врахувати коми робить це дуже важко. Я не стверджую, що це завжди робить правильно, якщо мова йде про обмежувачі списку, можливо, лише половину часу ...
— wvxvw

Це не вдається, (aa, bb)коли курсор увімкнено першим a. Це також не працює для переміщення. FOO(aaa *, bbb, ccc)Як- *небудь псується транспонування.
— ideaman42

Також не працює для FOO(&aaa, bbb)(& не замінюється).
— ideaman42

4

Я використовую варіант, transpose-sexpsякий шукає випадок, який ви описуєте, і переміщує речі, розділені комами, або просто регулярно transpose-sexps. Він також залишає курсор на місці замість того, щоб тягнути його вперед, що дещо інакше, але мені особисто подобається.

(defun my-transpose-sexps ()
  "If point is after certain chars transpose chunks around that.
Otherwise transpose sexps."
  (interactive "*")
  (if (not (looking-back "[,]\\s-*" (point-at-bol)))
      (progn (transpose-sexps 1) (forward-sexp -1))
    (let ((beg (point)) end rhs lhs)
      (while (and (not (eobp))
                  (not (looking-at "\\s-*\\([,]\\|\\s)\\)")))
        (forward-sexp 1))
      (setq rhs (buffer-substring beg (point)))
      (delete-region beg (point))
      (re-search-backward "[,]\\s-*" nil t)
      (setq beg (point))
      (while (and (not (bobp))
                  (not (looking-back "\\([,]\\|\\s(\\)\\s-*" (point-at-bol))))
        (forward-sexp -1))
      (setq lhs (buffer-substring beg (point)))
      (delete-region beg (point))
      (insert rhs)
      (re-search-forward "[,]\\s-*" nil t)
      (save-excursion
        (insert lhs)))))

Для мене це залишає пробіл на початку виклику assertEqual (починаючи з точки на пробілі).
— Croad Langshan

1
Це не працює для аргументів ключових слів на кшталт: f(a=1, b=2)(це переміщається навколо)
— Att Righ

1
Хоча питання про код C, ця відповідь працює для f(a=1, b=2)- emacs.stackexchange.com/a/47930/2418
— ideaman42

2

У режимах, які використовують SMIE, transpose-sexpслід правильно працювати в цьому випадку. Вони все одно не зможуть, коли символ інфіксації (він же "роздільник") не є ,(або a ;), а є словом (наприклад and).

Отже, моя думка полягає в тому, що команда для цього є, transpose-sexpі коли це працює не правильно, я вважаю це помилкою (але помилка, яка може бути важкою та / або потребує часу, щоб виправити і мати низький пріоритет, тому не ' т затримати дихання). Спосіб її виправити - це встановити forward-sexp-functionфункцію, яка буде знати, що "після того, як я побачу кому, я просто стрибаю весь аргумент".


1
Я думаю, що режим java (наприклад) не використовує SMIE? Як би можна було вирішити це?
— Семюель Едвін Уорд

1
Ні, дійсно, основні режими для мов, подібних до C, не використовують SMIE і не лише з історичних причин: аналізатор SMIE просто занадто слабкий для цих мов. Це означає, що парсер SMIE буде добре працювати, якщо ви хочете поміняти місцями два аргументи, розділені комою (ця частина граматики є досить простою), тож я думаю, можна було б налаштувати SMIE і використовувати його, forward-sexp-functionале ви б мали додати якийсь код, щоб використовувати SMIE лише forward-sexp-function в тих випадках, коли він працює досить добре, оскільки у багатьох інших випадках це призведе до заплутаної поведінки.
— Стефан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.