Creating Your Own Functions

You’ve been calling functions all along — set_position(), set_color(), scene.add(). Each one packages up a bunch of steps under a single name so you don’t have to repeat them.

Now it’s your turn. In this lesson you’ll write your own functions using def. A function you define works exactly like the built-in ones — call it by name, pass in values, and it does the work.

Open In Jupyter K-12

The Problem — Repeated Code

The scene below contains two trees. Each tree is made from a cylinder (trunk) and a sphere (leaves). That’s six lines per tree — and they’re nearly identical. Adding a third tree means copying six more lines. A forest of ten trees? Sixty lines of nearly identical code.

import scene3d

scene = scene3d.Scene()
scene.set_sky(scene3d.Sky.PURE_SKY)
scene.set_ground(length=20, width=20)

trunk1 = scene3d.Shapes.Cylinder(diameter=0.3, height=1.5, tessellation=8)
trunk1.set_color('#8B4513')
trunk1.set_position(-3, 0.75, 0)
scene.add(trunk1)

leaves1 = scene3d.Shapes.Sphere(diameter=2.0, segments=12)
leaves1.set_color('#228B22')
leaves1.set_position(-3, 2.0, 0)
scene.add(leaves1)

trunk2 = scene3d.Shapes.Cylinder(diameter=0.3, height=1.5, tessellation=8)
trunk2.set_color('#8B4513')
trunk2.set_position(3, 0.75, 0)
scene.add(trunk2)

leaves2 = scene3d.Shapes.Sphere(diameter=2.0, segments=12)
leaves2.set_color('#228B22')
leaves2.set_position(3, 2.0, 0)
scene.add(leaves2)

The Solution — Define a Function

A function groups code under a name. You write the steps once, then call the name as many times as you need.

def make_tree(scene, x, z):
    # steps that build one tree go here

Run the cell below. It produces the same two trees — but now adding a third is just one more line.

import scene3d

scene = scene3d.Scene()
scene.set_sky(scene3d.Sky.PURE_SKY)
scene.set_ground(length=20, width=20)

def make_tree(scene, x, z):
  trunk = scene3d.Shapes.Cylinder(diameter=0.3, height=1.5, tessellation=8)
  trunk.set_color('#8B4513')
  trunk.set_position(x, 0.75, z)
  scene.add(trunk)
  leaves = scene3d.Shapes.Sphere(diameter=2.0, segments=12)
  leaves.set_color('#228B22')
  leaves.set_position(x, 2.0, z)
  scene.add(leaves)

make_tree(scene, -3, 0)
make_tree(scene, 3, 0)
make_tree(scene, 0, -3)

How def Works

def make_tree(scene, x, z):
    trunk = scene3d.Shapes.Cylinder(...)
    ...
Part What it does
def The keyword that defines a new function
make_tree The name you give the function — use it to call it later
(scene, x, z) Parameters — values passed in when the function is called
: Marks the end of the def line
Indented body The code that runs each time the function is called

When you write make_tree(scene, -3, 0), Python replaces scene with your scene, x with -3, and z with 0 inside the function body.

Two rules to remember

  1. Define before calling. The def block must appear in your code before you call the function.
  2. Indentation marks the body. Everything indented under def is inside the function.

{ “question_type”: “multiple_choice”, “question”: “Which keyword do you use to define a new function in Python?”, “options”: [ { “key”: “a”, “text”: “function” }, { “key”: “b”, “text”: “define” }, { “key”: “c”, “text”: “def” }, { “key”: “d”, “text”: “new” } ], “answer”: “c”, “submitted_answer”: “” }

{ “question_type”: “true_false”, “question”: “You can call a function as many times as you like after defining it once.”, “answer”: “True”, “submitted_answer”: “” }

Adding Parameters to Customize Behavior

Right now every tree is the same height. Parameters let callers choose different values. Adding a height parameter — with a default value of 1.5 — lets you vary the tree without making it required:

def make_tree(scene, x, z, height=1.5):
    ...

make_tree(scene, 0, 0) still works and uses the default height. make_tree(scene, 0, 0, height=3.0) overrides it with a taller tree.

Run the cell below to see three trees of different heights side by side.

import scene3d

scene = scene3d.Scene()
scene.set_sky(scene3d.Sky.PURE_SKY)
scene.set_ground(length=20, width=20)

def make_tree(scene, x, z, height=1.5):
  trunk = scene3d.Shapes.Cylinder(diameter=0.3, height=height, tessellation=8)
  trunk.set_color('#8B4513')
  trunk.set_position(x, height / 2, z)
  scene.add(trunk)
  leaf_diameter = height * 1.4
  leaves = scene3d.Shapes.Sphere(diameter=leaf_diameter, segments=12)
  leaves.set_color('#228B22')
  leaves.set_position(x, height + leaf_diameter / 2, z)
  scene.add(leaves)

make_tree(scene, -4, 0, height=1.0)
make_tree(scene, 0, 0, height=2.0)
make_tree(scene, 4, 0, height=3.5)

{ “question_type”: “multiple_choice”, “question”: “In the function definition ‘def make_tree(scene, x, z, height=1.5):’, what does height=1.5 mean?”, “options”: [ { “key”: “a”, “text”: “height must always equal 1.5” }, { “key”: “b”, “text”: “height is used as a variable name only” }, { “key”: “c”, “text”: “1.5 is the default value used when the caller doesn’t supply height” }, { “key”: “d”, “text”: “The function will error if height is not exactly 1.5” } ], “answer”: “c”, “submitted_answer”: “” }

Building a Forest — Functions Meet Loops

Functions become even more powerful when combined with loops. The scene below uses make_tree inside a for loop with random positions and heights, building an entire forest from a single function definition.

Run it a few times — a different forest appears each time!

import scene3d
import random

scene = scene3d.Scene()
scene.set_sky(scene3d.Sky.PURE_SKY)
ground = scene.set_ground(length=30, width=30)
ground.set_material(scene3d.Material.Grass.Bright)
ground.set_tiling(8)

def make_tree(scene, x, z, height=1.5):
  trunk = scene3d.Shapes.Cylinder(diameter=0.3, height=height, tessellation=8)
  trunk.set_color('#8B4513')
  trunk.set_position(x, height / 2, z)
  scene.add(trunk)
  leaf_diameter = height * 1.4
  leaves = scene3d.Shapes.Sphere(diameter=leaf_diameter, segments=12)
  leaves.set_color('#228B22')
  leaves.set_position(x, height + leaf_diameter / 2, z)
  scene.add(leaves)

for i in range(12):
  x = random.uniform(-10, 10)
  z = random.uniform(-10, 10)
  h = random.uniform(1.0, 3.5)
  make_tree(scene, x, z, height=h)

{ “question_type”: “freeform”, “question”: “In one sentence, describe the main benefit of grouping code into a function.”, “answer”: “write once reuse”, “submitted_answer”: “” }

Try It Yourself

Use the slider to control how many trees appear in the forest. Notice that no matter the count, the function handles all the placement — you only changed one number.

import scene3d
import random

TREE_COUNT = 8 #@param {type:"slider", min:1, max:25, step:1}

random.seed(99)

scene = scene3d.Scene()
scene.set_sky(scene3d.Sky.PURE_SKY)
ground = scene.set_ground(length=30, width=30)
ground.set_material(scene3d.Material.Grass.Bright)
ground.set_tiling(8)

def make_tree(scene, x, z, height=1.5):
  trunk = scene3d.Shapes.Cylinder(diameter=0.3, height=height, tessellation=8)
  trunk.set_color('#8B4513')
  trunk.set_position(x, height / 2, z)
  scene.add(trunk)
  leaf_diameter = height * 1.4
  leaves = scene3d.Shapes.Sphere(diameter=leaf_diameter, segments=12)
  leaves.set_color('#228B22')
  leaves.set_position(x, height + leaf_diameter / 2, z)
  scene.add(leaves)

for i in range(TREE_COUNT):
  x = random.uniform(-10, 10)
  z = random.uniform(-10, 10)
  h = random.uniform(1.0, 3.5)
  make_tree(scene, x, z, height=h)

Think about a 3D scene you’d like to build — a city with buildings, a reef with coral, a campsite with tents and campfires.

What function would you define? What would you name it, and what parameters would it take? Describe what goes inside the function and how you’d call it to populate your scene.