HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Command-line-based capacitance decoding

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
linebaseddecodingcommandcapacitance

Problem

I am an amateur programmer and have just written a simple Capacitor Identifier mostly to practice. I have not had many people review my coding and thought this would be a good time to start. It is completed and works. Is there a better way I should have went about it? What should I look at in what and how I am writing that might improve my approach?

#!/usr/bin/env python3

import sys

# Get the arguments list 
cmdargs = sys.argv

cmdargs = cmdargs[1:]

tolerances = {'B':'.10%','C':'.25%','D':'.5%','E':'.5%','F':'1%','G':'2%','H':'3%','J':'5%','K':'10%','M':'20%','N':'.05%','P':'+100% to 0%','Z':'+80% to -20%'}

# Get the total number of args passed
total = len(cmdargs)

# Templete String for output
capTemp = '{} = {}'

# output container
result = []

# cycle through passed arguments and decode each capacitor
for arg in cmdargs:
    case = len(arg)

    if(case == 2):
        temp = arg + ' pf, ' + str(float(arg) / 1000000) + 'uf'
        result.append(capTemp.format(arg, temp))
    elif(case == 3):
        cap = int(arg[:2]) * 10**int(arg[2:])
        temp = str(cap) + ' pf, ' + str(float(cap) / 1000000) + 'uf'
        result.append(capTemp.format(arg, temp))

    elif(case == 4):
        cap = int(arg[:2]) * 10**int(arg[2:3])
        temp = str(cap) + ' pf, ' + str(float(cap) / 1000000) + 'uf, ' + tolerances[arg[3:].upper()] + ' tolerance'
        result.append(capTemp.format(arg, temp))

# print the decoded capacitor values
for i in result:
    print(i)

Solution

Variable usage

Assign cmdargs once, and get it right the first time. Put a more insightful comment there. Rename it to cmd_args for readability.

# Skip argv[0], which is the name of this program
cmd_args = sys.argv[1:]


The total variable is never used.

The variable name case is not descriptive enough. Naming a variable temp is almost always a bad idea as well. I suggest names like arg_len and decoded_value, respectively.

tolerances is a constant, and should be named TOLERANCES by convention. Format it using one entry per line for readability.

Decoding technique

It is good practice to separate your calculations from your output routines. Start by defining a function decode_capacitance(code):

def decode_capacitance(code):
    '''
    Decodes the capacitance as a (value, tolerance) pair.
    The value is a float representing the nominal number of picofarads.
    The tolerance is a free-form string, and may be None.
    '''
    code_length = len(code)
    if code_length == 2:
        return float(code), None
    elif code_length == 3:
        return float(code[:2]) * 10 ** int(arg[2:]), None
    elif code_length == 4:
        return float(code[:2]) * 10 ** int(arg[2:3]), TOLERANCES[code[3:].upper()]


In Python, it is idiomatic to write if conditions without parentheses.

However, there is a lot of redundancy there, and not much insight either. An improvement would be:

def decode_capacitance(code):
    '''(Same docstring)'''
    base_pF, scale, tol = float(code[0:2]), int(code[2:3] or 0), code[3:4]
    multiplier = 10 ** scale
    return base_pF * multiplier, TOLERANCES.get(tol.upper())


You fail to interpret the third digit properly. If the third digit is 8 or 9, it is supposed to be interpreted as a multiplier of 0.01 or 0.1, respectively. To fix that, change the middle line to:

multiplier = 10 ** (scale if scale <= 5 else scale - 10)


As @vnp noted, you have no validation or error handling (and I haven't added any for you).

Formatting technique

Define another function to display the capacitance and tolerance in the desired format.

It would be nice, I think, to automatically select the most natural units.

The standard symbol for the farad is F — a capital letter.

Putting it all together

With the appropriate functions defined, the main loop is quite simple. Print results as you go; there's no need to store results.

import sys

TOLERANCES = {
    'B': '.10%',
    'C': '.25%',
    'D': '.5%',
    'E': '.5%',
    'F': '1%',
    'G': '2%',
    'H': '3%',
    'J': '5%',
    'K': '10%',
    'M': '20%',
    'N': '.05%',
    'P': '+100% to 0%',
    'Z': '+80% to -20%',
}

def decode_capacitance(code):
    '''
    Decodes the capacitance as a (value, tolerance) pair.
    The value is a float representing the nominal number of picofarads.
    The tolerance is a free-form string, and may be None.
    '''
    base_pF, scale, tol = float(code[0:2]), int(code[2:3] or 0), code[3:4]
    multiplier = 10 ** int(scale if scale  1000000:
        mantissa, unit = pF / 1000000, 'uF'
    else:
        mantissa, unit = pF, 'pF'

    output = '{} {}'.format(mantissa, unit)
    if tolerance is not None:
        output += ', ' + tolerance + ' tolerance'
    return output

# Skip argv[0], which is the name of this program
cmd_args = sys.argv[1:]

# Cycle through passed arguments and decode each capacitor
for arg in cmd_args:
    print('{} = {}'.format(arg, format_capacitance(*decode_capacitance(arg))))

Code Snippets

# Skip argv[0], which is the name of this program
cmd_args = sys.argv[1:]
def decode_capacitance(code):
    '''
    Decodes the capacitance as a (value, tolerance) pair.
    The value is a float representing the nominal number of picofarads.
    The tolerance is a free-form string, and may be None.
    '''
    code_length = len(code)
    if code_length == 2:
        return float(code), None
    elif code_length == 3:
        return float(code[:2]) * 10 ** int(arg[2:]), None
    elif code_length == 4:
        return float(code[:2]) * 10 ** int(arg[2:3]), TOLERANCES[code[3:].upper()]
def decode_capacitance(code):
    '''(Same docstring)'''
    base_pF, scale, tol = float(code[0:2]), int(code[2:3] or 0), code[3:4]
    multiplier = 10 ** scale
    return base_pF * multiplier, TOLERANCES.get(tol.upper())
multiplier = 10 ** (scale if scale <= 5 else scale - 10)
import sys

TOLERANCES = {
    'B': '.10%',
    'C': '.25%',
    'D': '.5%',
    'E': '.5%',
    'F': '1%',
    'G': '2%',
    'H': '3%',
    'J': '5%',
    'K': '10%',
    'M': '20%',
    'N': '.05%',
    'P': '+100% to 0%',
    'Z': '+80% to -20%',
}

def decode_capacitance(code):
    '''
    Decodes the capacitance as a (value, tolerance) pair.
    The value is a float representing the nominal number of picofarads.
    The tolerance is a free-form string, and may be None.
    '''
    base_pF, scale, tol = float(code[0:2]), int(code[2:3] or 0), code[3:4]
    multiplier = 10 ** int(scale if scale <= 5 else scale - 10)
    return base_pF * multiplier, TOLERANCES.get(tol.upper())

def format_capacitance(pF, tolerance):
    if pF > 1000000:
        mantissa, unit = pF / 1000000, 'uF'
    else:
        mantissa, unit = pF, 'pF'

    output = '{} {}'.format(mantissa, unit)
    if tolerance is not None:
        output += ', ' + tolerance + ' tolerance'
    return output

# Skip argv[0], which is the name of this program
cmd_args = sys.argv[1:]

# Cycle through passed arguments and decode each capacitor
for arg in cmd_args:
    print('{} = {}'.format(arg, format_capacitance(*decode_capacitance(arg))))

Context

StackExchange Code Review Q#66707, answer score: 6

Revisions (0)

No revisions yet.