Introduction to Pyrex

Download Report

Transcript Introduction to Pyrex

Introduction to Pyrex
http://www.sweetapp.com/pyrex
September 2002
Brian Quinlan
[email protected]
What is Pyrex?
• Pyrex is a language for writing Python
extension modules
• Pyrex has a Python-like syntax that gets
compiled into C code
• Pyrex let’s you mix Python and C data
types and function calls freely
Slide 2
©2002 Brian Quinlan
The perfect example
• Let’s compute perfect numbers!
• Perfect numbers are number whose
positive divisors (except for itself) sum to
itself
e.g. 6 is a perfect number because:
1x6=6
2x3=6
1+2+3=6
• Naïve methods of computing perfect
numbers are slow – so let’s use one and
optimize
Slide 3
©2002 Brian Quinlan
The Python code
from math import sqrt, ceil
from operator import add
def _calculate_factors(x):
factors = [1]
sqrt_x = int(ceil(sqrt(x)))
for i in xrange(2, sqrt_x):
if x % i == 0:
factors.append(i)
factors.append(x / i)
if sqrt_x ** 2 == x: factors.append(sqrt_x)
return factors
def is_perfect(x):
return reduce(add, _calculate_factors(x), 0) == x
Slide 4
©2002 Brian Quinlan
The Pyrex code
from math import sqrt, ceil
from operator import add
def _calculate_factors(x):
factors = [1]
sqrt_x = int(ceil(sqrt(x)))
for i in xrange(2, sqrt_x):
if x % i == 0:
factors.append(i)
factors.append(x / i)
if sqrt_x ** 2 == x: factors.append(sqrt_x)
return factors
def is_perfect(x):
return reduce(add, _calculate_factors(x), 0) == x
Slide 5
©2002 Brian Quinlan
Pyrex is VERY like Python
• Pyrex syntax is VERY similar to Python
syntax
• Running the same code using Pyrex is
about 15% faster
• There are Pyrex-specific features that allow
us to improve the performance even more
Slide 6
©2002 Brian Quinlan
Use C types
from math import sqrt, ceil
from operator import add
def _calculate_factors(int x):
cdef int sqrt_x, i
factors = [1]
sqrt_x = ceil(sqrt(x))
for i in xrange(2, sqrt_x):
if x % i == 0:
factors.append(i)
factors.append(x / i)
if sqrt_x ** 2 == x: factors.append(sqrt_x)
return factors
def is_perfect(int x):
return reduce(add, _calculate_factors(x), 0) == x
Slide 7
©2002 Brian Quinlan
Use a Pyrex “for” construct
from math import sqrt, ceil
from operator import add
def _calculate_factors(int x):
cdef int sqrt_x, i
factors = [1]
sqrt_x = ceil(sqrt(x))
for i from 2 <= i < sqrt_x:
if x % i == 0:
factors.append(i)
factors.append(x / i)
if sqrt_x ** 2 == x: factors.append(sqrt_x)
return factors
def is_perfect(int x):
return reduce(add, _calculate_factors(x), 0) == x
Slide 8
©2002 Brian Quinlan
Use the C math library
cdef extern from "math.h":
double sqrt(double x)
double ceil(double x)
from operator import add
def _calculate_factors(int x):
cdef int sqrt_x, i
factors = [1]
sqrt_x = ceil(sqrt(x))
for i from 2 <= i < sqrt_x:
if x % i == 0:
factors.append(i)
factors.append(x / i)
…
Slide 9
©2002 Brian Quinlan
Use C functions
cdef extern from "math.h":
…
from operator import add
cdef object _calculate_factors(int x):
cdef int sqrt_x, i
factors = [1]
sqrt_x = ceil(sqrt(x))
for i from 2 <= i < sqrt_x:
if x % i == 0:
factors.append(i)
factors.append(x / i)
if sqrt_x ** 2 == x: factors.append(sqrt_x)
return factors
…
Slide 10
©2002 Brian Quinlan
Do our own summation
…
def is_perfect(int x):
cdef int sum
cdef int i
sum = 0
for i in _calculate_factors(x):
sum = sum + i
return sum == x
Slide 11
©2002 Brian Quinlan
Results
6.81
7
5.96
6
5
Time
(s)
3.58
4
3
2.2
1.92
1.79
2
1.38
Slide 12
©2002 Brian Quinlan
+ sum
+ func
+ math
+ for
+ cdefs
Pyrex
0
Python
1
A vector class
cdef class Vector3:
cdef double x
cdef double y
cdef double z
def __init__(self, double x, double y, double z):
self.x, self.y, self.z = x, y, z
Slide 13
©2002 Brian Quinlan
Getting it’s attributes
def __getattr__(self, name):
if name == 'x':
return self.x
elif name == 'y':
return self.y
elif name == 'z':
return self.z
else:
raise AttributeError(
'Vector3 has no attribute "%s"' % name
)
Slide 14
©2002 Brian Quinlan
Some operations
def __add__(Vector3 a, Vector3 b):
return Vector3(a.x + b.x, a.y + b.y, a.z + b.z)
cdef int __nonzero__(Vector3 self):
return self.x or self.y or self.z
def __str__(self):
return 'Vector3(x=%s, y=%s, z=%s)' % (
self.x, self.y, self.z)
def __repr__(self): # __repr__ = __str__ not allowed
return 'Vector3(x=%r, y=%r, z=%r)' % (
self.x, self.y, self.z)
Slide 15
©2002 Brian Quinlan
Using Pyrex
• The hassle-factor is low (easy to install
Pyrex, easy to get Pyrex to compile your
code - so long as you have a C compiler)
• Documentation is minimal but
understandable
• Writing simple functions using Pyrex features
is easy (though there are a few gotchas)
• Writing classes is harder (more gotches,
more bugs, more unfinished features)
• C and the Python C API has more gotches
than Pyrex
Slide 16
©2002 Brian Quinlan