<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 What is introspection?
From IBM https
Step1:  When we typed help(), we were greeted with a message and some instructions, followed by the help prompt. At the prompt, we entered keywords and were shown a list of Python keywords. Having gotten the answer to our question, we then quit the help utility, saw a brief farewell message, and were returned to the Python prompt.
As you can see from this example, Python's online help utility displays information on a variety of topics, or for a particular object. The help utility is quite useful, and does make use of Python's introspection capabilities. But simply using help doesn't reveal how help gets its information. And since the purpose of this article is to reveal all of Python's introspection secrets, we need to quickly go beyond the help utility.
Before we leave help, let's use it to get a list of available modules. Modules are simply text files containing Python code whose names end in .py. If we type help('modules') at the Python prompt, or enter modules at the help prompt, we'll see a long list of available modules, similar to the partial list shown below. Try it yourself to see what modules are available on your system, and to see why Python is considered to come with "batteries included."
Listing 5. Partial listing of available modules
Step2:  The sys module
One module that provides insightful information about Python itself is the sys module. You make use of a module by importing the module and referencing its contents (such as variables, functions, and classes) using dot (.) notation. The sys module contains a variety of variables and functions that reveal interesting details about the current Python interpreter. Let's take a look at some of them. Again, we're going to run Python interactively and enter commands at the Python command prompt. The first thing we'll do is import the sys module. Then we'll enter the sys.executable variable, which contains the path to the Python interpreter
Step3:  When we enter a line of code that consists of nothing more than the name of an object, Python responds by displaying a representation of the object, which, for simple objects, tends to be the value of the object. In this case, since the displayed value is enclosed in quotes, we get a clue that sys.executable is probably a string object. We'll look at other, more precise, ways to determine an object's type later, but simply typing the name of an object at the Python prompt is a quick and easy form of introspection.
Let's look at some other useful attributes of the sys module.
The platform variable tells us which operating system we are on
Step4:  The current Python version is available as a string, and as a tuple (a tuple contains a sequence of objects)
Step5:  The argv variable is a list containing command line arguments, if any were specified. The first item, argv[0], is the path of the script that was run. When we run Python interactively this value is an empty string
Step6:  The modules variable is a dictionary that maps module names to module objects for all the currently loaded modules. As you can see, Python loads certain modules by default
Step7:  The keyword module
Let's return to our question about Python keywords. Even though help showed us a list of keywords, it turns out that some of help's information is hardcoded. The list of keywords happens to be hardcoded, which isn't very introspective after all. Let's see if we can get this information directly from one of the modules in Python's standard library. If we type help('modules keywords') at the Python prompt we see the following
Step8:  Here is a list of matching modules.  Enter any module name to get more help.
keyword - Keywords (from "graminit.c")
So it appears as though the keyword module might contain keywords. By opening the keyword.py file in a text editor we can see that Python does make its list of keywords explicitly available as the kwlist attribute of the keyword module. We also see in the keyword module comments that this module is automatically generated based on the source code of Python itself, guaranteeing that its list of keywords is accurate and complete
Step9:  The dir() function
While it's relatively easy to find and import a module, it isn't as easy to remember what each module contains. And you don't always want to have to look at the source code to find out. Fortunately, Python provides a way to examine the contents of modules (and other objects) using the built-in dir() function.
The dir() function is probably the most well-known of all of Python's introspection mechanisms. It returns a sorted list of attribute names for any object passed to it. If no object is specified, dir() returns the names in the current scope. Let's apply dir() to our keyword module and see what it reveals
Step10:  And how about the sys module we looked at earlier?
The sys module's attributes
Step11:  Without any argument, dir() returns names in the current scope. Notice how keyword and sys appear in the list, since we imported them earlier. Importing a module adds the module's name to the current scope
Step12:  So builtins appears to be a name in the current scope that's bound to the module object named builtin. (Since modules are not simple objects with single values, Python displays information about the module inside angle brackets instead.) Note that if you look for a builtin.py file on disk you'll come up empty-handed. This particular module object is created out of thin air by the Python interpreter, because it contains items that are always available to the interpreter. And while there is no physical file to look at, we can still apply our dir() function to this object to see all the built-in functions, error objects, and a few miscellaneous attributes that it contains
Step13:  The dir() function works on all object types, including strings, integers, lists, tuples, dictionaries, functions, custom classes, class instances, and class methods. Let's apply dir() to a string object and see what Python returns. As you can see, even a simple Python string has a number of attributes
Step14:  Try the following examples yourself to see what they return. Note that the # character marks the start of a comment. Everything from the start of the comment to the end of the line is ignored by Python
Step17:  To illustrate the dynamic nature of Python's introspection capabilities, let's look at some examples using dir() on a custom class and some class instances. We're going to define our own class interactively, create some instances of the class, add a unique attribute to only one of the instances, and see if Python can keep all of this straight. Here are the results
Step18:  Documentation strings
One attribute you may have noticed in a lot of our dir() examples is the doc attribute. This attribute is a string containing the comments that describe an object. Python calls this a documentation string, or docstring, and here is how it works. If the first statement of a module, class, method, or function definition is a string, then that string gets associated with the object as its doc attribute. For example, take a look at the docstring for the builtins object. We'll use Python's print statement to make the output easier to read, since docstrings often contain embedded newlines (\n)
Step19:  Once again, Python even maintains docstrings on classes and methods that are defined interactively in the Python shell. Let's look at the docstrings for our Person class and its intro method
Step20:  Because docstrings provide such valuable information, many Python development environments have ways of automatically displaying the docstrings for objects. Let's look at one more docstring, for the dir() function
Step21:  Interrogating Python objects
We've mentioned the word "object" several times, but haven't really defined it. An object in a programming environment is much like an object in the real world. A real object has a certain shape, size, weight, and other characteristics. And a real object is able to respond to its environment, interact with other objects, or perform a task. Computer objects attempt to model the objects that surround us in the real world, including abstract objects like documents and schedules and business processes.
Like real-world objects, several computer objects may share common characteristics while maintaining their own minor variations. Think of the books you see in a bookstore. Each physical copy of a book might have a smudge, or a few torn pages, or a unique identification number. And while each book is a unique object, every book with the same title is merely an instance of an original template, and retains most of the characteristics of the original.
The same is true about object-oriented classes and class instances. For example, every Python string is endowed with the attributes we saw revealed by the dir() function. And in a previous example, we defined our own Person class, which acted as a template for creating individual Person instances, each having its own name and age values, while sharing the ability to introduce itself. That's object-orientation.
In computer terms, then, objects are things that have an identity and a value, are of a certain type, possess certain characteristics, and behave in a certain way. And objects inherit many of their attributes from one or more parent classes. Other than keywords and special symbols (like operators, such as +, -, *, **, /, %, <, >, etc.) everything in Python is an object. And Python comes with a rich set of object types
Step22:  Modules have names, and the Python interpreter itself is considered the top-level, or main, module. When you run Python interactively the local name variable is assigned a value of 'main'. Likewise, when you execute a Python module from the command line, rather than importing it into another module, its name attribute is assigned a value of 'main', rather than the actual name of the module. In this way, modules can look at their own name value to determine for themselves how they are being used, whether as support for another program or as the main application executed from the command line. Thus, the following idiom is quite common in Python modules
Step23:  Type
The type() function helps us determine whether an object is a string or an integer or some other kind of object. It does this by returning a type object, which can be compared to the types defined in the types module
Step24:  Types that are part of optional modules (e.g. array) are not listed.
Step25:  Identity
We said earlier that every object has an identity, a type, and a value. What's important to note is that more than one variable may refer to the exact same object, and, likewise, variables may refer to objects that look alike (having the same type and value), but have separate and distinct identities. This notion of object identity is particularly important when making changes to objects, such as appending an item to a list, as in the example below where the blist and clist variables both reference the same list object. As you can see in the example, the id() function returns the unique identifier for any given object
Step26:  Attributes
We've seen that objects have attributes, and that the dir() function will return a list of these attributes. Sometimes, however, we simply want to test for the existence of one or more attributes. And if an object has the attribute in question, we often want to retrieve that attribute. These tasks are handled by the hasattr() and getattr() functions, as illustrated in this example
Step27:  Callables
Objects that represent potential behavior (functions and methods) can be invoked, or called. We can test an object's callability with the callable() function
Step28:  Instances
While the type() function gave us the type of an object, we can also test an object to determine if it is an instance of a particular type, or custom class, using the isinstance() function
Step30:  Subclasses
We mentioned earlier that instances of a custom class inherit their attributes from the class. At the class level, a class may be defined in terms of another class, and will likewise inherit attributes in a hierarchical fashion. Python even supports multiple inheritance, meaning an individual class can be defined in terms of, and inherit from, more than one parent class. The issubclass() function allows us to find out if one class inherits from another
Step32:  Interrogation time
Let's wrap things up by putting together several of the introspection techniques we've covered in the last section. To do so, we're going to define our own function, interrogate(), which prints a variety of information about any object passed to it. Here is the code, followed by several examples of its use
<ASSISTANT_TASK:>
Python Code:
__builtins__?  # ipython help on object (module) __builtins__
__builtins__?? # should also show code if present (not built in)
help(__builtins__) # extended help (python)
help() # type keywords below to see keywords and quit to quit
Explanation: What is introspection?
From IBM https://www.ibm.com/developerworks/library/l-pyint/
Print statements adapted for Python3 by Olsthoorn, Dec.2016
In everyday life, introspection is the act of self-examination. Introspection refers to the examination of one's own thoughts, feelings, motivations, and actions. The great philosopher Socrates spent much of his life in self-examination, encouraging his fellow Athenians to do the same. He even claimed that, for him, "the unexamined life is not worth living." (See Resources for links to more about Socrates.)
In computer programming, introspection refers to the ability to examine something to determine what it is, what it knows, and what it is capable of doing. Introspection gives programmers a great deal of flexibility and control. Once you've worked with a programming language that supports introspection, you may similarly feel that "the unexamined object is not worth instantiating."
This article introduces the introspection capabilities of the Python programming language. Python's support for introspection runs deep and wide throughout the language. In fact, it would be hard to imagine Python without its introspection features. By the end of this article you should be very comfortable poking inside the hearts and souls of your own Python objects.
We'll begin our exploration of Python introspection in the most general way possible, before diving into more advanced techniques. Some might even argue that the features we begin with don't deserve to be called "introspective." We'll have to agree that whether they fall under the umbrella of introspection or not is open to debate. For the purposes of this article, our only concern is finding the answers to interesting questions.
So let's begin our inquiry, using Python interactively. When we start Python from the command line, we enter the Python shell, where we can enter Python code and get an immediate response from the Python interpreter. (The commands listed in this article will should execute properly using Python3. You may get different results or errors if using an earlier version.
We're running IPython in a jupyter notebook, therefore, Python is already running.
You may be wondering what words will be recognized by Python. Most programming languages have reserved words, or keywords, that have special meaning in that language, and Python is no exception. You may also have noticed that Python suggested we type help to get more information. Perhaps we can ask Python for some help about keywords.
Python's online help utility
Let's start by typing help, as suggested, and see if it gives us any clues about keywords:
Asking Python for help:
Type help() for interactive help, or help(object) for help about object.
Since we don't know what object might contain keywords, let's try help() without specifying any particular object:
Listing 3. Starting the help utility
End of explanation
#help('modules') # there is an error in my Ipython implementation
Explanation: When we typed help(), we were greeted with a message and some instructions, followed by the help prompt. At the prompt, we entered keywords and were shown a list of Python keywords. Having gotten the answer to our question, we then quit the help utility, saw a brief farewell message, and were returned to the Python prompt.
As you can see from this example, Python's online help utility displays information on a variety of topics, or for a particular object. The help utility is quite useful, and does make use of Python's introspection capabilities. But simply using help doesn't reveal how help gets its information. And since the purpose of this article is to reveal all of Python's introspection secrets, we need to quickly go beyond the help utility.
Before we leave help, let's use it to get a list of available modules. Modules are simply text files containing Python code whose names end in .py. If we type help('modules') at the Python prompt, or enter modules at the help prompt, we'll see a long list of available modules, similar to the partial list shown below. Try it yourself to see what modules are available on your system, and to see why Python is considered to come with "batteries included."
Listing 5. Partial listing of available modules
End of explanation
import sys
sys.executable
Explanation: The sys module
One module that provides insightful information about Python itself is the sys module. You make use of a module by importing the module and referencing its contents (such as variables, functions, and classes) using dot (.) notation. The sys module contains a variety of variables and functions that reveal interesting details about the current Python interpreter. Let's take a look at some of them. Again, we're going to run Python interactively and enter commands at the Python command prompt. The first thing we'll do is import the sys module. Then we'll enter the sys.executable variable, which contains the path to the Python interpreter:
Listing 6. Importing the sys module
End of explanation
sys.platform
Explanation: When we enter a line of code that consists of nothing more than the name of an object, Python responds by displaying a representation of the object, which, for simple objects, tends to be the value of the object. In this case, since the displayed value is enclosed in quotes, we get a clue that sys.executable is probably a string object. We'll look at other, more precise, ways to determine an object's type later, but simply typing the name of an object at the Python prompt is a quick and easy form of introspection.
Let's look at some other useful attributes of the sys module.
The platform variable tells us which operating system we are on:
The sys.platform attribute
End of explanation
sys.version
Explanation: The current Python version is available as a string, and as a tuple (a tuple contains a sequence of objects):
The sys.version and sys.version_info attributes
End of explanation
sys.path
Explanation: The argv variable is a list containing command line arguments, if any were specified. The first item, argv[0], is the path of the script that was run. When we run Python interactively this value is an empty string:
Listing 10. The sys.argv attribute
The path variable is the module search path, the list of directories in which Python will look for modules during imports. The empty string, '', in the first position refers to the current directory:
Listing 12. The sys.path attribute
End of explanation
sys.modules
Explanation: The modules variable is a dictionary that maps module names to module objects for all the currently loaded modules. As you can see, Python loads certain modules by default:
Listing 13. The sys.modules attribute
End of explanation
help('modules keywords') # There is an error in my python implemetation (TODO, reinstall)
Explanation: The keyword module
Let's return to our question about Python keywords. Even though help showed us a list of keywords, it turns out that some of help's information is hardcoded. The list of keywords happens to be hardcoded, which isn't very introspective after all. Let's see if we can get this information directly from one of the modules in Python's standard library. If we type help('modules keywords') at the Python prompt we see the following:
Listing 14. Asking for help on modules with keywords
End of explanation
import keyword
Explanation: Here is a list of matching modules.  Enter any module name to get more help.
keyword - Keywords (from "graminit.c")
So it appears as though the keyword module might contain keywords. By opening the keyword.py file in a text editor we can see that Python does make its list of keywords explicitly available as the kwlist attribute of the keyword module. We also see in the keyword module comments that this module is automatically generated based on the source code of Python itself, guaranteeing that its list of keywords is accurate and complete:
Listing 15. The keyword module's keyword list
End of explanation
dir(keyword)
Explanation: The dir() function
While it's relatively easy to find and import a module, it isn't as easy to remember what each module contains. And you don't always want to have to look at the source code to find out. Fortunately, Python provides a way to examine the contents of modules (and other objects) using the built-in dir() function.
The dir() function is probably the most well-known of all of Python's introspection mechanisms. It returns a sorted list of attribute names for any object passed to it. If no object is specified, dir() returns the names in the current scope. Let's apply dir() to our keyword module and see what it reveals:
Listing 16. The keyword module's attributes
End of explanation
import sys
dir(sys)
Explanation: And how about the sys module we looked at earlier?
The sys module's attributes
End of explanation
dir()
__builtins__
Explanation: Without any argument, dir() returns names in the current scope. Notice how keyword and sys appear in the list, since we imported them earlier. Importing a module adds the module's name to the current scope:
Listing 18. Names in the current scope
End of explanation
dir(__builtins__)
Explanation: So builtins appears to be a name in the current scope that's bound to the module object named builtin. (Since modules are not simple objects with single values, Python displays information about the module inside angle brackets instead.) Note that if you look for a builtin.py file on disk you'll come up empty-handed. This particular module object is created out of thin air by the Python interpreter, because it contains items that are always available to the interpreter. And while there is no physical file to look at, we can still apply our dir() function to this object to see all the built-in functions, error objects, and a few miscellaneous attributes that it contains:
Listing 20. The builtins module's attributes
End of explanation
dir('this is a string')
Explanation: The dir() function works on all object types, including strings, integers, lists, tuples, dictionaries, functions, custom classes, class instances, and class methods. Let's apply dir() to a string object and see what Python returns. As you can see, even a simple Python string has a number of attributes:
Listing 21. String attributes
End of explanation
dir(42)   # Integer (and the meaning of life)
dir([])   # List (an empty list, actually)
dir(())   # Tuple (also empty)
dir({})   # Dictionary (ditto)
dir(dir)  # Function (functions are also objects)
Explanation: Try the following examples yourself to see what they return. Note that the # character marks the start of a comment. Everything from the start of the comment to the end of the line is ignored by Python:
Using dir() on other objects
End of explanation
class Person(object):
    Person class.
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def intro(self):
        Return an introduction.
        return "Hello, my name is {:s} and I'm {:d}.".format(self.name, self.age)
bob = Person("Robert", 35)   # Create a Person instance
joe = Person("Joseph", 17)   # Create another
joe.sport = "football"       # Assign a new attribute to one instance
dir(Person)      # Attributes of the Person class
dir(bob)         # Attributes of bob
dir(joe)         # Note that joe has an additional attribute
bob.intro()      # Calling bob's intro method
dir(bob.intro)   # Attributes of the intro method
Explanation: To illustrate the dynamic nature of Python's introspection capabilities, let's look at some examples using dir() on a custom class and some class instances. We're going to define our own class interactively, create some instances of the class, add a unique attribute to only one of the instances, and see if Python can keep all of this straight. Here are the results:
Using dir() on custom classes, class instances, and attributes
End of explanation
print(__builtins__.__doc__)   # Module docstring
Explanation: Documentation strings
One attribute you may have noticed in a lot of our dir() examples is the doc attribute. This attribute is a string containing the comments that describe an object. Python calls this a documentation string, or docstring, and here is how it works. If the first statement of a module, class, method, or function definition is a string, then that string gets associated with the object as its doc attribute. For example, take a look at the docstring for the builtins object. We'll use Python's print statement to make the output easier to read, since docstrings often contain embedded newlines (\n):
Listing 24. Module docstring
End of explanation
Person.__doc__         # Class docstring
Person.intro.__doc__   # Class method docstring
Explanation: Once again, Python even maintains docstrings on classes and methods that are defined interactively in the Python shell. Let's look at the docstrings for our Person class and its intro method:
Class and method docstrings:
End of explanation
print(dir.__doc__)   # Function docstring
Explanation: Because docstrings provide such valuable information, many Python development environments have ways of automatically displaying the docstrings for objects. Let's look at one more docstring, for the dir() function:
End of explanation
dir()                # The dir() function
directory = dir      # Create a new variable
directory()          # Works just like the original object
dir.__name__         # What's your name?
directory.__name__   # My name is the same
__name__             # And now for something completely different
Explanation: Interrogating Python objects
We've mentioned the word "object" several times, but haven't really defined it. An object in a programming environment is much like an object in the real world. A real object has a certain shape, size, weight, and other characteristics. And a real object is able to respond to its environment, interact with other objects, or perform a task. Computer objects attempt to model the objects that surround us in the real world, including abstract objects like documents and schedules and business processes.
Like real-world objects, several computer objects may share common characteristics while maintaining their own minor variations. Think of the books you see in a bookstore. Each physical copy of a book might have a smudge, or a few torn pages, or a unique identification number. And while each book is a unique object, every book with the same title is merely an instance of an original template, and retains most of the characteristics of the original.
The same is true about object-oriented classes and class instances. For example, every Python string is endowed with the attributes we saw revealed by the dir() function. And in a previous example, we defined our own Person class, which acted as a template for creating individual Person instances, each having its own name and age values, while sharing the ability to introduce itself. That's object-orientation.
In computer terms, then, objects are things that have an identity and a value, are of a certain type, possess certain characteristics, and behave in a certain way. And objects inherit many of their attributes from one or more parent classes. Other than keywords and special symbols (like operators, such as +, -, *, **, /, %, <, >, etc.) everything in Python is an object. And Python comes with a rich set of object types: strings, integers, floats, lists, tuples, dictionaries, functions, classes, class instances, modules, files, etc.
When you have an arbitrary object, perhaps one that was passed as an argument to a function, you may want to know a few things about that object. In this section we're going to show you how to get Python objects to answer questions such as:
What is your name?
What kind of object are you?
What do you know?
What can you do?
Who are your parents?
Name
Not all objects have names, but for those that do, the name is stored in their name attribute. Note that the name is derived from the object, not the variable that references the object. The following example highlights that distinction:
What's in a name?
End of explanation
if __name__ == '__main__':
    # Do something appropriate here, like calling a
    # main() function defined elsewhere in this module.
    main()
else:
    # Do nothing. This module has been imported by another
    # module that wants to make use of the functions,
    # classes and other useful bits it has defined.
    pass
Explanation: Modules have names, and the Python interpreter itself is considered the top-level, or main, module. When you run Python interactively the local name variable is assigned a value of 'main'. Likewise, when you execute a Python module from the command line, rather than importing it into another module, its name attribute is assigned a value of 'main', rather than the actual name of the module. In this way, modules can look at their own name value to determine for themselves how they are being used, whether as support for another program or as the main application executed from the command line. Thus, the following idiom is quite common in Python modules:
Testing for execution or import:
End of explanation
import types
Explanation: Type
The type() function helps us determine whether an object is a string or an integer or some other kind of object. It does this by returning a type object, which can be compared to the types defined in the types module:
Am I your type?
End of explanation
dir(types)
def s(x): return x**2
type(s)
if type(s) is types.FunctionType: print("s is a function")
type(42)
type([])
type({})
type(dir)
Explanation: Types that are part of optional modules (e.g. array) are not listed.
End of explanation
print(id.__doc__)
alist = [1, 2, 3]
blist = [1, 2, 3]
clist = blist
clist
blist
alist
id(alist)
id(blist)
id(clist)
alist is blist
blist is clist
clist.append(4)
clist
blist
alist
Explanation: Identity
We said earlier that every object has an identity, a type, and a value. What's important to note is that more than one variable may refer to the exact same object, and, likewise, variables may refer to objects that look alike (having the same type and value), but have separate and distinct identities. This notion of object identity is particularly important when making changes to objects, such as appending an item to a list, as in the example below where the blist and clist variables both reference the same list object. As you can see in the example, the id() function returns the unique identifier for any given object:
End of explanation
print(hasattr.__doc__)
print(getattr.__doc__)
hasattr(id, '__doc__')
print(getattr(id, '__doc__'))
Explanation: Attributes
We've seen that objects have attributes, and that the dir() function will return a list of these attributes. Sometimes, however, we simply want to test for the existence of one or more attributes. And if an object has the attribute in question, we often want to retrieve that attribute. These tasks are handled by the hasattr() and getattr() functions, as illustrated in this example:
Have an attribute; get an attribute:
End of explanation
print(callable.__doc__)
callable('a string')
callable(dir)
Explanation: Callables
Objects that represent potential behavior (functions and methods) can be invoked, or called. We can test an object's callability with the callable() function:
Can you do something for me?
End of explanation
print(isinstance.__doc__)
isinstance(42, str)
isinstance('a string', int)
isinstance(42, int)
isinstance('a string', str)
Explanation: Instances
While the type() function gave us the type of an object, we can also test an object to determine if it is an instance of a particular type, or custom class, using the isinstance() function:
Are you one of those?
End of explanation
print(issubclass.__doc__)
issubclass(float, complex)
class SuperHero(Person):   # SuperHero inherits from Person...
    def intro(self):       # but with a new SuperHero intro
        Return an introduction.
        return "Hello, I'm SuperHero %s and I'm %s." % (self.name, self.age)
issubclass(SuperHero, Person)
issubclass(Person, SuperHero)
Explanation: Subclasses
We mentioned earlier that instances of a custom class inherit their attributes from the class. At the class level, a class may be defined in terms of another class, and will likewise inherit attributes in a hierarchical fashion. Python even supports multiple inheritance, meaning an individual class can be defined in terms of, and inherit from, more than one parent class. The issubclass() function allows us to find out if one class inherits from another:
End of explanation
def interrogate(item):
    Print useful information about item.
    if hasattr(item, '__name__'):
        print("NAME:    ", item.__name__)
    if hasattr(item, '__class__'):
        print("CLASS:   ", item.__class__.__name__)
        print("ID:      ", id(item))
        print("TYPE:    ", type(item))
        print("VALUE:   ", repr(item))
        print("CALLABLE: ", end="")
    if callable(item):
        print("Yes")
    else:
        print("No")
    if hasattr(item, '__doc__'):
        doc = getattr(item, '__doc__')
        doc = doc.strip()   # Remove leading/trailing whitespace.
        firstline = doc.split('\n')[0]
        print("DOC:     ", firstline)
    print()
interrogate('a string')     # String object
interrogate(43)
interrogate([1, 2, 'a'])
interrogate(('a', 'b', 3))
Explanation: Interrogation time
Let's wrap things up by putting together several of the introspection techniques we've covered in the last section. To do so, we're going to define our own function, interrogate(), which prints a variety of information about any object passed to it. Here is the code, followed by several examples of its use:
End of explanation
<END_TASK>