ENVI IDL:如何基于面向对象思想进行编程?

news2024/12/18 18:54:49

最近打算使用markdown语法进行博客的编写,所以风格和格式方面会有区别,见谅。

01 为什么会有这方面的想法?

我惯用python,因此对于IDL进行编程也会有先入为主的想法,它也体现在我的IDL编程中。

02 如何正常编写函数?

举例如下:

当我传入年月日(X年Y月Z日),返回年积日(第X年第Y天);当我传入年积日,返回年月日;

如果使用函数编写,一般需要两个函数完成上述功能。分别如下:

function ymd2doy, year, month, day
    now_date = imsl_datetodays(day, month, year)
    old_date = imsl_datetodays(31, 12, year - 1)
    doy = now_date - old_date
    
    return, [year, doy]
end

function doy2ymd, year, doy
    old_date = imsl_datetodays(31, 12, year - 1)
    imsl_daystodate, old_date + doy, day, month, year
    
    return, [year, month, day]
end

至于其中两个函数imsl_datetodays, imsl_daystodate,前者是将年月日数据转化为儒略日(距离1900年1月1日的总天数),后者将儒略日转化为年月日。但如何将年月日和年积日进行互相转化这里稍微取巧,详见程序。

03 如何使用对象思想编写时间类?

3.1 编写具备简单方法的时间类

首先可以发现,这两个函数都是和时间相关的,所以自然就会萌生这样的想法?以后关于时间处理的函数我都放到一个类中,需要就去调用这个类就好了。

那么使用面向对象程序应该如何进行类的创建以及类的实例化呢?

首先,理解如何定义一个空类?(没有任何方法和属性)

pro time__define
    struct = {time, inherits idl_object}
end

(文件名称一般命名为time_define.pro)

那么,首先定义一个pro过程:time__define,一般而言,__define是类定义的范式,注意有两个下划线__。前面的time为类的名称,与pro过程中的struct = {time, inherits idl_object}time对应。
inherits idl_object为继承基类(我个人认为idl_object为非常基础的类别),一般会继承该类别,该类别包含最基本的一些方法方便你去拓展类。

那么,将上述程序进行编译(compile),你可以使用该类了:
在这里插入图片描述
什么叫做实例化,类就是一类抽象的东西,他们具有相同或者类似的特征,但是在具体表达的时候又有一些差异。例如,我可以一个时间类,但是可能每一个时间对象都有不一样的年月日的属性;那么这个时候我们如果有很多个时间类的具体对象,那么不同对象就有不同的年月日属性,这个叫做实例化。

但是实例化出来这个类,我们没有为这个类写一些方法,因此这个时间对象a其实没有什么用。

现在需要为time类写一些方法(方法在普通的pro过程中就是函数,在类中称为方法)。

function time::doy2ymd, year, doy
    old_date = imsl_datetodays(31, 12, year - 1)
    imsl_daystodate, old_date + doy, day, month, year
    
    return, [year, month, day]
end

function time::ymd2doy, year, month, day
    now_date = imsl_datetodays(day, month, year)
    old_date = imsl_datetodays(31, 12, year - 1)
    doy = now_date - old_date

    return, [year, doy]
end

pro time__define
    struct = {time, inherits idl_object}
end

如果是普通函数那么前面已经展示了,而对于time下的方法如何书写如上所示。
使用function class_name::function_name, arg1, arg2···样式进行书写。其中class_name表示类的名称或当前function归属于哪一个类;function_name为方法的名称;arg1,arg2为该方法的参数。::是将function_name作为class_name的方法的一种特殊表达字符,表示类拥有该方法。
那么接下来你可以使用该类。
在这里插入图片描述

3.2 编写具备方法和属性的时间类

前面已经说明了,如何进行具备方法的时间类编写,但是对象里面不仅可以有方法,还可以有关于对象的一些属性,例如时间类我们还可以编写具备年月日属性、具备年月日和年积日转化方法(两个)的时间类。

function time::doy2ymd, year, doy
    old_date = imsl_datetodays(31, 12, year - 1)
    imsl_daystodate, old_date + doy, day, month, year
    
    return, [year, month, day]
end

function time::ymd2doy, year, month, day
    now_date = imsl_datetodays(day, month, year)
    old_date = imsl_datetodays(31, 12, year - 1)
    doy = now_date - old_date

    return, [year, doy]
end
pro time__define
    struct = {time, inherits idl_object, year: 0l, month: 0l, day: 0l, doy: 0l}
end

这里我们在time_define中加上了三个属性: year: 0l, month: 0l, day: 0l, doy: 0l,均设置为默认值是长整型0。但是我们如何在类中去调用这些属性呢?
显然,在ymd2doy方法的内部中year、month、day的三个变量应该由用户传入,但是会不会存在歧义?这些变量似乎与类的
属性的名称完全一致,均为year, month, day。如何区分呢?

实际上,我们在类的内部使用类的属性时,通过self进行调用(对于类的方法也是如此)。例如我有一个方法打印时间对象当前的年月日,如何做到?

function time::print_time
    print, self.year, self.month, self.day, self.doy, format='年: %d,: %02d,: %02d, 年积日: %03d'
end

在这里插入图片描述

这样将引出一个问题?为什么我不可以直接使用a.year, a.month, a.day, a.doy进行这个时间对象属性的获取?

确实可以,但是如果基于现有代码那么将会发生报错:
在这里插入图片描述
这是因为,通过a.day进行属性的获取实际上是用到了基类idl_objectgetproperty方法,但是在idl_object基类中并没有关于新来的三个属性的相关代码,这里需要对该方法进行重写,如下:

(需要注意,getproperty方法在基类中是一个pro过程,而非function,所以进行重写时需要使用pro而非function

pro time::GetProperty, year=year, month=month, day=day, doy=doy
    year = self.year
    month = self.month
    day = self.day
    doy = self.doy
end

首先,需要明白get的含义:

当我们通过a.year获取a对象的year属性时,实际上是执行a.getproperty, year=year操作,在getproperty方法中,self.year将对象的属性返回给year,这样a.year就得到了这个对象的year属性。

读取对象属性的效果如下:
hi

但是这样写似乎会有一点小瑕疵,就是用户仅仅通过a.year获取对象的year属性,但是在getproperty方法中将每一个属性都返回了,虽然其他属性我们没有使用到。但是这会造成后续的一些麻烦,例如如果我后面get方法非常复杂的时候,那么所有的操作都执行一遍就会存在一些内存泄漏等问题或者说我在获取属性的时候又进行了一些比较复杂的计算那么就会浪费您昂贵的芯片。

所以我们需要有一个函数去监测当前参数是否被提供,或者说当前的year是否存在.注意或许会想到keyword_set函数,但是它用于检测参数是否被提供,也就是是否有东西传入进去?如果是下面这种情况:

function test, b=b
    print, keyword_set(b), format='keyword_set: %d'
    b = 123
end

pro temp
    _ = test(b=q)
    print, q
end

那么实际运行结果是:

在这里插入图片描述
所以应该使用arg_present函数,它用于检测是否有参数被传递进去(实际上并不准确,这里不详细说明)。如果无法理解就直接硬记住吧,虽然它实际上就是检测当前变量是否存在或者超出生存期(包括引用指针传入)。

修改后如下:

pro time::GetProperty, year=year, month=month, day=day, doy=doy
    if arg_present(year) then year = self.year
    if arg_present(month) then month = self.month
    if arg_present(day) then day = self.day
    if arg_present(doy) then doy = self.doy
end

这里再说明一个初始化方法(init),这是在类被实例化时会触发的函数,用于对一些信息或者属性等进行初始化。
例如,前面的属性实际上是无法通过struct = {time, inherits idl_object, year: 0l, month: 0l, day: 0l, doy: 0l}进行最初的修改,
即便你已经填写了0,但是仅仅是声明了属性的数据类型。(即便将此处的数值进行修改,值不会发生变化,对于int就是默认的0,对于
string就是默认的空字符串等等)。

所以我们如果我们想要进行一些初始值的修改设定,需要通过inti方法。

function time::init, year, month, day, doy
    ; 初始化
    self.year = year
    self.month = month
    self.day = day
    self.doy = doy
    
    return, 1  ; 1表示成功实例化对象
end

上述代码中的yearmonthdaydoy参数在实例化时间类时需要传入。操作如下:

在这里插入图片描述

上述说明的完整代码如下:

function time::init, year, month, day, doy
    ; 初始化
    self.year = year
    self.month = month
    self.day = day
    self.doy = doy
    
    return, 1  ; 1表示成功实例化对象
end

function time::doy2ymd, year, doy
    old_date = imsl_datetodays(31, 12, year - 1)
    imsl_daystodate, old_date + doy, day, month, year
    
    return, [year, month, day]
end

function time::ymd2doy, year, month, day
    now_date = imsl_datetodays(day, month, year)
    old_date = imsl_datetodays(31, 12, year - 1)
    doy = now_date - old_date

    return, [year, doy]
end

function time::print_time
    print, self.year, self.month, self.day, self.doy, format='年: %d, 月: %02d, 日: %02d, 年积日: %03d'
end

pro time::GetProperty, year=year, month=month, day=day, doy=doy
    if arg_present(year) then year = self.year
    if arg_present(month) then month = self.month
    if arg_present(day) then day = self.day
    if arg_present(doy) then doy = self.doy
end

pro time__define
    struct = {time, inherits idl_object, year: 0l, month: 0l, day: 0l, doy: 0l}
end

到这里基本上完成所有最基本类的创建和简单使用,以下是我对时间类的一些拓展:

function date::Init, _extra=ex
    ; 初始化
    _ = self.idl_object::init()  ; 初始化父类对象
    if isa(ex) then self.setproperty, _extra=ex

    return, 1  ; 1表示成功实例化对象
end

function date::doy2ymd, year, doy, str=str, int=int
    ; 更新
    if (keyword_set(year) and keyword_set(doy)) then begin
        self.year = year
        self.doy = doy
    endif
    
    ; 年积日转化为年月日
    old_date = imsl_datetodays(31, 12, self.year-1)
    imsl_daystodate, old_date + self.doy, self.day, self.month, self.year
    
    return, self.to_ymd(str=str, int=int)
end

function date::to_ymd, str=str, int=int
    if keyword_set(str) then return, string(self.year, self.month, self.day, format='%04d%02d%02d')
    if keyword_set(int) then return, long(string(self.year, self.month, self.day, format='%04d%02d%02d'))
    return, [self.year, self.month, self.day]
end

function date::ymd2doy, year, month, day, str=str, int=int
    ; 更新
    if (keyword_set(year) and keyword_set(month) and keyword_set(day)) then begin
        self.year = year
        self.month = month
        self.day = day
    endif
    
    ; 年月日转年积日
    now_days = imsl_datetodays(self.day, self.month, self.year)
    old_days = imsl_datetodays(31, 12, self.year - 1)
    self.doy = now_days - old_days
    
    return, self.to_doy(str=str, int=int)
end

function date::to_doy, str=str, int=int
    if keyword_set(str) then return, string(self.year, self.doy, format='%04d%03d')
    if keyword_set(int) then return, long(string(self.year, self.doy, format='%04d%03d'))
    return, [self.year, self.doy]
end

; 更新年月日等属性
pro date::_update, ymd=ymd, doy=doy
    if keyword_set(ymd) then begin
        _ = self.ymd2doy(self.year, self.month, self.day)
    endif
    
    if keyword_set(doy) then begin
        _ = self.doy2ymd(self.year, self.doy)
    endif
end

; 取值
pro date::GetProperty, year=year, month=month, day=day, doy=doy
    ; 如果用户请求返回某一属性, 那么将其返回
    if arg_present(year) then year = self.year
    IF arg_present(month) THEN month = self.month
    IF arg_present(day) THEN day = self.day
    if arg_present(doy) then doy = self.doy
end

; 设置值
pro date::SetProperty, ymd=ymd, ydays=ydays
    ; 如果用户传入属性, 那么就设置它
    if (isa(ymd, /integer) or isa(ymd, /string)) then begin
        if (isa(ymd, /integer)) then ymd = string(ymd, format='%08d')
        self.year = fix(strmid(ymd, 0, 4))
        self.month = fix(strmid(ymd, 4, 2))
        self.day = fix(strmid(ymd, 6, 2))
        self._update, /ymd
    endif
    
    if (isa(ydays, /integer) or isa(ydays, /string)) then begin
        if isa(ydays, /integer) then ydays = string(ydays, format='%07d')
        self.year = fix(strmid(ydays, 0, 4))
        self.doy = fix(strmid(ydays, 4, 3))
        self._update, /doy
    endif
end

; 定义Date类
pro date__define
    struct = {date, inherits idl_object, year: 0l, month: 0l, day: 0l, doy: 0l}
end

Bye~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1121954.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

codeforces (C++ Morning)

题目: 翻译: 思路: 1、要将四位数显示,每次操作可以选择移动光标(移动到相邻的位置)或者显示数字,计算最少需要多少次操作。 2、用flag表示当前光标位置,sum为记录操作次数&#…

【试题039】 多个逻辑或例题

题目:设int n;,执行表达式(n0)||(n1)||(n2)||(n3)后,n的值是?代码分析: //设int n; , 执行表达式(n 0) || (n 1) ||(n 2) ||(n 3)后, n的值是?int n;printf("n%d\n", (n 0) || (n 1) || (n 2) || (n 3));//分析&#xff1…

怎么写一个可以鼠标控制旋转的div?

说在前面 鼠标控制元素旋转在现在也是一个很常见的功能,让我们从实现div元素的旋转控制开始来了解元素旋转的具体原理和实现方法吧。 效果展示 体验地址 https://code.juejin.cn/pen/7290719197439459386 实现步骤 画一个div 首先我们需要先画一个div&#xff0…

Android快速滑动条/快速滑块/快速滚动条标准实现,Java

Android水平和垂直方向的快速滑动条/快速滑块/快滑滚动条/快滑滚动块标准实现,Java /** Copyright 2018 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in com…

如何在linux服务器上安装Anaconda与pytorch

如何在linux服务器上安装Anaconda与pytorch 1,安装anaconda1.1 下载anaconda安装包1.2 安装anaconda1.3 设计环境变量1.4 安装完成验证 2 Anaconda安装pytorch2.1 创建虚拟环境2.2 查看现存环境2.3 激活环境2.4 选择合适的pytorch版本下载2.5 检测是否安装成功&…

FPGA设计时序约束六、设置最大/最小时延

目录 一、背景 二、Max/Min_delay约束 2.1 约束设置参数 2.2 约束说明 三、工程示例 3.1 工程代码 3.2 时序报告 四、参考资料 一、背景 在设计中,有时需要限定路径的最大时延和最小时延,如没有特定时钟关系的异步信号,但需要限制最大…

【tg】4:NetworkManager :p2p、ice、消息收发

代码分布 NetworkManager 自成体系,看起来也么有啥依赖 class NetworkManager : public sigslot::has_slots<>, public std::enable_shared_from_this<NetworkManager

Redis缓存(缓存预热,缓存穿透,缓存雪崩,缓存击穿)

目录 一, 缓存 1, 什么是缓存 2, 什么是热点数据(热词) 3, 缓存更新策略 3.1 定期生成 3.2 实时生成 二, Redis缓存可能出现的问题 1, 缓存预热 1.1 什么是缓存预热 1.2 缓存预热的过程 2, 缓存穿透 2.1 什么是缓存穿透 2.2 缓存穿透产生的原因 2.3 缓存穿透的解…

html表格标签

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><!--表格table 行 tr 列 td --> <table border"1px"><tr> <!--colsp…

《数据结构与算法之美》读书笔记1

Java的学习 方法参数多态&#xff08;向上和向下转型&#xff09; 向上转型&#xff1a; class Text{public static void main(String[] args) {Animals people1 new NiuMa();people1.eat1();//调用继承后公共部分的方法&#xff0c;没重写调用没重写的&#xff0c;重写了调…

DataGridView的下拉DataGridViewComboBoxColumn的数据绑定问题

DataGridView的下拉DataGridViewComboBoxColumn的数据绑定问题 需求&#xff1a;左边这列固定x行&#xff0c;右边显示下拉&#xff0c;并且赋上默认值 public void Set(){// 添加需要固定显示的行数dataGridView1.Rows.Add("早班";dataGridView1.Rows.Add("中…

电脑技巧:笔记本电脑网络不显示wifi列表解决办法

目录 1.WiFi功能被关闭 2.启用了飞行模式 3.WLAN连接被禁用 4.无线网卡驱动未安装 5.WLAN AutoConfig服务未启动 我的笔记本电脑连接wifi时&#xff0c;结果wifi列表中不显示任何的网络信息&#xff0c;这是怎么回事&#xff1f;要如何解决&#xff1f; 答&#xff1a;笔…

Go学习第四章——程序流程控制

Go学习第四章——程序流程控制 1 分支结构1.1 单分支1.2 双分支1.3 多分支1.4 switch分支 2 循环结构2.1 for循环2.2 while和dowhile的实现2.3 经典案例——打印金字塔2.4 经典案例——打印九九乘法表 3 跳转控制语句3.1 break3.2 continue3.3 goto3.4 return 流程控制的作用&a…

JavaSE入门---认识String类、学习String类的相关方法

文章目录 什么是String类&#xff1f;String类的常用方法字符串构造&#xff08;三种&#xff09;String对象的比较&#xff08;四种&#xff09;字符串查找转化数值和字符串转化大小写转化字符串和数组转化格式化 字符串替换字符串拆分字符串截取字符串的其他方法 字符串常量池…

SOLIDWORKS 2024新功能 3D CAD三维机械设计10大新功能

SOLIDWORKS 2024新增功能 - 3D CAD三维机械设计 10大新增功能 1. 先前版本的兼容性 •利用您订阅的 SOLIDWORKS&#xff0c;可将您的 SOLIDWORKS 设计作品保存为旧版本&#xff0c;与使用旧版本 SOLIDWORKS 的供应商无缝协作。 •可将零件、装配体和工程图保存为最新版本…

【CSS】常见 CSS 布局

1. 响应式布局 <!DOCTYPE html> <html><head><title>简单的响应式布局</title><style>/* 全局样式 */body {font-family: Arial, sans-serif;margin: 0;padding: 0;}/* 头部样式 */header {background-color: #333;color: #fff;padding: …

【C语言练习题】添加逗号

✨博客主页&#xff1a;小钱编程成长记 &#x1f388;博客专栏&#xff1a;C语言练习题 添加逗号 1. 题目2.讲解3.代码总结 1. 题目 牛客网在线OJ 2.讲解 因为数字位数可能不全是3的倍数&#xff0c;比如&#xff1a;23&#xff0c;445&#xff0c;555。所以我们从后向前进行&…

“我有一个大胆的想法”?Meta AI 新技术让你的思维图像一览无余!

夕小瑶科技说 原创 作者 | 付奶茶 大家之前是否想象过未来的技术进步会带来读脑器&#xff0c;计算界面是否有可能越过触摸屏、键盘进入我们思维内部读取我们脑袋中所想。尽管当前我们社会尚未达到这一阶段&#xff0c;但我们确实逐渐接近这一愿景&#xff01; 不久前&#x…

DDR电源硬件设计要点

一、DDR电源简介 1. 电源 DDR的电源可以分为三类: a、主电源VDD和VDDQ,主电源的要求是VDDQ=VDD,VDDQ是给IO buffer供电的电源,VDD是给但是一般的使用中都是把VDDQ和VDD合成一个电源使用。 有的芯片还有VDDL,是给DLL供电的,也和VDD使用同一电源即可。电源设计时,需要考…

【PyTorch】深度学习实践 02 线性模型

深度学习的准备过程 准备数据集选择模型模型训练进行推理预测 问题 对某种产品花费 x 个工时&#xff0c;即可得到 y 收益&#xff0c;现有 x 和 y 的对应表格如下&#xff1a; x &#xff08;hours&#xff09; y&#xff08;points&#xff09;12243648 求花费4个工时可得…