Python从入门到进阶(十三)——解析命令行参数与时间日期处理

1 解析命令行参数

  1. argparse介绍:
argparse 是 Python 内置的一个用于命令项选项与参数解析的模块;
argparse 将会从 sys.argv 中解析出这些参数,并自动生成帮助和使用信息
  1. argparse使用:
    ArgumentParser对象的相关属性。
    全部参数见下表:
属性解释默认值
prog程序的名称sys.argv[0]
usage描述程序用途的字符串自动生成
description在参数帮助文档之前显示的文本None
epilog在参数帮助文档之后显示的文本同上
parents一个ArgumentPaser对象的列表,它们的参数也应包含在内[]
prefix_chars可选参数的前缀字符集合'-'
formatter_class用于自定义帮助文档输出格式的类argparse.HelpFormatter
fromfile_prefix_chars当需要从文件中读取其他参数时,用于标识文件名的前缀字符集合None
argument_default参数的全局默认值同上
conflict_handler解决冲突选项的策略‘error’
add_help为解析器添加一个 -h/--help选项True
llow_abbrev如果缩写是无歧义的,则允许缩写长选项(版本>=python3.5)True
exit_on_error决定当错误发生时是否让ArgumentParser附带错误信息退出(版本>=python3.9)同上
示例代码:
#导入argparse模块
import argparse  
# 创建解析器
parser = argparse.ArgumentParser(description='desc')  
# 添加整型参数
parser.add_argument('--integers', type=int, default=0, help='input an integer')  
# 解析参数parse_args()通常不带参数调用,ArgumentParser将自动从sys.argv确定命令行参数。
args = parser.parse_args()  
print(args)
#返回一个具有integers属性的对象 Namespace(integers=0).

源码中的add_argument()方法解析:

ArgumentParser.add_argument(name or flags...,
                            action='',
                            nargs='',
                            const,
                            default,
                            type,
                            choices,
                            required,
                            help,
                            metavar,
                            dest)
add_argument(‘-f’, ‘–foo’) # 可选参数
add_argument(‘foo’) # 位置参数
action #该action关键字参数指定的命令行参数应该如何处理
action = ‘store’ # 默认操作仅存储参数的值,可以不写
action = ‘store_const’ # 将存储由const关键字参数指定的值
action = ‘store_true’ # 这些是’store_const’分别存储值True和False的情况下使用
action = ‘store_false’
action = ‘append’ # 存储一个列表,并将命令行的每个参数值附加到列表中
action = ‘append_const’ # 存储一个列表,并将const关键字参数指定的值附加到列表中,可用于多个参数需要将常量存储到同一列表,const默认参数为None
action = ‘count’ # 计算关键字参数出现的次数
action = ‘extend’ # 存储一个列表,并将每个参数值添加到列表中
nargs : 将单个命令行参数与要执行的单个操作相关联,并收集到一个列表中
nargs = N(一个整数) # nargs=2,命令行python test.py --foo a b 将a,b收集到一个列表中
nargs = ? # 表示从命令行使用一个参数,作为选项参数的值,如果命令行指定了参数的值则使用(python test.py --foo xx),如果不存在命令行参数(python test.py),使用default默认值,如果存在可选项参数(python test.py --foo),但是没有指定参数值,会使用const的值。
nargs = * # 存在的所有命令行参数都收集到一个列表中
nargs = + # 跟*用法一样,都会收集到一个列表中,但是如果没有命令行参数则会报错
default # 指定默认值
type # 指定类型 int float等
choices # 指定某些命令行参数应从一组受限制的值中选择,如果参数不是可接受的值一直,则报错
required=True # 指定参数值为必填
help #帮助信息说明

代码示例,
实现输入数字,返回指定值

import argparse

# 创建解析对象,并添加描述信息
parser = argparse.ArgumentParser(description = "输出数字2倍数") 
# 添加命令行参数“num",还有该参数的帮助信息,参数类型
parser.add_argument("num", help="2*num a given number", type = int)
# 进行解析
args = parser.parse_args()
# 实现功能
print(args.square*2)
  1. Python 命令行解析
    手工编写 Python 命令行解析,支持 ‘-x’ 或者 ‘–x’ 类型选项处理,如果没有指定值则设置为True
# -*- coding: UTF-8 -*-
import sys

def error(info):
    print(info)
    sys.exit(0)

def parse_option(token):
    if len(token) == 0 or len(token) == 1 or token[0] != '-':
        error("格式错误,选项长度至少大于2并且第一个字符必须是 '-'")

    if token[1] != '-':
        return token[1:]

    if len(token) == 2 or token[2] == '-':
        error("格式错误,不支持空选项 '--' 或则三横杆选项 '---x' ")

    return token[2:]

def parse_value(token):
    if token is None:
        return True

    if len(token) == 0:
        return True

    if token[0] == '-':
        error('格式错误')
    else:
        return token

if __name__ == '__main__':
    count = len(sys.argv)
    options = {}
    
    # TODO(You): 请在此使用 parse_option 和 parse_value 解析命令行

    for option in options:
        value = options[option]
        print("{}={}".format(option, value))
        请选出下列能正确实现这一功能的选项。
        A.
    i = 1
	while i < count:
	    token = sys.argv[i]
	    next_token = None
	    if i+1 < count:
	        next_token = sys.argv[i+1]
	
	    option = parse_option(token)
	    value = parse_value(next_token)
	
	    options[option] = value
	    i += 1
    B.
    i = 1
while i < count:
    token = sys.argv[i]
    next_token = None
    if i+1 < count:
        next_token = sys.argv[i+1]

    option = parse_value(token)
    value = parse_option(next_token)

    options[option] = value
    i += 1
    C.
    i = 1
while i < count:
    token = sys.argv[i]
    next_token = None
    if i+1 < count:
        next_token = sys.argv[i+1]
        i = i + 1

    option = parse_option(token)
    value = parse_value(next_token)

    options[option] = value
    i += 1
    D.
    i = 1
while i < count:
    token = sys.argv[i]
    next_token = None
    if i+1 < count:
        next_token = sys.argv[i+1]
        i = i + 1

    option = parse_option(token)
    value = parse_value(next_token)

    options[option] = value
# C正确
  1. Python命令行解析(二)
    使用 optparse 库配置指定命令行选项,并解析命令行 1. 选项 ‘-s’ 和选项 ‘–server’ 等价 2. 选项 ‘–host’ 设置默认为 0.0.0.0 3. 选项 ‘–port’ 设置默认为 80 4. 选项 ‘–ssl’ 如果指定,则 option.ssl=True
使用 optparse 库配置指定命令行选项,并解析命令行 1. 选项 '-s' 和选项 '--server' 等价 2. 选项 '--host' 设置默认为 0.0.0.0 3. 选项 '--port' 设置默认为 80 4. 选项 '--ssl' 如果指定,则 option.ssl=True

# -*- coding: UTF-8 -*-
from ast import parse
from optparse import OptionParser

if __name__ == "__main__":
    parser = OptionParser()

    # TODO(You): 请在此添加上述要求的4个命令行参数选项配置
    
    (options, args) = parser.parse_args()
    print(f"server={options.server}")
    print(f"host={options.host}")
    print(f"port={options.port}")
    print(f"ssl={options.ssl}")

请选出下列能正确实现这一功能的选项。
A.
parser.add_option(
    "-s", "--server",
    dest="server",
    help="server",
    metavar="SERVER"
)

parser.add_option(
    "-h", "--host",
    dest="host",
    help="host",
    metavar="HOST"
)

parser.add_option(
    '-p', "--port",
    dest="port",
    help="port",
    default='80',
    metavar="PORT"
)

parser.add_option(
    "--ssl",
    dest="ssl",
    help="ssl",
    action="store_true",
    metavar="SSL"
)
B.
parser.add_option(
    "-s", "--server",
    dest="server",
    help="server",
    metavar="SERVER"
)

parser.add_option(
    "-h", "--host",
    dest="host",
    help="host",
    default='0.0.0.0',
    metavar="HOST"
)

parser.add_option(
    '-p', "--port",
    dest="port",
    help="port",
    default='80',
    metavar="PORT"
)

parser.add_option(
    "--ssl",
    dest="ssl",
    help="ssl",
    action="store_true",
    metavar="SSL"
)
C.
parser.add_option(
    "-s", "--server",
    dest="server",
    help="server",
    metavar="SERVER"
)

parser.add_option(
    "-h", "--host",
    dest="host",
    help="host",
    default='0.0.0.0',
    metavar="HOST"
)

parser.add_option(
    '-p', "--port",
    dest="port",
    help="port",
    default='80',
    metavar="PORT"
)

parser.add_option(
    "--ssl",
    dest="ssl",
    help="ssl",
    action="store_true",
    metavar="SSL"
)
D.
parser.add_option(
    "-s", "--server",
    dest="server",
    help="server",
    metavar="SERVER"
)

parser.add_option(
    "-h", "--host",
    dest="host",
    help="host",
    default='0.0.0.0',
    metavar="HOST"
)

parser.add_option(
    '-p', "--port",
    dest="port",
    help="port",
    default='80',
    metavar="PORT"
)

parser.add_option(
    "--ssl",
    dest="ssl",
    help="ssl",
    metavar="SSL"
)
# C 正确

2 时间日期处理

python中时间处理主要使用的库是datetime

  1. datetime是内置模块,不需要安装,直接使用
    import datetime
    2.datetime里面有五个类:
  • date类:表示日期的类
  • time类:表示时间的类
  • datetime类:表示时间日期的类
  • timedelta类:表示两个datetime对象的差值
  • tzinfo类:表示时区的相关信息
    其中最常用的是datetime类,其包含了date类和time类.
    3.模块的使用:
    datetime的简单使用
#获取当前日期
from datetime import datetime
now = datetime.now()
#获取今天
datetime.today()
#获取指定日期
datetime.date(y,m,d)
datetime.time(h,m,s)
datetime(y,m,d,h)
#输出指定格式
print('strftime():', now.strftime("%Y-%m-%d"))

timedelta的使用

import datetime
now = datetime.now()
y = now + timedelta(days=-1) # 昨天
m = now + timedelta(days=1)  # 明天
  1. 使用案例:输出指定日期是星期几
# python3
#! coding=utf8

from datetime import datetime

year,month,day= 2023,10,6

weekday = ['周一','周二','周三','周四','周五','周六','周日']

i = datetime(year,month,day).weekday()
print(weekday[i])


i = datetime(year,month,day).isoweekday()
print(weekday[i-1])


wday = datetime(year,month,day).strftime('%a')
print(wday)
  1. 扩展,一个用来计算农历的库
zhdate
安装
pip install zhdate

示例:

#! python3
#! encoding=utf8

from datetime import datetime
import zhdate

'''
pip install zhdate
计算农历, 公历和农历的转换
内置1900-2100的农历数据
'''

date_now = zhdate.ZhDate.today()
print(date_now)

date_1 = zhdate.ZhDate(2022,1,1)
print(date_1)

date_2 = date_1.to_datetime()
print(date_2.date())

#计算距离端午节还有几天
zhdwj = zhdate.ZhDate(2024,5,5)
dwj = zhdwj.to_datetime()
now_day = datetime.now()
total = dwj.toordinal() - now_day.toordinal()
print(f'今天{now_day.strftime("%Y-%m-%d")}距离{zhdwj.chinese()}-端午节还有{total}天')

  1. Python计时器
    便利的 Python 计时器,统计从 0 遍历到 100000 消耗的时间,精确到毫秒
便利的 Python 计时器,统计从 0 遍历到 100000 消耗的时间,精确到毫秒

# -*- coding: UTF-8 -*-
from datetime import datetime
from time import time, mktime

class TimeSpan:
    def __init__(self) -> None:
        self.start = round(time() * 1000)

    def elapse_mill_secs(self):
        # TODO(You): 请在此计算从开始到现在的耗时,精确到毫秒

    def elapse_secs(self):
        return (self.elapse_mill_secs())/1000

if __name__ == '__main__':
    s = TimeSpan()

    for i in range(0, 100000):
        pass
    print('耗时: {} 毫秒'.format(s.elapse_mill_secs()))
    print('耗时: {} 秒'.format(s.elapse_secs()))

以下实现,错误 的是?。
# A.
def elapse_mill_secs(self):
    end = round(time() * 1000)
    return end-self.start
# B.
def elapse_mill_secs(self):
    end = round(mktime(datetime.now().timetuple())*1000)
    return end-self.start
# C.
def elapse_mill_secs(self):
    end = round(datetime.now().timestamp() * 1000)
    return end-self.start
# D.
def elapse_mill_secs(self):
    end = round(time(datetime.now())*1000)
    return end-self.start
# D错误
  1. Python时间加法
    从2008年1月开始到本月,遍历每一个月份的1号,并打印信息
# -*- coding: UTF-8 -*-
from datetime import date, timedelta
from calendar import monthrange
 
def next_month(d):
    # TODO(You): 请在此实现计算下一个月的代码
    return value
 
def for_each_month(start, finish, action):
    while start < finish:
        action(start)
        start = next_month(start)
 
if __name__ == '__main__':
    for_each_month(
        date(2008, 1, 1),
        date.today(),
        lambda d: print(d)
    )
    # 请选出以下实现 错误 的代码。
# A.
offset = monthrange(d.year, d.month)
first_weeky_day, days_in_month = offset
value = d+timedelta(days_in_month)  
# B.
offset = monthrange(d.year, d.month)
days_in_month, first_weeky_day = offset
value = d+timedelta(days_in_month)  
# C.
offset = monthrange(d.year, d.month)
days_in_month = offset[1]
value = d+timedelta(days_in_month)
# D.
days_in_month = monthrange(d.year, d.month)[1]
value = d+timedelta(days_in_month)
# B错误
题目逻辑分析:
1、定义了一个 next_month 函数,用于计算下一个月的日期。
2、next_month 函数的输入参数是一个日期对象 d。
3、使用 monthrange 函数计算出当前月份的天数和第一天是星期几。
4、提取出当前月份的天数,加上一个月之后的天数,得到下一个月的日期。
5、返回下一个月的日期。
6、定义了一个 for_each_month 函数,用于遍历一个时间段内的每一个月份。
7、for_each_month 函数的输入参数包括开始日期、结束日期和一个处理函数 action。
8、在 for_each_month 函数中,使用 next_month 函数计算下一个月份的日期,并调用 action 处理函数处理该日期。
9、在 main 函数中,使用 for_each_month 函数遍历从 20081 月开始到当前日期的每一个月份,并输出该月份的日期。
 题目逐段分析:
 from datetime import date, timedelta
from calendar import monthrange
 
# 定义一个函数,用于计算下一个月的日期
def next_month(d):
    # 获取当前日期所在月的天数信息
    offset = monthrange(d.year, d.month)
    # 获取当前月份的总天数
    days_in_month = offset[1]
    # 获取下一个月的日期,使用 timedelta 函数加上当前月份的总天数即可
    value = d + timedelta(days_in_month)
    # 返回计算出的下一个月的日期
    return value
 
# 定义一个函数,用于对指定日期区间内的每个月进行遍历并执行指定的操作
def for_each_month(start, finish, action):
    # 不断对 start 进行遍历,直到达到指定的 finish 日期
    while start < finish:
        # 执行指定的操作
        action(start)
        # 获取下一个月的日期
        start = next_month(start)
 
# 主程序入口
if __name__ == '__main__':
    # 遍历指定日期区间内的每个月份
    for_each_month(
        date(2008, 1, 1),
        date.today(),
        lambda d: print(d)
    )
题目中的引入知识:
1、monthrange(year, month) ,是 Python 标准库中 calendar 模块的函数之一,用于获取给定年份和月份的月份天数和第一天的星期几。该函数返回一个二元组,第一个元素是该月份的天数,第二个元素是该月份第一天的星期几,星期一是0,星期日是6。
例如, calendar.monthrange(2022, 2) 返回 (28, 1),表示20222月有28天,第一天是星期二。
2、序列解包,是指将一个序列(包括列表、元组、字符串、集合等)中的元素,按照顺序赋值给多个变量的过程。具体地说,就是将一个序列按照位置顺序,依次赋值给一系列变量,变量的个数应该和序列中的元素个数相等。序列解包的实际应用场景很多,比如函数返回多个值、交换两个变量的值、遍历字典等等。
例如,我们有一个元组(1,2,3),我们可以通过序列解包将其赋值给三个变量:
a, b, c = (1, 2, 3)
print(a, b, c) # 输出:1 2 3
答案中错误的代码分析:

offset = monthrange(d.year, d.month)
# 1、monthrange返还了d.year和d.month两个值
# 2、用序列解包的方式把赋值给days_in_month, first_weeky_day
# 然鹅:days_in_month的为d.year取错了,first_weeky_day没有使用。
days_in_month, first_weeky_day = offset
value = d+timedelta(days_in_month)
答案中正确的代码分析:

offset = monthrange(d.year, d.month)
# 取值正确,但first_weeky_day没有使用。
first_weeky_day, days_in_month = offset
value = d+timedelta(days_in_month)
# 最优代码,省略了offset转存的过程。
days_in_month = monthrange(d.year, d.month)[1]
value = d+timedelta(days_in_month)
在 Python 中,我们可以使用星号(*)来表示序列解包中的“剩余部分”,即将多余的元素赋值给一个列表。比如,如果一个序列中有 5 个元素,而你只想取前两个元素,同时也想把剩余的元素存入一个列表中,可以这样写:a, b, *rest = [1, 2, 3, 4, 5]。这样,a 和 b 分别被赋值为 12,而 rest 则被赋值为 [3, 4, 5]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值