top of page
  • Writer: VC Healy
    VC Healy
  • May 24, 2020
  • 1 min read

Some more control tools.


if Statement

In the statement there does not need to be any elif or Else statements they are both optional.

There can however be multiple elif statements if required. Just make sure that the code is still readable.

If an Else statement is used then this must be the last statement of the if statement.


>>> x = int(input("Please enter an integer: "))
Please enter an integer: 42
>>> if x < 0:
...     x = 0
...     print('Negative changed to zero')
... elif x == 0:
...     print('Zero')
... elif x == 1:
...     print('Single')
... else:
...     print('More')
...
More

u

 
 
  • Writer: VC Healy
    VC Healy
  • May 24, 2020
  • 2 min read

The for statement iterates over items of any sequence (list, string) as they appear in the sequence

>>> # Measure some strings:
... words = ['cat', 'window', 'defenestrate']
>>> for w in words:
...     print(w, len(w))
...
cat 3
window 6
defenestrate 12

Th e simplest way to modify a collection, like words above would be to create a new collection from the previous collection. A example below would be iterating over a list of active/inactive users.

The first option deleting a user that as a key value of status set to inactive.

# Strategy:  Iterate over a copy
for user, status in users.copy().items():
    if status == 'inactive':
        del users[user]

The next code snippet would be preferred over the above code.

# Strategy:  Create a new collection
active_users = {}
for user, status in users.items():
    if status == 'active':
        active_users[user] = status

While Loops


Similar to the for loop only as far as a part of the code is being looped over. This time the loop does not continue to repeat based on the number of elements in an sequence but it is based on a statement remaining true. This can be something as simple as a comparison of a value that changes during each loop with a static value.


The Fibonacci series is an excellent basis to provide an example of this.

>>> def fib(n):    # write Fibonacci series up to n
...     """Print a Fibonacci series up to n."""
...     a, b = 0, 1
...     while a < n:
...         print(a, end=' ')
...         a, b = b, a+b
...     print()
...
>>> # Now call the function we just defined:
... fib(2_000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

As can be seen above code. The function fib() is being called and supplies the agrument 'n' with a parameter of 2000.

In the while loop the value of 'a' is being used to determine when the loop should terminate and once 'a' is equal or greater than this value of 'n', then the loo[p terminates and the print function is actioned.


 
 
  • Writer: VC Healy
    VC Healy
  • May 24, 2020
  • 4 min read

Part of the collections module that specialises in datatypes providing alternatives to general purpose containers (list,dict, set and tuple)


namedtuple is a factory function for the creation of tuple subclasses with named fields.


Assigning a meaning to each position in a tuple allows for more readable, self-documenting code. These can be used in place of a tuple, adding the ability to access fields by name instead of positional index.

collections.namedtuple(mytuple,field_names,*,rename=False,defaults=None,module=None))

Returns a new tuple subclass named mytuple.

The new subclass is used to create tuple-like objects that have fields accessible by attribute lookup as well as being indexable and iterable.

Instances of the subclass also have a helpful docstring (with mytuple and field_names) and a helpful __repr__() method which lists the tuple contents in a name=value format.


The field_names are a sequence of strings such as ['x', 'y'].

Alternatively, field_names can be a single string with each fieldname separated by whitespace and/or commas, for example 'x y' or 'x, y'.

Valid identifiers used for a fieldname consist of letters, digits, and underscores but do not start with a digit or underscore and cannot be a keyword.


If rename is true, invalid fieldnames are automatically replaced with positional names.

For example, ['abc', 'def', 'ghi', 'abc'] is converted to ['abc', '_1', 'ghi', '_3'], eliminating the keyword def and the duplicate fieldname abc.


defaults can be None or an iterable of default values.

fields with a default value must come after any fields without a default, the defaults are applied to the rightmost parameters.

For example, if the fieldnames are ['x', 'y', 'z'] and the defaults are (1, 2), then x will be a required argument, y will default to 1, and z will default to 2.


If module is defined, the __module__ attribute of the named tuple is set to that value.


Named tuple instances do not have per-instance dictionaries, so they are lightweight and require no more memory than regular tuples.


Changed in version 3.1: Added support for rename.

Changed in version 3.6: The verbose and rename parameters became keyword-only arguments.

Changed in version 3.6: Added the module parameter.

Changed in version 3.7: Removed the verbose parameter and the _source attribute.

Changed in version 3.7: Added the defaults parameter and the _field_defaults attribute.


>>> Point = namedtuple('Point', ['x', 'y'])
 >>> p = Point(11, y=22) # instantiate with positional or keyword arguments 
>>> p[0] + p[1] # indexable like the plain tuple (11, 22) 33 
>>> x, y = p # unpack like a regular tuple 
>>> x, y (11, 22) 
>>> p.x + p.y # fields also accessible by name 33 
>>> p # readable __repr__ with a name=value style Point(x=11, y=22) 

Named tuples are especially useful for assigning field names to result tuples returned by the csv or sqlite3 modules:

EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')

import csv 
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))): print(emp.name, emp.title) 

import sqlite3 
conn = sqlite3.connect('/companydata') 
cursor = conn.cursor() 
cursor.execute('SELECT name, age, title, department, paygrade FROM employees') 
for emp in map(EmployeeRecord._make, cursor.fetchall()): 
	print(emp.name, emp.title) 

In addition to the methods inherited from tuples, named tuples support three additional methods and two attributes. To prevent conflicts with field names, the method and attribute names start with an underscore.


classmethodsomenamedtuple._make(iterable)

Class method that makes a new instance from an existing sequence or iterable.

>>> t = [11, 22] 
>>> Point._make(t) 
Point(x=11, y=22) 

somenamedtuple._asdict()

Return a new dict which maps field names to their corresponding values:

>>> p = Point(x=11, y=22) 
>>> p._asdict() 
{'x': 11, 'y': 22} 

Changed in version 3.1: Returns an OrderedDict instead of a regular dict.

Changed in version 3.8: Returns a regular dict instead of an OrderedDict. As of Python 3.7, regular dicts are guaranteed to be ordered. If the extra features of OrderedDict are required, the suggested remediation is to cast the result to the desired type: OrderedDict(nt._asdict()).


somenamedtuple._replace(**kwargs)

Return a new instance of the named tuple replacing specified fields with new values:

>>> p = Point(x=11, y=22)
>>> p._replace(x=33) Point(x=33, y=22) 
>>> for partnum, record in inventory.items(): 
...  inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now()) 
somenamedtuple._fields

Tuple of strings listing the field names. Useful for introspection and for creating new named tuple types from existing named tuples.

>>> p._fields # view the field names ('x', 'y') 
>>> Color = namedtuple('Color', 'red green blue') 
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) 
>>> Pixel(11, 22, 128, 255, 0) Pixel(x=11, y=22, red=128, green=255, blue=0) 

somenamedtuple._field_defaults

Dictionary mapping field names to default values.

>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0]) 
>>> Account._field_defaults {'balance': 0} 
>>> Account('premium') Account(type='premium', balance=0) 

To retrieve a field whose name is stored in a string, use the getattr() function:

>>> getattr(p, 'x') 
11 

To convert a dictionary to a named tuple, use the double-star-operator

>>> d = {'x': 11, 'y': 22} 
>>> Point(**d) 
Point(x=11, y=22) 

A named tuple is a regular Python class, add or change functionality with a subclass.

Here is how to add a calculated field and a fixed-width print format:

>>> class Point(namedtuple('Point', ['x', 'y'])): ...  __slots__ = () ...  
	@property
 ...  	def hypot(self): 
...  	return (self.x ** 2 + self.y ** 2) ** 0.5 
...  	def __str__(self): 
...  	return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot) 

>>> for p in Point(3, 4), Point(14, 5/7): 
...  print(p) 
Point: x= 3.000  y= 4.000  hypot= 5.000 Point: x=14.000  y= 0.714  hypot=14.018 

The subclass shown above sets __slots__ to an empty tuple. This helps keep memory requirements low by preventing the creation of instance dictionaries.

Subclassing is not useful for adding new, stored fields.

Instead, simply create a new named tuple type from the _fields attribute:

>>> Point3D = namedtuple('Point3D', Point._fields + ('z',)) 

Docstrings can be customised by making direct assignments to the __doc__ fields:


>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN' 
>>> Book.title.__doc__ = 'Title of first printing' 
>>> Book.authors.__doc__ = 'List of authors sorted by last name' 

Changed in version 3.5: Property docstrings became writeable.

 
 

© 2020 by Vincent Healy. Proudly created with Wix.com

bottom of page