| import bpy
import bmesh
import math
def vert1For(u, t):
    return [ 0, u, 0]
def vert2For(u, t, dTheta, z1):
    theta1 = dTheta * math.sin(t+u*0.4)
    return [ math.sin(theta1)*z1, u, math.cos(theta1)*z1]
def vert3For(u, t, dTheta, z2, thetaLag):
    theta2 = dTheta * math.sin(t+u*0.4-thetaLag)
    return [ math.sin(theta2)*z2, u, math.cos(theta2)*z2]
def makeMesh(name, nSegs, z1, z2, dTheta, thetaLag):
    mesh = bpy.data.meshes.new(name)
    verts = []
    faces = []
    for u in range(0,nSegs+1):
        v4=len(verts)
        verts.append( vert1For(u,0) )
        verts.append( vert2For(u,0,dTheta, z1) )
        verts.append( vert3For(u,0,dTheta, z2, thetaLag) )
        if (u>0):
            v1 = v4-3
            v2 = v1+1
            v3 = v1+2
            v5 = v1+4
            v6 = v1+5
            faces.append( [ v1, v4, v5, v2] )
            faces.append( [ v2, v5, v6, v3] )
    mesh.from_pydata(verts, [], faces)
    mesh.validate(True)
    mesh.show_normal_face = True
    return mesh
def addShapeKey(obj, i, nKeys, z1, z2, dTheta, thetaLag):
    kn = "phase %d"%i
    sk = obj.shape_key_add(kn)
#    sk.value = 0
#    sk.frame = i/nKeys
#    sk.frame = i*i/(nKeys*nKeys) # crazy version
    bm = bmesh.new()
    bm.from_mesh(obj.data)
    bm.verts.ensure_lookup_table()
    sl = bm.verts.layers.shape.get(kn)
    for u in range( math.floor(len(bm.verts) / 3)):
        t = math.pi*2*i/nKeys
        bm.verts[u*3][sl] = vert1For(u, t)
        bm.verts[u*3+1][sl] = vert2For(u, t, dTheta, z1)
        bm.verts[u*3+2][sl] = vert3For(u, t, dTheta, z2, thetaLag)
    bm.to_mesh(obj.data)
dTheta = 0.8
thetaLag = 0.2
z1 = 2
z2 = 3
mesh = makeMesh("fin", 40, z1, z2, dTheta, thetaLag)
obj = bpy.data.objects.new("fin", mesh)
bpy.context.scene.objects.link(obj)
sk0 = obj.shape_key_add("Basis")
print(sk0)
sk0 = obj.data.shape_keys
print(sk0)
sk0.use_relative = False
nKeys = 11;
for i in range(1,nKeys):
    addShapeKey(obj, i, nKeys, z1, z2, dTheta, thetaLag)
# This next bit does not actually work, and I'm not sure why.  That's why pretty much everything in bpy.ops should be avoided.
obj.select = True
bpy.context.scene.objects.active = obj
print("retime")
bpy.ops.object.shape_key_retime()
 | 
Blender python API quick-start
Syntax highlighting by Pygments.