Can PyCharm help me extract a free function from a method?

I want to receive from

class Sum:
    def __init__(self, a, b):
        self._a = a
        self._b = b

    def evaluate(self):
        return self._a + self._b

      

to

def add(a, b):
    return a + b


class Sum:
    def __init__(self, a, b):
        self._a = a
        self._b = b

    def evaluate(self):
        return add(self._a, self._b)

      

ie, extract the evaluate

expression from the method self._a + self._b

as a "free function" (a function that is not a method). Is this possible with PyCharm's automatic refactorings?

+3


source to share


2 answers


There is no direct way to do what you want, but you can work around it:

  • Select the operator self._a + self._b

    and right click> Refactor> Extract> Method or Ctrl+ Alt+M
  • In the pop-up window, select a name for your function (for example add

    )> OK. This will create a class function named as given. This process will also reorganize the usage according to your case.
  • Select the newly created function and its contents, and while holding Shift+ Alt, press the Upor buttons Downto move it to where you want it to be in your code. Just as you selected it and placed it last, hit Shift+ Tabto correct your identification.
  • Modify the generated function arguments to suit your case:
    Erase self

    , Add a

    , b

    etc.
    Also erase self.

    everywhere inside the function. You can do this by finding and replacing:
    Ctrl+ R> enter self.

    in the first search string> leave the second search string blank and starting from the beginning of your file, click Replaceuntil everything is correct.
  • In your function, evaluate

    remove self.

    that will be generated before the name of your generated function. Also pass the correct arguments to the function (for example return add(self.a, self.b)

    )


And you're done, it's a bit of a job, and it's not all that automated, but it will save you typing time!

This is tested in PyCharm 2017.1 pro edition

+1


source


I don't know if this can be done with a single refactoring, but it can be done almost completely automated in 3-4 steps:

  • extract the method with Ctrl+ Alt+M
  • turn it into a free function ("move method to top level" in PyCharm lingo) with F6
  • rename arguments with Shift+F6
  • (optional :) move the function to the beginning of the source file (manually)

Detailed steps:

First step: extract the method

  • Select the expression or operator (s) to be extracted (here self._a + self._b

    )
  • Click Ctrl+ Alt+M

    or

    from the context menu of the selection, choose Refactoring > Extract > Method ...

  • In the dialog that appears, enter a name for your function (in my example add

    ) and click OK .

The result will look like this:



class Sum:
    def __init__(self, a, b):
        self._a = a
        self._b = b

    def evaluate(self):
        return self.add()

    def add(self):
        return self._a + self._b

      

Second step: turn the method into a free function

Now, pull the new method out of the class and turn it into a module-level function:

  • Select the recently retrieved method or place the cursor anywhere (signature or body)
  • Click F6

    or

    from the context menu, select Refactor > Move ...

  • In the "Make Top Level Method" dialog box that appears, leave the "To" input field as it is (i.e. set the current location of the module source file) and click Refactor

The result will look like this:



class Sum:
    def __init__(self, a, b):
        self._a = a
        self._b = b

    def evaluate(self):
        return add(self._a, self._b)


def add(_a, _b):
    return _a + _b

      

Third step: rename the arguments

As you can see, the refactoring has correctly replaced the argument self

with two arguments for the operands. Unfortunately, he used the names of the _...

corresponding "hidden" instance members.

  • Select the underscore ( _

    ) in a function signature or where the function uses arguments
  • Click Shift+F6

    or

    on the shortcut menu, choose Refactor > Rename ...

  • In the Rename dialog box that appears, the underline will already be selected, so just click ←or Deland then click Enter(or click the Refactor button ).

Repeat for other function argument (s).

(In scenarios where you want to select completely different names, simply place the cursor in the argument name to change it without selecting part of it. The entire name will then start in the dialog's input field and can be overwritten by typing something new.)

The result will look like this:



class Sum:
    def __init__(self, a, b):
        self._a = a
        self._b = b

    def evaluate(self):
        return add(self._a, self._b)


def add(a, b):
    return a + b

      

Fourth step (optional): Move the function to the beginning of the source file

(or wherever you want to place it)

As you can see, PyCharm has placed a new top-level function after the class. I wanted to have it before that. Moving it with Shift+ Alt+ ↑as recommended in John's answer didn't work for me in PyCharm 2016.3.2 on GNOME, so I just separated the function and cut it with Crtl+ xand pasted it where I want it with Crtl+ v.

0


source







All Articles