I'm fairly new to Python and trying to set up a class with a constructor to have a small number of required properties and a larger number of optional ones with defaults and definitions of acceptable inputs.
I've tried using the argparse module, but I am not understanding how to parse the arguments then pass the results into the properties of the class. This also has not allowed me to define logical criteria for expected inputs.
I'm looking to do something similar to this MATLAB script.
methods
function obj = Platform(ClassID,varargin)
inPar = inputParser;
expectedClass = {'Ownship', 'Wingman', 'Flight Group', 'Unknown', 'Suspect', 'Neutral', 'Friend', 'Foe'};
validClassID = @(x) any(validatestring(x,expectedClass));
addRequired(inPar,'ClassID',validClassID)
defaultDim = struct('length', 0, 'width', 0, 'height', 0, 'oOffset', [0 0 0]);
validDim = @(x) ~isempty(intersect(fieldnames(x),fieldnames(defaultDim)));
addOptional(inPar,'Dimensions',defaultDim,validDim)
defaultPos = [0 0 0];
validPos = @(x) isclass(x,'double') && mean(size(x) == [1 3]);
addOptional(inPar,'Position',defaultPos,validPos)
defaultOr = [0 0 0];
validOr = @(x) isclass(x,'double') && mean(size(x) == [1 3]);
addOptional(inPar,'Orientation',defaultOr,validOr)
defaultTraj = struct('Waypoints',[0 0 0],...
'TimeofArrival',0,...
'Velocity',[0 0 0],...
'Orientation',[0 0 0]);
validTraj = @(x) ~isempty(fieldnames(x),fieldnames(defaultTraj));
addOptional(inPar,'Trajectory',defaultTraj,validTraj)
expectedDL = {'One','Two','Three};
defaultDL = {};
validDL = @(x) any(validatestring(x,expectedDL));
addOptional(inPar,'DataLinks',defaultDL,validDL)
defaultSens = {};
validSens = @(x) isa(x,'Sensor');
addOptional(inPar,'Sensors',defaultSens,validSens)
parse(inPar,ClassID,varargin{:})
obj.PlatformID = randi([1 10000]);
obj.ClassID = inPar.Results.ClassID;
obj.Dimensions = inPar.Results.Dimensions;
obj.Position = inPar.Results.Position;
obj.Orientation = inPar.Results.Orientation;
obj.Trajectory = inPar.Results.Trajectory;
obj.Sensors = inPar.Results.Sensors;
obj.DataLinks = inPar.Results.DataLinks;
end
Happily, Python has no need of doing this sort of ad-hoc string and array parsing.
Good Python code is object oriented. Instead of passing values around as raw strings and arrays, you should encapsulate them into objects of meaningful types. Those objects should be left responsible for validating themselves when constructed and for maintaining their invariants throughout their lifetime.
Even better Python code can take advantage of static type hinting to offload much of that validation to before your code is even run.
An idiomatic Python translation might look something like this (with some liberal guesswork interpretation):
That's it! Any
Platforms you construct will be fully validated, provided type checking passes. No need implement manual validation for things that the type system can already verify!Need more invariants? Enforce them in the appropriate type. In a good object oriented design,
Platformdoes not (and should not) need to know anything about what makes a validOrientation, only that it has one and that it's already valid.