matlab 学习Python解析器

2nc8po8w  于 2023-10-23  发布在  Matlab
关注(0)|答案(1)|浏览(169)

我对Python相当陌生,并试图用构造函数设置一个类,使其具有少量必需属性和大量可选属性,并具有默认值和可接受输入的定义。
我试过使用argparse模块,但我不明白如何解析参数,然后将结果传递到类的属性中。这也不允许我为预期的输入定义逻辑标准。
我希望做一些类似于这个MATLAB脚本。

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
6psbrbz9

6psbrbz91#

令人高兴的是,Python不需要进行这种特殊的字符串和数组解析。
好的Python代码是面向对象的。与其将值作为原始字符串和数组传递,不如将它们封装到 * 有意义类型的对象 * 中。这些对象应该负责在构造时验证自己,并在其整个生命周期中维护其不变量。
甚至更好的Python代码可以利用静态类型提示,在代码运行之前卸载大部分验证。
一个惯用的Python翻译可能看起来像这样(带有一些自由猜测的解释):

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import NamedTuple, Literal

class Position(NamedTuple):
    x: float
    y: float
    z: float

    @classmethod
    def origin(cls) -> Position:
        return cls(0, 0, 0)

class Orientation(NamedTuple):
    yaw: float
    pitch: float
    roll: float

    @classmethod
    def pos_x(cls) -> Orientation:
        return cls(0, 0, 0)

    @classmethod
    def pos_y(cls) -> Orientation:
        return cls(1, 0, 0)

    @classmethod
    def pos_z(cls) -> Orientation:
        return cls(0, 1, 0)

class Geometry(NamedTuple):
    extent: Position
    o_offset: Position

    @classmethod
    def unit_cube(cls) -> Geometry:
        return cls((1, 1, 1), (0, 0, 0))

@dataclass
class Trajectory:
    waypoints: list[Position] = field(default_factory=list)
    time_of_arrival: float = 0
    velocity: Position = Position.origin()
    orientation: Orientation = Orientation.pos_x()

class Platform(ABC):

    _geometry: Geometry
    _position: Position
    _orientation: Orientation
    _trajectory: Trajectory
    _datalinks: list[Literal['One','Two','Three']]
    _sensors: list[Sensors]

    def __init__(
        self,
        geometry: Geometry = Geometry.unit_cube(),
        pos: Position = Position.origin(),
        orientation: Orientation = Orientation.pos_x(),
        trajectory: Trajectory | None = None,
        datalinks: list[Literal['One','Two','Three'] | None = None,
        sensors: list[Sensors] | None = None,
    ) -> None:
        if trajectory is None:
            trajectory = Trajectory()

        if datalinks is None:
            datalinks = []

        if sensors is None:
            sensors =  []

        self._geometry = geometry
        self._position = pos
        self._orientation = orientation
        self._trajectory = trajectory
        self._datalinks = datalinks
        self._sensors = sensors

    @abstractmethod
    def do_something_class_specific(self) -> None:
        ...

class NeutralPlatform(Platform):
    def do_something_class_specific(self) -> None:
        self.watch_and_wait()

class FooPlatform(Platform):
    def do_something_class_specific(self) -> None:
        self.attack_mode()

就是这样!只要类型检查通过,您构造的任何Platform都将被完全验证。不需要为类型系统已经可以验证的东西实现手动验证!
需要更多的不变量?以适当的类型执行它们。在一个好的面向对象设计中,Platform不需要(也不应该)知道什么是有效的Orientation,只需要知道它有一个并且它已经有效。

相关问题