More Functions¶

Values and Variables¶

7
True
'blue'

number = 7
is_green = True
color = 'blue'

Just like with function names, use _ for compound names.

So, use

is_green = True

instead of

isGreen = True
number = 7
is_green = True
color = 'blue'
another = number

number = 7
number = number + 1

NOTES

The assignment operator = is essentially the "move the arrow to another value" operator.

@Bit.run_from_empty(5, 3)
def run(bit):
    pass

NOTES

Variables defined in a function (either in the function definition or in the function body) are scoped to that function.

def move_twice(bit):
    bit.move()
    bit.move()

@Bit.run_from_empty(5, 3)
def run(bit):
    move_twice(bit)

NOTES

You can have variables of the same name in different scopes (e.g. different functions).

When a function is called, it has to have values for all the parameters in the function signature (or you get a missing argument exception).

The value for bit in run is provided by the @Bit.run_from_empty(5, 3) line. The details about how that works are not important right now.

When you call a function, you give values to the variable names defined in the function signature.

It's just like calling an assignment operator =.

def paint_twice(bit, color):
    bit.move()
    bit.paint(color)
    bit.move()
    bit.paint(color)

@Bit.run_from_empty(5, 3)
def run(bit):
    color = 'blue'
    paint_twice(bit, color)

NOTES

Both variables need values for paint_color to run.

Observe how the arguments are mapped by position.

def paint_twice(bit, color):
    bit.move()
    bit.paint(color)
    bit.move()
    bit.paint(color)
@Bit.run_from_empty(5, 3)
def run(bit):
    color = 'blue'
    paint_twice(bit, color)
    paint_twice(bit, 'red')

</div>

NOTES

Note that when the first call to paint_twice finishes, its variables are cleared. Then those variables get new values when it is called the second time.

In [ ]:
from byubit import Bit

def paint_twice(bit, color):
    bit.move()
    bit.paint(color)
    bit.move()
    bit.paint(color)
    
@Bit.run_from_empty(7, 3)
def run(bit):
    color = 'blue'
    paint_twice(bit, color)
    paint_twice(bit, 'red')
    paint_twice(bit, color)
    

NOTES

Run the code we've been looking at. Observe the result.

Note: passing a value by variable reference paint_twice(bit, color) vs passing a literal value paint_twice(bit, 'red')

In [ ]:
from byubit import Bit

def paint_twice(bit, color):
    bit.move()
    bit.paint(color)
    bit.move()
    bit.paint(color)
    
@Bit.run_from_empty(5, 3)
def run(bit):
    color = 'blue'
    paint_twice(bit)

NOTES

The missing required position argument.

In [ ]:
from byubit import Bit

def paint_twice(bit, color):
    bit.move()
    bit.paint(color)
    bit.move()
    bit.paint(color)
    
@Bit.run_from_empty(5, 3)
def run(bit):
    color = 'blue'
    paint_twice(color)

NOTES

Which argument did we leave out? bit or color?

Again: the arguments are mapped by position. So, paint_twice.bit got the same value as run.color.

Remember: the arguments are mapped by position, not by name.

In [ ]:
from byubit import Bit

def paint_twice(bit, color):
    bit.move()
    bit.paint(color)
    bit.move()
    bit.paint(color)
    
@Bit.run_from_empty(5, 3)
def run(bit):
    color = 'blue'
    paint_twice(color, bit)

'thing' object has no attribute 'name' means the value of a variable is not the type you think it is.

This is often the result of passing arguments in the wrong order.

NOTES

What does this error mean?

Look at the wiring diagram. What was paint_twice.bit pointing to when we tried bit.move()?

'blue' is a str, and str does not have an attribute named move.

"'thing' has no attribute named 'name'" very often means you passed function arguments in the wrong order.

Comparisons¶

Helpful Bit Fact¶

You can get the color of the current square with

bit.get_color()

🎨 == and !=¶

You can determine if two strings are the same using ==.

You can determine if two strings are different using !=.

jump.py¶

Notes

Step through the code.

Note that the comparision operator != (and ==) do not get their own step in the history.

Why doesn't this work?

current_color = bit.get_color()
while current_color != color:
    bit.move()
In [ ]:
%%file jump.py
from byubit import Bit

def jump(bit, color):
    while bit.get_color() != color:
        bit.move()
    bit.snapshot(f'Jumped to {color}')
    
@Bit.run('jump')
def run(bit):
    jump(bit, 'red')
    jump(bit, 'blue')
    jump(bit, 'green')
    jump(bit, 'blue')

👨🏼‍🎨 Follow the path¶

In [ ]:
# Solution
from byubit import Bit

def follow_color(bit):
    color = bit.get_color()
    while bit.get_color() == color:
        bit.move()

@Bit.run('path')
@Bit.pictures('images/')
def run(bit):
    while bit.front_clear():
        follow_color(bit)
        
        if bit.get_color() == 'green':
            bit.left()
        elif bit.get_color() == 'blue':
            bit.right()
            

follow_the_path.py¶

Help Bit follow the path.

When the path changes to green, turn left.

When the path changes to blue, turn right.

When the path changes to red, go straight.

Stop when you run into something.

NOTES

Pattern: getting a snapshot of initial color (color = bit.get_color()) and then comparing back to that dynamically (bit.get_color() == color).

No else block necessary (although you could do else: pass)

Key Ideas¶

  • Values
  • Variables
  • Defining and calling functions with multiple arguments
  • bit.get_color()
  • == and !=