Finding Python

A few tips for manually discovering Python’s features.

Allek Mott
The Startup
6 min readSep 21, 2019

--

When I took my first stab at learning Python, I was initially turned away. It wasn’t syntax or lack of documentation, but rather the sheer amount of unknowns that pop up, almost immediately.

In this article, I’ll walk you through some techniques I found useful, and show you how you can use them to dig into Python yourself.

Examples will appear as they would when typed into the Python shell.

Read the Docs

One of the best places I’ve found to look is Python’s official documentation (also available here for Python 3).

Here, you can find a pretty extensive rundown of all standard modules available in Python. If you’re wondering about the capabilities or syntax of core Python features, and don’t mind technical writing, you’ll likely find your answers.

I’ll reference the documentation quite a bit in this article.

__doc__

Every public function, class, and method in Python’s standard library will ship with documentation in the form of a docstring.

A particular entity’s docstring can be accessed via its __doc__ attribute:

>>> object.__doc__'The most base type'

Some docstrings will span multiple lines, so they may look better printed out:

>>> print(str.__doc__)str(object='') -> stringReturn a nice string representation of the object.
If the argument is a string, the return value is the same object.

Functions

There are a couple functions I’ve found especially useful when it comes to exploring from both the Python shell and while debugging files.

Photo by João Silas on Unsplash

dir

dir is an essential function to familiarise yourself with while you explore Python. It returns a list of attributes of whatever is passed to it. If it isn’t passed anything, it returns all attributes of the current scope.

Wondering what you can do with a particular object?

>>> cool_var = str()
>>> dir(cool_var)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

These are all things you could access using the dot . operator on cool_var:

>>> cool_var.isalnum<built-in method isalnum of str object at 0x109e0b508>

Ok, so cool_var has a method called isalnum. Perhaps isalnum has a docstring?

>>> print(cool_var.isalnum.__doc__)S.isalnum() -> boolReturn True if all characters in S are alphanumeric
and there is at least one character in S, False otherwise.

Well-documented code can be quite the dream.

type

The type function will return the type of a given object.

Pondering the type of a variable?

>>> mystery = str()
>>> type(mystery)
<type 'str'>

Note that <type 'str'> here is the string representation of mystery‘s type. str is the actual type mystery, as we defined it. So if you were to print(str), it would be reasonable to expect the same:

>>> print(str)<type 'str'>

type also has practical use cases outside of exploration. For instance, if you wanted to do something special if something was a str:

>>> if type(mystery) is str:
... print("Not such a mystery anymore, huh.")
...
Not such a mystery anymore, huh.

Builtins

There is a set of classes, objects, and functions, among other things, that will always be there for you in Python. These go by the name builtins, attached to any scope as the module __builtins__.

Photo by Fleur on Unsplash

You can use the dir function to list all properties of this module. These just so happen to be the builtins:

>>> dir(__builtins__)['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']

As you can see, some things we use all the time in Python, like print and len, are included here.

To use these, it isn’t even necessary to prefix them with __builtins__— you can just refer to them as they appear in the list. If you can see it here, be assured that you can use it anywhere you want, and it will always be there. No import necessary.

Imports

Imports seem like magic at first. You just add the line import coolstuff, and all of a sudden, you have a bunch of cool stuff. Where do these packages come from? What other ones are available?

Photo by chuttersnap on Unsplash

In a given context, modules available for import in will be present on what’s called the module search path. Basically, this is a list of folders containing Python scripts.

There are three places Python will look for modules by default:

  1. The directory of the running script
  2. Directories listed in the environment variable PYTHONPATH
  3. Default directories specified by your particular Python installation

Directories included by these three sources are combined into the path property or the sys module, (sys.path). sys.path is a list containing all directories that the running instance of Python should search for modules.

You can actually take a peek yourself:

>>> import sys
>>> print(sys.path)
['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-arm-linux-gnueabihf', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/home/pi/.local/lib/python2.7/site-packages', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']

Inside of these folders will be a bunch of .py files, yours included (since your script's directory will be part of sys.path). There may also be Python packages included — directories containing an __init__.py file, often containing multiple modules, that are treated as a single module with the name of the directory.

When you import something, Python looks for a Python file (.py), cache file (.pyc) or package named something in those directories. If it can't find something, you'll get an ImportError like this: ImportError: No module named something.

__file__

Most modules will have a __file__ attribute containing the path of the actual module file:

>>> import os
>>> os.__file__
'/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'

If you’re ever confused as to where a particular module is coming from, this could point you in the right direction.

That’s a Wrap

Figuring out all of the beautiful tools that Python offers can be tedious at times. I hope these techniques will bring greater ease.

Thanks for reading, and best of luck with your Python endeavours.

--

--