patternpythonMinor
Logical functions and truth tables
Viewed 0 times
tablestruthandfunctionslogical
Problem
This program goes through 7 common logical functions (
I don't care much about the speed, but how can I improve the style and follow the PEP guidelines in this program?
AND, OR, NOT, NOR, XOR, XNOR, and NAND) and generates and prints truth tables for them all.#!/usr/bin/env python2
# coding:utf-8
import operator
import itertools
table = list(itertools.product([False, True], repeat=2))
ops={'AND': ('∧', (lambda a,b:bool(operator.and_(a,b)))),
'OR': ('∨', (lambda a,b:bool(operator.or_(a,b)))),
'NOT': ('¬', (lambda a,b:bool(operator.not_(a)))),
'NOR': ('↓', (lambda a,b:bool(operator.not_(operator.or_(a,b))))),
'XOR': ('↮', (lambda a,b:bool(operator.xor(a,b)))),
'XNOR': ('↔', (lambda a,b:bool(operator.not_(operator.xor(a,b))))),
'NAND': ('↑', (lambda a,b:bool(operator.not_(operator.and_(a,b)))))}
pad = lambda x:(str(x) if len(str(x)) == 5 else str(x) + ' ')
for i in ops.keys():
print i +',',ops[i][0],'\n' + '-'*25
for j in table:
print '|', pad(j[0]), '|', pad(j[1]), '|', pad(ops[i][1](j[0],j[1])), '|'
print '-'*25, '\n'I don't care much about the speed, but how can I improve the style and follow the PEP guidelines in this program?
Solution
You should make a class. This lets you consolidate the implementation to be consistent, and simplifies a number of the details. You can also implement
Inheriting from
This way you've separated your concerns. The class encapsulates "what is a logical operator and how do I make it print pretty", and then we use it as necessary to get value and formatting for it.
Then we can still create all of our logical operators, but we do it with classes and a tuple instead of a dict and tuples.
A better way to pad strings is to use
Then we can put it all together.
Also, you could use more whitespace throughout. Makes it easier to read.
__str__ and __repr__ to make it easier to print them. Use string formatting for thisclass LogicalOperator(object):
def __init__(self, name, symbol, functor):
self.name = name
self.symbol = symbol
self.functor = functor
def __call__(self, a, b):
return bool(functor(a, b))
def __str__(self):
return self.name
def __repr__(self):
return "{}, {}".format(self.name, self.symbol)Inheriting from
namedtuple makes this easier (thanks to Caridorc for pointing out in the comments).from collections import namedtuple
class LogicalOperator(namedtuple('LogicalOperator', 'name symbol functor')):
# no __init__ now
# rest is unchangedThis way you've separated your concerns. The class encapsulates "what is a logical operator and how do I make it print pretty", and then we use it as necessary to get value and formatting for it.
Then we can still create all of our logical operators, but we do it with classes and a tuple instead of a dict and tuples.
ops = (
LogicalOperator('AND', '∧', operator.and_),
LogicalOperator('OR', '∨', operator.or_),
LogicalOperator('NOT', '¬', lambda a, _: not a),
LogicalOperator('NOR', '↓', lambda a, b: not (a or b)),
LogicalOperator('XOR', '↮', operator.xor),
LogicalOperator('XNOR', '↔', lambda a, b: not (a ^ b)),
LogicalOperator('NAND', '↑', lambda a, b: not (a and b))
)A better way to pad strings is to use
string.rjust. An even better way is to use the Format Specification Mini-Language.Then we can put it all together.
if __name__ == '__main__':
column_width = 25
table = list(itertools.product([False, True], repeat=2))
for op in ops:
print(op)
print("-"*column_width)
for left, right in table:
print("|{:^5}|{:^5}|{:^5}|".format(left, right, op(left, right)))
print("-"*column_width)Also, you could use more whitespace throughout. Makes it easier to read.
Code Snippets
class LogicalOperator(object):
def __init__(self, name, symbol, functor):
self.name = name
self.symbol = symbol
self.functor = functor
def __call__(self, a, b):
return bool(functor(a, b))
def __str__(self):
return self.name
def __repr__(self):
return "{}, {}".format(self.name, self.symbol)from collections import namedtuple
class LogicalOperator(namedtuple('LogicalOperator', 'name symbol functor')):
# no __init__ now
# rest is unchangedops = (
LogicalOperator('AND', '∧', operator.and_),
LogicalOperator('OR', '∨', operator.or_),
LogicalOperator('NOT', '¬', lambda a, _: not a),
LogicalOperator('NOR', '↓', lambda a, b: not (a or b)),
LogicalOperator('XOR', '↮', operator.xor),
LogicalOperator('XNOR', '↔', lambda a, b: not (a ^ b)),
LogicalOperator('NAND', '↑', lambda a, b: not (a and b))
)if __name__ == '__main__':
column_width = 25
table = list(itertools.product([False, True], repeat=2))
for op in ops:
print(op)
print("-"*column_width)
for left, right in table:
print("|{:^5}|{:^5}|{:^5}|".format(left, right, op(left, right)))
print("-"*column_width)Context
StackExchange Code Review Q#134086, answer score: 5
Revisions (0)
No revisions yet.