Refactoring A Python Beginner’s Code

ああ、PyConJPの講演資料っていうんですか、まだ0%ですね。

Who am I / おまえ誰よ

_images/sphinxusers.jpg
_images/beproud.gif
_images/pyconjp2012_logo.png

2 Python books

_images/epp.jpg _images/pypro.png

9/16、Expert Python Reading PyConJP2012 Edition

  • at 9/16 OpenSpace
  • Gift something...

My Confusions when I started Python programing

  • I didn’t know what is good coding style in Python
  • I tried to port code from C/C++ to Python
  • That code looks like Java or C++

My code in 2004

class PlayerMaker:
    def __init__(self):
        self.name = ""
        self.hp = 0
        self.at = 0
        ...

    def setName( self, item ):
        self.name = item.text

    def setHp( self, item ):
        self.hp = int(item.text)

    def setAt( self, item ):
        self.at = int(item.text)

    def setDf( self, item ):
        self.df = int(item.text)

    def setAg( self, item ):
        self.ag = int(item.text)

   ...

A code I just glanced a few months ago

public class ISBNConverter {
   public static void main(String[] args) {
      ...
      char [] cisbn = isbn.toCharArray();
      int [] iisbn;
      iisbn = new int[10];
      ...
      for (int idx=0; idx<9; idx++) {
          iisbn[idx] = Character.digit(cisbn[idx], 10);
          if ((iisbn[idx]<0)||(iisbn[idx]>9)){
              System.out.println("Error: Not a number is included in the 9 numbers.");
              System.exit(0);
      ...

I tried to rewrite by python straightly

def main(args):
    ...
    cisbn = isbn
    iisbn = [None] * 10;
    ...
    for idx in range(9):
        if not cisbn[idx].isdigit():
            print("Error: Not a number is included in the 9 numbers.")
            sys.exit(0)
        iisbn[idx] = int(cisbn[idx])

    if cisbn[9] == 'X':
        iisbn[9] = 10
    else:

Why the code does not seems like Python?

CamelCase getter/setter

class PlayerMaker:
    def __init__(self):
        self.name = ""
        self.hp = 0
        ...

    def setName( self, item ):
        self.name = item.text

    def setHp( self, item ):
        self.hp = int(item.text)

    ...

range for-loop

Like for(i=0; i<9; i++) {...}

for idx in range(9):

For example...

for i in range(9):
    if not cisbn[i].isdigit():
    ...

Prepare fixed-length array

Initializing array...

iisbn = [None] * 10;

For example...

for idx in range(9):
    ...
    iisbn[idx] = int(cisbn[idx])

そうだ、リファクタリングしよう

OK, Let’s refactoring!

First, we need Test-Case

  • We NEED test case before any changes
  • Changes SHOULD NOT effect the results
  • For now, I test only printed text.

Practice

The points of refactoring

  • Remove range loop
  • Decrease variables
  • Separate some processing in a loop
  • Add new function to split code
  • Replace complex loop by simple one
  • Use Exceptions instead of print/exit
  • Write Test-Case for new functions

Questions?

Thank You!