For reference, all of the code I used is at the bottom of this post.
I will first discuss a few python style points, and then we'll look at performance.
Pep8:
First thing to do is get a style/lint checker. I use the pycharm ide which will show you style and compile issues right in the editor. When you get a chance you should also read through pep8 which is the official python style guide.
Don't mash your list elements:
One item per line is quite a bit easier to read.
numeric_types = [
'(BIG|MEDIUM|SMALL|TINY)*INT(EGER)*(\(.*?\))*',
'DEC(IMAL)*(\(.*?\))*',
...
'BIT',
'BOOL(EAN)*'
]
Use pythons iterators:
Most of the time, you will not need to use an index variable (eg: the i
in the original code). Python can just iterate over an amazing number of things.
for line in lines:
for regex_str in numeric_types:
if re.search(regex_str, line):
line = re.sub(regex_str, "SERIAL", line).replace(
" AUTO_INCREMENT", "")
break
Performance investigation:
So when investigating these sorts of things, timeit
is your friend. I timed the things I tried as:
def method1():
...
def method2():
...
from timeit import timeit
count = 3
print('original:', [timeit(method1, number=200) for i in range(count)])
print('compiled:', [timeit(method2, number=200) for i in range(count)])
Method1:
method1 is functionally equivalent to the original code.
def method1():
for line in lines:
for regex_str in numeric_types:
if re.search(regex_str, line):
line = re.sub(regex_str, "SERIAL", line).replace(
" AUTO_INCREMENT", "")
break
Method2:
method2 compiles all of regular expression strings into regular expression objects, and then uses the objects:
num_type_regex = [re.compile(x) for x in numeric_types]
def method2():
for line in lines:
for regex in num_type_regex:
if regex.search(line):
line = regex.sub("SERIAL", line).replace(
" AUTO_INCREMENT", "")
break
Timing Results:
Not surprisingly, the compiled expressions were faster.
original: [1.3694926374633507, 1.2469248480337616, 1.2260409178909049]
compiled: [0.9859922309149369, 1.0048337256902489, 1.0676349069804303]
All of the Code:
import re
line = 'id INTEGER(11) NOT NULL AUTO_INCREMENT,'
lines = [line + str(i) for i in range(1000)]
numeric_types = [
'(BIG|MEDIUM|SMALL|TINY)*INT(EGER)*(\(.*?\))*',
'DEC(IMAL)*(\(.*?\))*',
'NUMERIC(\(.*\))*',
'FIXED(\(.*\))*',
'FLOAT(\(.*\))*',
'DOUBLE( PRECISION)*(\(.*?\))*',
'REAL(\(.*\))*',
'BIT',
'BOOL(EAN)*']
num_type_regex = [re.compile(x) for x in numeric_types]
num_type_joined = re.compile('|'.join(numeric_types))
def method1():
for line in lines:
for regex_str in numeric_types:
if re.search(regex_str, line):
line = re.sub(regex_str, "SERIAL", line).replace(
" AUTO_INCREMENT", "")
break
def method2():
for line in lines:
for regex in num_type_regex:
if regex.search(line):
line = regex.sub("SERIAL", line).replace(
" AUTO_INCREMENT", "")
break
from timeit import timeit
count = 3
print('original:', [timeit(method1, number=200) for i in range(count)])
print('compiled:', [timeit(method2, number=200) for i in range(count)])