Search code examples
pythondictionarykey

Function returning different dictionary after second call


Background:

I am attempting to determine the difference between technical drawing dimensions and actual measured dimensions. These dimensions are stored within two dictionaries: actual_data and drawing_data. Due to the fact that the actual measurements can be taken in many ways, they are stored as lists to accommodate the following cases:

  1. 1x1 list. This represents a singular dimension with no variation or tolerance specified.
  2. 1x2 list. This represents a dimension that has an upper and lower limit or tolerance.
  3. Nx1 list. This represents a list of singular dimensions taken from one surface of a large component.
  4. Nx2 list. This represents a list of dimensions that each have an upper and lower limit or tolerance.

To avoid too many conditionals, I break up all matrices into lists and assign each new list (either 1x1 or 1x2) a new key.

My Script:

import numpy as np

drawing_data = {
        'A': [394.60],
        'B': [629.85, 629.92],
        'C': [759.95, 760.00],
        'D': [839.95, 840.00],
        'E': [1779.50, 1780.50]
        }

actual_data = {
        'A': [390.00],
        'B': [629.88, 629.90],
        'C': [760.17, 760.25],
        'D': [[840.12, 840.18], [840.04, 840.06], [840.07, 840.07]],
        'E': [1780.00, 1780.00]
        }

As you can see, Dimension D has an expected measurement ranging between 839.95mm and 840.00mm. However, due to the size of the component, it is measured in three places (hence, the list of lists).

def dimensional_deviation(drawing, actual):
    
    # If the actual data is of the type Nx1 or Nx2, it is split and converted into new dimensions of the
    # type 1x1 or 1x2 - new dictionary keys are created to accommodate the new dimensions, and the 
    # original dictionary entries are deleted.
    #---------------------------------------------------------------------------------------------------
    new_dict_drawing, new_dict_actual, keys_to_remove = {}, {}, []

    for dimension in drawing:
        
        if type(actual.get(dimension)[0]) is list:

            keys_to_remove.append(dimension) # Create a list of unnecessery dimensions
            
            for i, sublist in enumerate(actual.get(dimension)):
                
                new_dict_drawing[f'{dimension}{i + 1}'] = drawing.get(dimension) # Create new dimension
                new_dict_actual[f'{dimension}{i + 1}'] = sublist # Create new dimension
                                
    for dimension in keys_to_remove: # Remove all unnecessary dimensions from the original dicts
        
        drawing.pop(dimension, None)
        actual.pop(dimension, None)

    # Merge dictionaries:    
    drawing = {**drawing, **new_dict_drawing}
    actual = {**actual, **new_dict_actual}
    #---------------------------------------------------------------------------------------------------
    
    # Determine the deviation between the drawing and actual dimensions. The average of the upper and 
    # lower bounds is used to simplify each case.
    #---------------------------------------------------------------------------------------------------
    inspection_results = {}
    
    for dimension in drawing:
        
        drawing_value, actual_value = drawing.get(dimension), actual.get(dimension)
        
        drawing_ave, actual_ave = np.mean(drawing_value), np.mean(actual_value)

        deviation = drawing_ave - actual_ave
            
    # Create new dictionary of the repair requirements:
    #---------------------------------------------------------------------------------------------------
        inspection_results[f'{dimension}'] = round(deviation, 3)
    
    return inspection_results

My Problem:

When I call the above for the first time, I get the desired output. Dimension D is broken up as expected and the deviation is calculated. However, when I call the same function a second time, everything regarding Dimension D is completely neglected as though the key did not exist:

print('First function call:')
print(dimensional_deviation(drawing=drawing_data, actual=actual_data))
print('---------------------------------------------------------------------------------------')

print('Second function call:')
print(dimensional_deviation(drawing=drawing_data, actual=actual_data))
print('---------------------------------------------------------------------------------------')

Resulting in:

First function call:
{'A': 4.6, 'B': -0.005, 'C': -0.235, 'E': 0.0, 'D1': -0.175, 'D2': -0.075, 'D3': -0.095}
--------------------------------------------------------------------------------------- 
Second function call:
{'A': 4.6, 'B': -0.005, 'C': -0.235, 'E': 0.0}
--------------------------------------------------------------------------------------- 

I believe I am overwriting my drawing_data and actual_data somewhere, but I cannot find the issue. Additionally, this is one of my first times using dictionaries and I suspect that my key creation and deletion may not be best practice.

In my comments you will see Create a list of unnecessary dimensions - an example of this would be Dimension D, as it is newly accounted for in D1, D2 and D3.

Could somebody please explain to me why I get this result on each subsequent function call after the first?


Solution

  • The issue was that the original dictionaries were being modified (see above comments):

    import numpy as np
    
    drawing_data = {
            'A': [394.60],
            'B': [629.85, 629.92],
            'C': [759.95, 760.00],
            'D': [839.95, 840.00],
            'E': [1779.50, 1780.50]
            }
    
    actual_data = {
            'A': [390.00],
            'B': [629.88, 629.90],
            'C': [760.17, 760.25],
            'D': [[840.12, 840.18], [840.04, 840.06], [840.07, 840.07]],
            'E': [1780.00, 1780.00]
            }
    #-------------------------------------------------------------------------------------------------------
    
    # The 'dimensional deviation' function takes the drawing data and actual data as arguments, returning a
    # dictionary of dimensions and whether they require rectification or not (based one the drawing data).
    #-------------------------------------------------------------------------------------------------------
    def dimensional_deviation(drawing, actual):
    
        temp_dict_drawing = {}
        for key in drawing:
            temp_dict_drawing[key] = drawing.get(key)
    
        temp_dict_actual = {}
        for key in drawing:
            temp_dict_actual[key] = actual.get(key)
        
        # If the actual data is of the type Nx1 or Nx2, it is split and converted into new dimensions of the
        # type 1x1 or 1x2 - new dictionary keys are created to accommodate the new dimensions, and the 
        # original dictionary entries are deleted.
        #---------------------------------------------------------------------------------------------------
        new_dict_drawing, new_dict_actual, keys_to_remove = {}, {}, []
    
        for dimension in temp_dict_drawing:
            
            if type(temp_dict_actual.get(dimension)[0]) is list:
    
                keys_to_remove.append(dimension) # Create a list of unnecessery dimensions
                
                for i, sublist in enumerate(temp_dict_actual.get(dimension)):
                    
                    new_dict_drawing[f'{dimension}{i + 1}'] = temp_dict_drawing.get(dimension) # Create new dimension
                    new_dict_actual[f'{dimension}{i + 1}'] = sublist # Create new dimension
                                    
        for dimension in keys_to_remove: # Remove all unnecessary dimensions from the original dicts
            
            temp_dict_drawing.pop(dimension)
            temp_dict_actual.pop(dimension)
    
        # Merge dictionaries:    
        drawing_new = {**temp_dict_drawing, **new_dict_drawing}
        actual_new = {**temp_dict_actual, **new_dict_actual}
        #---------------------------------------------------------------------------------------------------
        
        # Determine the deviation between the drawing and actual dimensions. The average of the upper and 
        # lower bounds is used to simplify each case.
        #---------------------------------------------------------------------------------------------------
        inspection_results = {}
        
        for dimension in drawing_new:
            
            drawing_value, actual_value = drawing_new.get(dimension), actual_new.get(dimension) # Fetch the data
    
            drawing_ave, actual_ave = np.mean(drawing_value), np.mean(actual_value) # Calculate averages
    
            deviation = drawing_ave - actual_ave
                
        # Create new dictionary of the repair requirements:
        #---------------------------------------------------------------------------------------------------
            inspection_results[f'{dimension}'] = round(deviation, 3)
        
        return inspection_results
    

    Alternatively, copy.deepcopy() also yielded the correct results:

    Deep copy of a dict in python