Function and method annotation (hinting)

If you've worked with Python functions and methods before, you may have noticed and wondered about some unexpected syntax in some of the methods in the template files earlier, specifically the items in bold here:

def _get_property_name(self) -> str:

def _set_property_name(self, value:str) -> None:

def _del_property_name(self) -> None:

def instance_method(self, arg:str, *args, **kwargs):

These are examples of type hints that are supported in Python 3. One of the standards that hms_sys code will also adhere to is that all methods and functions should be type hinted. The resulting annotations may eventually be used to enforce type checking of arguments using a decorator, and even later on may be useful in streamlining unit testing. On a shorter-term basis, there is some expectation that an automatic documentation generation system will pay attention to those, so they're part of the internal standards now.

Type hinting is probably new enough that it's not in common use just yet, so a walk-through of what it does and how it works is probably worth examination. Consider the following unannotated function and its results when executed:

def my_function(name, price, description=None):
    """
A fairly standard Python function that accepts name, description and 
price values, formats them, and returns that value.
"""
    result = """
name .......... %s
description ... %s
price ......... %0.2f
""" % (name, description, price)
    return result

if __name__ == '__main__':
    print(
        my_function(
            'Product #1', 12.95, 'Description of the product'
        )
    )
    print(
        my_function(
            'Product #2', 10
        )
    )

The results from executing that code look good:

This is pretty straightforward, as Python functions go. The my_function function expects a name and price, and also allows for a description argument, but that is optional and defaults to None. The function itself just collects all those into a formatted string-value and returns it. The price argument should be a number value of some sort, and the others should be strings, if they exist. In this case, the expected types of those argument values are probably obvious based on the argument names.

The price argument, though, could be any of several different numerical types, and still function—int and float values obviously work, since the code runs without error. So too would a decimal.Decimal value, or even a complex type, as nonsensical as that would be. The type hinting annotation syntax exists, then, to provide a way to indicate without requiring what type or types of values are expected or returned.

Here's the same function, hinted:

def my_function(name:str, price:(float,int), description:(str,None)=None) -> str:
    """
A fairly standard Python function that accepts name, description and 
price values, formats them, and returns that value.
"""
    result = """
name .......... %s
description ... %s
price ......... %0.2f
""" % (name, description, price)
    return result

if __name__ == '__main__':
    print(
        my_function(
            'Product #1', 12.95, 'Description of the product'
        )
    )
    print(
        my_function(
            'Product #2', 10
        )
    )

    # - Print the __annotations__ of my_function
    print(my_function.__annotations__)

The only differences here are the type hinting annotations after each argument and the return type hint at the end of the function's first line, which indicate the expected types of each argument, and of the results of calling the function:

my_function(name:str, price:(float,int), description:(str,None)=None) -> str:

The output from the function call is identical, but the __annotations__ attribute of the function is shown at the end of the output:

All the type-hinting annotations really do is to populate the __annotations__ property of my_function, as shown at the end of the preceding execution. Essentially, they are providing metadata about and attached to the function itself that can be used later.

Taken together then, all of these standards are intended to do the following:

  • Help keep code as readable as possible (baseline PEP-8 conventions)

  • Keep the structure and organization of code within files predictable (module and class element organization standards)

  • Make it easy to create new elements (modules, classes, and so on) that conform to those standards (the various templates)

  • Provide some degree of future-proofing against efforts to allow automated documentation generation, type checking of methods and functions, and possibly some unit testing efficiencies to be explored later (type-hinting annotations)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.154.18