Professional Documents
Culture Documents
• Software development
and design
• Understanding and using APIs
• Cisco platforms and development
• Application deployment
and security
• Infrastructure and automation
• Network fundamentals
Bookmark ciscopress.com/DEVASC
for more information
* Discount code DEVNET confers a 40% discount off the list price of books, eBooks, and video courses when purchased on
ciscopress.com. Discount code may not be combined with any other offer and is not redeemable for cash. Discount offer
expires 11:59 p.m. EDT on December 31, 2020. Offer subject to change.
DevNet Associate
DEVASC 200-901
Official Cert Guide
Cisco Press
DevNet Associate DEVASC 200-901 Official Cert Guide
Chris Jackson, Jason Gooley, Adrian Iliesiu,
Ashutosh Malegaonkar
Copyright © 2021 Cisco Systems, Inc.
Published by: Cisco Press
Pearson Education, Inc.
All rights reserved. No part of this book may be reproduced or transmitted in any form or by any
means, electronic or mechanical, including photocopying, recording, or by any information
storage and retrieval system, without written permission from the publisher, except for the
inclusion of brief quotations in a review.
ISBN-13: 978-0-13-664296-1
ISBN-10: 0-13-664296-9
Trademark Acknowledgments
All terms mentioned in this book that are known to be trademarks or service marks have been
appropriately capitalized. Cisco Press or Cisco Systems, Inc., cannot attest to the accuracy of this
information. Use of a term in this book should not be regarded as affecting the validity of any
trademark or service mark.
Special Sales
For information about buying this title in bulk quantities, or for special sales opportunities
(which may include electronic versions; custom cover designs; and content particular to your
business, training goals, marketing focus, or branding interests), please contact our corporate
sales department at corpsales@pearsoned.com or (800) 382-3419.
For government sales inquiries, please contact governmentsales@pearsoned.com.
For questions about sales outside the U.S., please contact intlcs@pearson.com.
Contents
Introduction
1 Introduction to Cisco DevNet Associate Certificate
2 Software Development and Design
3 Introduction to Python
4 Python Functions, Classes, and Modules
5 Working with Data in Python
6 Application Programming Interface (API)
7 RESTful API Requests and Responses
8 Cisco Enterprise Networking Management Platforms and APIs
9 Cisco Data Center and Compute Management Platforms and APIs
10 Cisco Collaboration Platforms and APIs
11 Cisco Security Platforms and APIs
12 Model-Driven Programmability
13 Application Deployment
14 Application Security
15 Infrastructure Automation
16 Network Fundamentals
17 Networking Components
18 IP Services
19 Final Preparation
A Answers to DIKTA Quizzes
B Exam Update
C Memory Tables
Glossary
Index
Online Elements
D Memory Table Answers
E Study Planner
CHAPTER 4
Python Functions: This section provides an overview of working with and building Python functions.
Object-Oriented Programing and Python: This section describes key aspects of using object-oriented
programing techniques.
Python Classes: This section provides an overview of creating and using Python classes.
Working with Python Modules: This section provides an overview of creating and using Python
modules.
This chapter moves away from the basics introduced in Chapter 3, “Introduction to Python,” and
introduces Python functions, classes, and modules. Building Python functions allows for the creation of
reusable code and is the first step toward writing object-oriented code. Classes are the Python tools used to
construct Python objects and make it easier to produce scalable applications that are easy to maintain and
readable. Finally, this chapter introduces the wide world of Python modules and how they can extend the
capabilities of Python and make your job of coding much easier.
Caution The goal of self-assessment is to gauge your mastery of the topics in this chapter. If you do not know the
answer to a question or are only partially sure of the answer, you should mark that question as wrong for purposes of
self-assessment. Giving yourself credit for an answer that you correctly guess skews your self-assessment results and
might provide you with a false sense of security.
1. Which of the following is the correct syntax for a Python function?
b. function function(arg);
c. def function(arg):
d. func function(arg):
a. 1function
b. __init__
c. True
d. Funct1on
3. When three single quotation marks are used on the next line directly after defining a function, what
does this indicate?
a. Multi-line text
b. A docstring
c. Configuration templates
d. YAML files
5. Which of the following are benefits of OOP? (Choose all that apply.)
a. Reusable code
b. Easy to follow
d. Complex integration
6. Which of the following are used to define a class in Python? (Choose two.)
a. class classname(parent):
b. class classname:
7. What is a method?
b. Syntax notation
b. Class attributes and methods used as the starting point for another class
9. Which module provides access to the file system and directory structure?
a. filesystem
b. open
c. system
d. os
a. pyATS
b. pyang
c. devnetats
d. ncclient
Foundation Topics
Python Functions
***Key Topic
In Python, a function is a named block of code that can take a wide variety of input parameters (or none at
all) and return some form of output back to the code that called the function to begin with. It represents a
key concept in programing sometimes referred to as DRY, which stands for Don’t Repeat Yourself. The
idea behind DRY is that if you perform some particular operations in your code multiple times, you can
simply create a function to reuse that block of code anywhere you need it instead of duplicating effort by
typing it each time..
Python offers two types of functions: built-in functions that are part of the standard library and functions
you create yourself. The standard library includes a huge number of functions you can use in your
program, like print(), many of which you have already been introduced to in Chapter 3. Building your own
functions is how you construct capabilities that are not already present within the Python language.
***Key Topic
To define a function in Python, you use the keyword def, a name for the function, a set of parentheses
enclosing any arguments you want to pass to the function, and a colon at the end. The name of a function
must follow these rules:
Must not be a reserved Python word, a built-in function (for example, print(), input(), type()), or a
name that has already been used as a function or variable
Can be any combination of the A–Z, a–z, 0–9 and the underscore (_) and dash (-)
The following is an example of an incredibly simple function that could be entered into the interactive
Python interpreter:
Python 3.8.1 (v3.8.1:1b293b6006, Dec 18 2019, 14:08:53)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def devnet():
'''prints simple function'''
print('Simple function')
>>> devnet()
Simple function
This function prints out the string “Simple function” any time you call it with devnet(). Notice the
indented portion that begins on the next line after the colon. Python expects this indented portion to contain
all the code that makes up the function. Keep in mind that whitespace matters in Python. The three single
quotation marks that appear on the first line of the indented text of the function are called a docstring and
can be used to describe what the function does.
As shown in the following example, you can use the built-in Python function help() to learn what a
function does and any methods that can be used:
>>> help(devnet)
Help on function devnet in module __main__:
devnet()
prints simple function
Each function must define how it will use arguments, using parameters to identify what gets passed in and
how it gets used. A parameter is simply a variable that is used in a function definition that allows code
within the function to use the data passed to it. To get results back from the function, you use the keyword
return and the object you want to pass back. The following example shows how to create a function that
subtracts two numbers and stores the result in a local variable called result that gets returned when the
function is called:
>>> def sub(arg1, arg2):
result = arg1 - arg2
return result
The variable result is local, meaning that it is not accessible to the main Python script, and it is used only
within the function itself. If you tried to call result directly, Python would produce an error saying that
result is not defined. You can, however, access global variables from within the function; you might do
this, for example, to set certain constants or key variables that any function can use (for example, IP
addresses). The difference in accessibility between a local variable and global variable is important,
because they allow your code to maintain separation and can keep your functions self-contained.
The previous example uses positional arguments, which must be passed to a function in a particular order.
Positional arguments work with a simple set of consistently applied arguments, but if a function needs
more flexible alignment to parameters within a function, you can use keyword arguments instead. A
keyword argument is a name/value pair that you pass to a function. Instead of using position, you specify
the argument the function uses. It is a lot like assigning a variable to an argument. In the previous example,
arg1 is subtracted from arg2, and if the positions of these arguments were switched, you would get a
different result when subtracting the values. With keyword arguments, it doesn’t matter in what order they
are passed to the function. Here is an example:
>>> sub(arg2=15, arg1=10)
-5
What happens if you don’t know the total number of arguments that are being passed to a function? When
you read in data, you might not know how many arguments to expect. Python allows you to use * and **
(often referred to as *args and **kwargs) to define any number of arguments or keyword arguments. *
and ** allow you to iterate through a list or other collection of data, as shown in this example:
>>> def hello(*args):
for arg in args:
print("Hello", arg, "!")
By using keyword arguments, you can send a list of key/value pairs to a function, as in the following
example:
>>> def hello(**kwargs):
for key, value in kwargs.items():
print("Hello", value, "!")
Hello Caleb !
Hello Sydney !
Hello Savannah !
Note the use of the items() function in the for statement to unpack and iterate through the values.
You can also supply a default value argument in case you have an empty value to send to a function. By
defining a function with an assigned key value, you can prevent an error. If the value in the function
definition is not supplied, Python uses the default, and if it is supplied, Python uses what is supplied when
the function is called and then ignores the default value. Consider this example:
>>> def greeting(name, message="Good morning!"):
print("Hello", name + ', ' + message)
>>> greeting('Caleb')
Hello Caleb, Good morning!
>>> greeting('Sydney', "How are you?")
Hello Sydney, How are you?
Object-Oriented Programing and Python
Python was developed as a modern object-oriented programing (OOP) language. Object-oriented
programing is a computer programing paradigm that makes it possible to describe real-world things and
their relationships to each other. If you wanted to describe a router in the physical world, for example, you
would list all its properties, such as ports, software versions, names, and IP addresses. In addition, you
might list different capabilities or functions of the router that you would want to interact with. OOP was
intended to model these types of relationships programmatically, allowing you to create an object that you
can use anywhere in your code by just assigning it to a variable in order to instantiate it.
***Key Topic
Objects are central to Python; in fact, Python really is just a collection of objects interacting with each
other. An object is self-contained code or data, and the idea of OOP is to break up a program into smaller,
easier-to-understand components. Up until now, you have mainly seen procedural programing techniques,
which take a top-down approach and follow predefined sets of instructions. While this approach works
well for simple programs, to write more sophisticated applications with better scalability, OOP is often the
preferred method used by professional programmers. However, Python is very flexible in that you can mix
and match these two approaches as you build applications.
Functions are an important part of the OOP principles of reusability and object-oriented structure. For the
200-901 DevNet Associate DEVASC exam, you need to be able to describe the benefits and techniques
used in Python to build modular programs. Therefore, you need to know how to use Python classes and
methods, which are covered next.
Python Classes
In Python, you use classes to describe objects. Think of a class as a tool you use to create your own data
structures that contain information about something; you can then use functions (methods) to perform
operations on the data you describe. A class models how something should be defined and represents an
idea or a blueprint for creating objects in Python.
***Key Topic
Creating a Class
Say that you want to create a class to describe a router. The first thing you have to do is define it. In
Python, you define a class by using the class keyword, giving the class a name, and then closing with a
colon. Pep8 (introduced in Chapter 3) recommends capitalizing a class name to differentiate it from a
variable. Here is a simple example of creating a class in Python:
>>> class Router:
pass
This example uses pass as a sort of placeholder that allows the class to be defined and set up to be used as
an object. To make the class more useful, you can add some attributes to it. In the case of a router, you
typically have some values that you want to have when you instantiate the class. Every router has a model
name, a software version, an IP address for management. You also need to pass some values to get started.
The first value is always self. The reason for this will become obvious when you instantiate the class: The
self value passes the object name that you select to instantiate the class. In the following example, the
object you will create is rtr1:
class Router:
'''Router Class'''
def __init__(self, model, swversion, ip_add):
'''intilize values'''
self.model = model
self.swversion = swversion
self.ip_add = ip_add
After defining the class, you add a docstring to document what the class is for and then you create a
function that calls __init__, which is a special case that is used for the setup of the class. (In __init__, the
double underscores are called dunder or magic methods.) Functions that are within the class are called
methods and become actions that you can perform on the object you are creating. To store attributes, you
map the name self and the values you pass to it become variables inside the object, which then store those
values as attributes. The last bit of code instantiates the object itself. Up until now, you have been creating
a template, and by assigning data to the variables within the class, you have been telling Python to build
the object. Now you can access any of the stored attributes of the class by using dot notation, as shown
here:
>>> rtr1.model
'iosV'
When you call rtr1.model, the interpreter displays the value assigned to the variable model within the
object. You can also create more attributes that aren’t defined during initialization, as shown in this
example:
>>> rtr1.desc = 'virtual router'
>>> rtr1.desc
'virtual router'
This example shows how flexible objects are, but you typically want to define any attributes as part of a
class to automate object creation instead of manually assigning values. When building a class, you can
instantiate as many objects as you want by just providing a new variable and passing over some data. Here
is another example of creating a second router object rtr2:
>>> rtr2= Router('isr4221', '16.9.5', '10.10.10.5')
>>> rtr2.model
'isr4221'
Methods
Attributes describe an object, and methods allow you to interact with an object. Methods are functions you
define as part of a class. In the previous section, you created an object and applied some attributes to it.
Example 4-1 shows how you can work with an object by using methods. A method that allows you to see
the details hidden within an object without typing a bunch of commands over and over would be a useful
method to add to a class. Building on the previous example, Example 4-1 adds a new function called
getdesc() to format and print the key attributes of your router. Notice that you pass self to this function
only, as self can access the attributes applied during initialization.
class Router:
'''Router Class'''
def __init__(self, model, swversion, ip_add):
'''intilize values'''
self.model = model
self.swversion = swversion
self.ip_add = ip_add
def getdesc(self):
'''return a formatted description of the router'''
desc = f'Router Model :{self.model}\n'\
f'Software Version :{self.swversion}\n'\
f'Router Management Address:{self.ip_add}'
return desc
There are two routers instantiated in this example: rtr1 and rtr2. Using the print function, you can call the
getdesc() method to return formatted text about the object’s attributes. The following output would be
displayed:
Rtr1
Router Model :iosV
Software Version :15.6.7
Router Management Address:10.10.10.1
Rtr2
Router Model :isr4221
Software Version :16.9.5
Router Management Address:10.10.10.5
Inheritance
***Key Topic
Inheritance in Python classes allows a child class to take on attributes and methods of another class. In the
previous section, Example 4-1 creates a class for routers, but what about switches? If you look at the
Router class, you see that all of the attributes apply to a switch as well, so why not reuse the code already
written for a new Switch class? The only part of Example 4-1 that wouldn’t work for a switch is the
getdesc() method, which prints information about a router. When you use inheritance, you can replace
methods and attributes that need to be different. To inherit in a class, you create the class as shown earlier
in this chapter, but before the colon, you add parentheses that include the class from which you want to
pull attributes and methods. It is important to note that the parent class must come before the child class in
the Python code. Example 4-2 shows how this works, creating a second class named Switch, using the
Router class as parent. In addition, it creates a different getdesc() method that prints text about a switch
rather than about a router.
class Router:
'''Router Class'''
def __init__(self, model, swversion, ip_add):
'''intilize values'''
self.model = model
self.swversion = swversion
self.ip_add = ip_add
def getdesc(self):
'''return a formatted description of the router'''
desc = (f'Router Model :{self.model}\n'
f'Software Version :{self.swversion}\n'
f'Router Management Address:{self.ip_add}')
return desc
class Switch(Router):
def getdesc(self):
'''return a formatted description of the switch'''
desc = (f'Switch Model :{self.model}\n'
f'Software Version :{self.swversion}\n'
f'Switch Management Address:{self.ip_add}')
return desc
You can add another variable names sw1 and instantiate the Switch class just as you did the Router class,
by passing in attributes. If you create another print statement using the newly created sw1 object, you see
the output shown in Example 4-3.
Rtr1
Router Model :iosV
Software Version :15.6.7
Router Management Address:10.10.10.1
Rtr2
Router Model :isr4221
Software Version :16.9.5
Router Management Address:10.10.10.5
Sw1
Switch Model :Cat9300
Software Version :16.9.5
Switch Management Address:10.10.10.8
To learn more about classes, methods, and inheritance, you can refer to the Python documentation.
https://docs.python.org/3/tutorial/classes.html
Low coupling/high cohesion: Modular code should be written in such a way that modules do not
have interdependencies. Each module should be self-contained so that changes to one module do not
affect other modules or code. In addition, a module should only include functions and capabilities
related to what the module is supposed to do. When you spread your code around multiple modules,
bouncing back and forth, it is really difficult to follow. This paradigm is called low coupling/high
cohesion modular design.
Code reusability: Modules allow for easy reusability of your code, which saves you time and makes
it possible to share useful code.
Collaboration: You often need to work with others as you build functional code for an organization.
Being able to split up the work and have different people work on different modules speeds up the
code-production process.
There are a few different ways you can use modules in Python. The first and easiest way is to use one of
the many modules that are included in the Python standard library or install one of thousands of third-party
modules by using pip. Much of the functionality you might need or think of has probably already been
written, and using modules that are already available can save you a lot of time. Another way to use
modules is to build them in the Python language by simply writing some code in your editor, giving the file
a name, and appending a .py extension. Using your own custom modules does add a bit of processing
overhead to your application, as Python is an interpreted language and has to convert your text into
machine-readable instructions on the fly. Finally, you can program a module in the C language, compile it,
and then add its capabilities to your Python program. Compared to writing your own modules in Python,
this method results in faster runtime for your code, but it is a lot more work. Many of the third-party
modules and those included as part of the standard library in Python are built this way.
Importing a Module
All modules are accessed the same way in Python: by, using the import command. Within a program—by
convention at the very beginning of the code—you type import followed by the module name you want to
use. The following example uses the math module from the standard library:
>>> import math
>>> dir(math)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh',
'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees',
'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum',
'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma',
'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder',
'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
After you import a module, you can use the dir() function to get a list of all the methods available as part
of the module. The ones in the beginning with the __ are internal to Python and are not generally useful in
your programs. All the others, however, are functions that are now available for your program to access.
As shown in Example 4-4, you can use the help() function to get more details and read the documentation
on the math module.
Example 4-4 math Module Help
>>> help(math)
Help on module math:
NAME
math
MODULE REFERENCE
https://docs.python.org/3.8/library/math
DESCRIPTION
This module provides access to the mathematical functions
defined by the C standard.
FUNCTIONS
acos(x, /)
Return the arc cosine (measured in radians) of x.
acosh(x, /)
Return the inverse hyperbolic cosine of x.
asin(x, /)
Return the arc sine (measured in radians) of x.
-Snip for brevity-
You can also use help() to look at the documentation on a specific function, as in this example:
>>> help(math.sqrt)
Help on built-in function sqrt in module math:
sqrt(x, /)
Return the square root of x.
If you want to get a square root of a number, you can use the sqrt() method by calling math.sqrt and
passing a value to it, as shown here:
>>> math.sqrt(15)
3.872983346207417
You have to type a module’s name each time you want to use one of its capabilities. This isn’t too painful
if you’re using a module with a short name, such as math, but if you use a module with a longer name,
such as the calendar module, you might wish you could shorten the module name. Python lets you do this
by adding as and a short version of the module name to the end of the import command. For example, you
can use this command to shorten the name of the calendar module to cal.
>>> import calendar as cal
Now you can use cal as an alias for calendar in your code, as shown in this example:
>>> print(cal.month(2020, 2, 2, 1))
February 2020
Mo Tu We Th Fr Sa Su
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29
Importing a whole module when you need only a specific method or function adds unneeded overhead. To
help with this, Python allows you to import specific methods by using the from syntax. Here is an example
of importing the sqrt() and tan() methods:
>>> from math import sqrt,tan
>>> sqrt(15)
3.872983346207417
As you can see here, you can import more than one method by separating the methods you want with
commas.
Notice that you no longer have to use math.sqrt and can just call sqrt() as a function, since you imported
only the module functions you needed. Less typing is always a nice side benefit.
Depending on your OS (this output is from a Mac), the previous code might look different from what you
see here, but it should still show you what Python sees, so it is useful if you are having trouble importing a
module.
If you remove the class from the code shown in Example 4-2 and store it in a separate file named
device.py, you can import the classes from your new module and end up with the following program,
which is a lot more readable while still operating exactly the same:
from device import Router, Switch
When you execute this program, you get the output shown in Example 4-5. If you compare these results
with the results shown in Example 4-3, you see that they are exactly the same. Therefore, the device
module is just python code that is stored in another file but used in your program.
Rtr1
Router Model :iosV
Software Version :15.6.7
Router Management Address:10.10.10.1
Rtr2
Router Model :isr4221
Software Version :16.9.5
Router Management Address:10.10.10.5
Sw1
Switch Model :Cat9300
Software Version :16.9.5
Router Management Address:10.10.10.8
***Key Topic
General-purpose standard library modules:
pprint: The pretty print module is a more intelligent print function that makes it much easier to
display text and data by, for example, aligning data for better readability. Use the following
command to import this module:
from pprint import pprint
sys: This module allows you to interact with the Python interpreter and manipulate and view
values. Use the following command to import this module:
import sys
os: This module gives you access to the underlying operating system environment and file
system. It allows you to open files and interact with OS variables. Use the following command to
import this module:
import os
datetime: This module allows you to create, format, and work with calendar dates and time. It
also enables timestamps and other useful additions to logging and data. Use the following
command to import this module:
import datetime
time: This module allows you to add time-based delays and clock capabilities to your Python
apps. Use the following command to import this module:
import time
csv: This is a standard library module for understanding CSV files. It is useful for exporting
Excel spreadsheets into a format that you can then import into Python as a data source. It can, for
example, read in a CSV file and use it as a Python list data type. Use the following command to
import this module:
import csv
json: This is a standard library module for reading JSON-formatted data sources and easily
converting them to dictionaries. Use the following command to import this module:
import json
PyYAML: This module converts YAML files to Python objects that can be converted to Python
dictionaries or lists. Use the following command to install this module:
pip install PyYAML
pyang: This isn’t a typical module you import into a Python program. It’s a utility written in
Python that you can use to verify your YANG models, create YANG code, and transform YANG
models into other data structures, such as XSD (XML Schema Definition). Use the following
command to install this module:
pip install pyang
ncclient: This Python library helps with client-side scripting and application integration for the
NETCONF protocol. Use the following command to install this module:
pip install ncclient
Automation tools:
napalm: napalm (Network Automation and Programmability Abstraction Layer with
Multivendor Support) is a Python module that provides functionality that works in a multivendor
fashion. Use the following command to install this module:
pip install napalm
Testing tools:
unittest: This standard library testing module is used to test the functionality of Python code. It is
often used for automated code testing and as part of test-driven development methodologies. Use
the following command to import this module:
import unittest
pyats: This module was a gift from Cisco to the development community. Originally named
Genie, it was an internal testing framework used by Cisco developers to validate their code for
Cisco products. pyats is an incredible framework for constructing automated testing for
infrastructure as code. Use the following command to install this module:
Pip install pyats (just installs the core framework, check documentation for more options)
Many parts of the pyats framework can be imported. Check the documentation on how to use it.
Chapter 5, “Working with Data in Python,” places more focus on techniques and tools used to interact with
data in Python. This will round out the key Python knowledge needed to follow along with the examples in
the rest of the book.
***Key Topic