Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Python: Six, ABC, and functools.wraps

DZone's Guide to

Python: Six, ABC, and functools.wraps

The author reviews some new Python skills from code reviewed in Stackstorm.

· Web Dev Zone
Free Resource

Tips, tricks and tools for creating your own data-driven app, brought to you in partnership with Qlik.

Over the past week I went through some Python code in Stackstorm (hosted in GitHub), and by doing so I learned a few cool new things. Maybe ‘new’ is not the right term, but these things were new to me and I wanted to share them with you.

The code I am referring to resides in a few places in Stackstorm, the first item:

@six.add_metaclass(abc.ABCMeta)
class Access(object):

Two things here:

1. six.add_metaclass – makes Access a metaclass in a way which is compatible both with Python2 and Python3. In general, six package has a purpose of helping developers migrate their code from Python 2 to Python 3 by writing code which is compatible with both. Hence the name: six = 2 * 3. To read more: https://pypi.python.org/pypi/six

2. abc.ABCMeta – abc is another builtin package, its purpose is to provide support for Abstract Base Classes. By making a class abstract you ensure that nobody can instantiate objects out of it. This is useful for (at least) three purposes:

a. Maintain logic which is common to multiple classes in one place

b. force the users to implement methods which are annotated by @abc.abstractmethod (you can also force the inheriting classes to create specific class members by using the annotation@abc.abstractproperty). For more info in regards see the docs.

c. creating a singleton. I’m still not convinced about the usefulness of creating a singleton in Python (because we have modules), but assuming you want to do so, you can either create a metaclass and call its methods as ClassName.method() or extend a metaclass but not implement the abstractmethod or abstractproperty. By not implementing the abstract-methods/properties the inheriting class will become abstract as well. This technique is used in a few different places in StackStorm, if you want to see some examples, search for classes that inherit from Access.

3. This one took me a while to wrap my head around (requires a “functional programming” mind if you will):

def decorate(f):
        @functools.wraps(f)
        def callfunction(*args, **kwargs):

By calling @functools.wraps(f) we’re using a decorator inside a decorator. Not trivial…

To understand the main idea of ‘functools.wraps’, it’s easier to go through the following points/process (at least, easier for me…):

  • When you decorate a function, you’re creating a new function that wraps the ‘original’ one, and return the wrapper

  • The wrapper is used in order to be able to perform all kinds of tasks before/after the ‘original’ function is applied. Examples: preparing the arguments for the ‘original function’, timing how long does it take for the function to execute, add log printings before and after and etc.

  • Say you have a wrapped function f, returned from a decorator, the user will then see the description (metadata) of the decorator instead of f, the original function.

  • In order to avoid this confusion, @functools.wraps(f) comes into the picture: by annotating the wrapper function with @functools.wraps(f) – you’re making sure that the user of the wrapper will see the same description/metadata as the original function has. By ‘description’ I mean the function-signature (the name of the function and the names of the arguments it takes).

Hope this is helpful!

Explore data-driven apps with less coding and query writing, brought to you in partnership with Qlik.

Topics:
python ,six ,functools ,stackstorm

Published at DZone with permission of Nir Alfasi. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}