Bmesh script.

Here is but one of may ways could approach this.
Rib n Bridge
- Make
growth_segments
cirlcles all with segments
segments. Each
has a radius in range (min_radius, max_radius)
and the the next is
in the range of (min_growth, max_growth)
above.
- A translation matrix, using the accumulative height is used to place
each successive circle.
- Each circle is added with
bmesh
's create circle primitive. On each
iteration a "rib" is the last added segments
edges of the bmesh.
- Skinned by bridging each rib with its next.
- Finally the first and last ribs are ngon filled with the
contextual_create
operator, somewhat akin to bmesh
's F
"fill" key.
import bpy
from bpy import context # for testing
import bmesh
from random import uniform
from mathutils import Matrix
segments = 16
min_radius = 0.5
max_radius = 2.0
growth_segments = 10
min_growth = 1.0
max_growth = 2.0
bm = bmesh.new()
h = 0
ribs = []
# make the circles
for i in range(growth_segments):
bmesh.ops.create_circle(
bm,
segments=segments,
radius=uniform(min_radius, max_radius),
matrix=Matrix.Translation((0, 0, h)),
)
h += uniform(min_growth, max_growth)
ribs.append(bm.edges[-segments:])
# bridge the loops
for rib, ribnext in zip(ribs, ribs[1:]):
bmesh.ops.bridge_loops(
bm,
edges=rib + ribnext,
)
# fill the ends
bmesh.ops.contextual_create(
bm,
geom=ribs[0] + ribs[-1],
)
# Create object load mesh
me = bpy.data.meshes.new("RandomCyl")
bm.to_mesh(me)
ob = bpy.data.objects.new("RandomCyl", me)
context.collection.objects.link(ob)
# make selected and active
ob.select_set(True)
context.view_layer.objects.active = ob
Matrices
Have used a matrix in the create circle operator to translate to the height

Here I've extended this a bit further to give a panel beaten effect, each rib is now a random ellipse using above min max for two radii, and also rotated randomly 0 to 45 degrees in Z.
A diagonal matrix is a quick way to produce a scale matrix.
Sx = Matrix.Scale(4, 3, 'X')
is equiv of
S = Matrix.Diagonal((4, 1, 1))
Each circle is transformed by R @ T @ S
(rotation, translation, scale)
bmesh.ops.create_circle(
bm,
segments=segments,
radius=1,
matrix=(
Matrix.Rotation(uniform(0, 0.7854), 4, 'Z') @
Matrix.Translation((0, 0, h)) @
Matrix.Diagonal(
(
uniform(min_radius, max_radius),
uniform(min_radius, max_radius),
1,
)
).to_4x4() # since tanslation mat is 4x4
),
)
Cannot emphasize enough, the better we become at using linear algebra (vectors and matrices) the "easier" it will be to use API methods. Is also generally faster and IMO cleaner.
Spin Profile
Another way would be to make profile edges on XZ plane and spin it around z axis to make a solid of revolution.
Equivalent of making profile shown on left, and creating mesh by spinning it with the screw modifier (default settings)
import bpy
from bpy import context # for testing
import bmesh
from random import uniform
from mathutils import Matrix
from math import radians
segments = 16
min_radius = 0.5
max_radius = 2.0
growth_segments = 10
min_growth = 1.0
max_growth = 2.0
bm = bmesh.new()
h = 0
verts = [bm.verts.new()]
for h in range(growth_segments):
radius = uniform(min_radius, max_radius)
verts.append(
bm.verts.new((radius, 0, h))
)
h += uniform(min_growth, max_growth)
verts.append(bm.verts.new((0, 0, verts[-1].co.z)))
for edge in zip(verts, verts[1:]):
bm.edges.new(edge)
# spin the sucker
bmesh.ops.spin(
bm,
geom=bm.edges[:],
axis=(0, 0, 1), # z axis
angle=radians(360), # 2pi one rev
steps=segments,
)