Functions

Previously, we’ve seen functions and methods built in to Python (such as range and zip) and built in to different data types (string, list, and dictionary methods). Functions allow us to create reusable chunks of code that we can call throughout our scripts. Functions are written in the form

def function_name(optional, list, of, arguments):
    # statements

def my_print_function():
   print('woohoo!')

my_print_function()
woohoo!
for x in range(3):
   my_print_function()
woohoo!
woohoo!
woohoo!

Functions also accept arguments that get passed into your function.

def print_my_own_range(start, stop, step):
    x = start
    while x < stop:
        print(x)
        x += step

print_my_own_range(0, 5, 2)
0
2
4

Functions can return values.

def get_my_own_range(start, stop, step):
    x = start
    list_to_return = []
    while x < stop:
        list.append(x)
        x += step
    return list_to_return

x = getMyOwnRange(0, 5, 2)
print(x)
[0, 2, 4]

Functions can also return multiple values.

def get_surrounding_numbers(number):
    return number + 1, number - 1

x, y = get_surrounding_numbers(3)
print(x, y)
2 4

Function Arguments

Function parameters (arguments) can be passed to functions a few different ways. The first is positional where the arguments are matched in order left to right:

def func(x, y, z):
   pass

func(1, 2, 3)       # Uses x = 1, y = 2, z = 3

Functions can have a default value if a value isn't passed in:

def func(x, y=3, z=10):
   pass

func(1)             # Uses x = 1, y = 3, z = 10

You can also specify the names of arguments you are passing if you only want to pass certain arguments. These are called keyword arguments. This is the method used in the Maya commands.

def func(x=1, y=3, z=10):
    pass

func(y=5)           # Uses x = 1, y = 5, z = 10

You can also have an arbitrary number of arguments:

def func(*args):
    print(args)

func(1, 2, 3, 4)      # Passes the arguments as a tuple
(1, 2, 3, 4)

And you can have an arbitrary number of keyword arguments:

def func(**kwargs):
    print(kwargs)

func(joints=1, x=2, y=3, z=4)      # Passes the arguments as a dictionary
{'y': 3, 'joints': 1, 'z': 4, 'x': 2}

Often you will see code where the arguments are unknown and both *arg and **kwargs will be used:

def func(*args, **kwargs):
    print(args)
    print(kwargs)

func('a', 'b', joints=1, x=2, y=3, z=4)
('a', 'b')
{'y': 3, 'joints': 1, 'z': 4, 'x': 2}

Scope

Scope is the place where variables and functions are valid. Depending on what scope you create a variable, it may or may not be valid in other areas of your code.

def my_function():
   x = 1     # x is in the local scope of my_function

Basic scope rules:

  1. The enclosing module (the .py file you create the variable in) is a global scope.
  2. Global scope spans a single file only.
  3. Each call to a function is a new local scope.
  4. Assigned names are local, unless declared global.

Examples:

x = 10
def func():
    x = 20

func()
print(x)       # prints 10 because the function creates its own local scope
x = 10
def func():
    global x
    x = 20

func()
print(x)       # prints 20 because we explicitly state we want to use the global x
x = 10
def func():
    print(x)
func()        # prints 10 because there is no variable x declared in the local
              # scope of the function so Python searches the next highest scope

Lambda Expressions

Lambda expressions are basically a way of writing short functions. Normal functions are usually of the form:

def name(arg1, arg2):
    # statements...

Lambda expressions are of the form:

lambda arg1, arg2: expression

This is useful because we can embed functions straight into the code that uses it. For example, say we had the following code:

def increment(x):
    return x + 1
def decrement(x):
    return x – 1
def crazy(x):
    return x / 2.2 ** 3.0

D = {'f1': increment, 'f2': decrement, 'f3': crazy}
D['f1'](2)

A drawback of this is that the function definitions are declared elsewhere in the file. Lambda expressions allow us to achieve the same effect as follows:

D = {
    'f1': (lambda x: x + 1),
    'f2': (lambda x: x - 1),
    'f3': (lambda x: x / 2.2 ** 3.0)
}
D['f1'](2)

Note that lambda bodies are a single expression, not a block of statements. It is similar to what you put in a def return statement. When you are just starting out using Python in Maya, you probably won’t be using many lambda expressions, but just be aware that they exist.