Python3 初学实践案例(6)终极 CLI 密码生成程序实现

Python3 初学实践案例(6)终极 CLI 密码生成程序实现

在前面一章的学习中,我已经完成了一个一定扔出 6 的生成密码算法实现。但是只能将生成的密码输出到终端,并不能够将密码保存到文件,这样还是很有问题的。

随机生成的东西我记都记不住,回头找不回来就麻烦了。所以,我需要给它加上这个功能。

实现源码

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import random
import argparse
import os
import time
import clipboard

# 设定密码保存路径
DEFAULT_FILENAME = './password.txt'

# 根据需要的结果,剪出一个数组
def cutLength(leng, level):
    # 算法比较复杂,简化来说,就是已知数组长度,和数组内数字的和
    # 求一个随机的数组,满足上面的两个条件
    res = []
    for i in range(level, 1, -1):
        res.append(random.randint(1, leng - sum(res) - i + 1))
    res.append(leng - sum(res))
    # 因为第一位生成大数字的几率高于后面的几位,
    # 所以在得到结果后,随机排序一下,以期待更随机一些
    random.shuffle(res)
    return res
# 根据上面生成的数组和对应的字典,制造一个密码数组
def makePassword(dists, arr):
    res = []
    # 根据字典和数组,循环生成密码
    for i in range(len(arr)):
        # res += random.choices(dists[i], k=arr[i])
        for j in range(arr[i]):
            res += random.choice(dists[i])
    # 得到结果后,再一次随机排序
    random.shuffle(res)
    # 最后把数组变成字符串,并输出
    return ''.join(res)
# 生成一个密码函数
def getPassword(leng, level):
    # 根据密码长度和等级,去求一个满足条件的数组
    arr = cutLength(leng,level)
    # 制造字典
    str1 = '01'
    str2 = '23456789'
    str3 = 'abcdefghijkmnpqrstuvwxyz'
    str4 = 'ABCDEFGHJKMNPQRSTUVWXYZ'
    str5 = '_@!,.:;-=+/?'

    dists = {
                1: [str1 + str2],
                3: [str2, str3, str4],
                4: [str2, str3, str4, str5]
            }
    # 生成密码
    return makePassword(dists[level], arr)

# 将生成的密码写入文件
def writePassword(name, passwd):
    # 如果文件不存在,则创建该文件
    if not os.path.exists(DEFAULT_FILENAME):
        f = open(DEFAULT_FILENAME, 'w')
        f.write('Here save the passwords generated by history\n\n')
        f.close()

    # 获取当前时间
    t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    # 将结果追加到文件中
    f = open(DEFAULT_FILENAME, 'a')
    f.write(name + '\t' + passwd + '\t' + t + '\n')
    f.close()

# 输出结果
def returnPassword(passwd, name):
    clipboard.copy(passwd)
    print('New password:\t\033[31m' + passwd + '\033[0m\nTip: The password has been copied to the clipboard')
    if name:
        print('And the password has been saved in the ' + DEFAULT_FILENAME + ' file')
    exit()

# 主函数
if __name__ == "__main__":
    # 设置命令行参数
    parser = argparse.ArgumentParser()
    parser.description='This program is used to generate simple or complex passwords'
    parser.add_argument("-v", "--version",action='version', version='%(prog)s 1.0')
    parser.add_argument('length', type=int, help='The length of the password (Default 8)', nargs='?')
    parser.add_argument('-n', '--name', help='Take a name for your password and Write it in ' + DEFAULT_FILENAME)

    group = parser.add_mutually_exclusive_group()
    group.add_argument("-s", "--simple", help="The password is made up of pure numbers", action="store_true")
    group.add_argument("-c", "--commonly", help="The password is made up of numbers and letters (Default)", action="store_true")
    group.add_argument("-d", "--difficult", help="The password is made up of numbers, letters, and punctuation", action="store_true")

    # 获取命令行参数结果
    args = parser.parse_args()

    # 确定密码长度为命令行设置或者默认为8
    length = args.length or 8

    # 如果密码长度小于 4 则提示并退出
    if length < 4:
        parser.print_usage()
        print('error: The password length must be greater than 3')
        exit()

    # 默认密码等级为一般
    level = 3

    if args.simple:
        level = 1
    if args.difficult:
        level = 4

    # 去得到密码
    res = getPassword(length, level)
    # 如果密码需要保存,则写入文件
    if args.name:
        writePassword(args.name, res)
    # 返回结果
    returnPassword(res, args.name)

运行效果:

重点补充

新增可选命令参数

我们需要保存密码,但是保存的是个啥密码我咋知道呢?所以,还是很有必要为这个密码取个名字的。这需要我们在过去密码的时候增加一个参数,这个参数可以缀一个值,这个值,就是我们为密码保存的名字。

代码如下:

parser.add_argument('-n', '--name', help='Take a name for your password and Write it in "./password.txt"')

所有加了 - 的参数都是可选项。

有了这样一个选项之后,我们就可以通过 args.name 拿到脚本执行时用户输入的名字参数是什么了。如果没有这个参数,则会返回 None

创建与写入文件以及判断文件是否存在

我们设定了一个保存文件的路径为 "./password.txt" ,但是如果这个文件不存在呢?

所以我们首先需要判断这个文件存在不存在,这就需要引入 os 库来解决问题:

import os
if not os.path.exists(file_path)

如果文件不存在,我们可以使用 open 来创建这个文件,并且写入内容:

f = open(file_path, 'w')
f.write('Here save the passwords generated by history\n\n')
f.close()

需要注意的是,在 open 了之后,一定要 close()

如果文件存在,则需要使用追加的方式在文件最后写入内容:

f = open(file_path, 'a')
f.write(name + '\t' + passwd + '\t' + t + '\n')
f.close()

一样,是需要关闭的。

将结果复制到剪切板

我们生成出来了密码,但是需要到终端里面复制一下,这个显然很不方便,所以如果能再生成密码的同时就将密码复制到剪切板,无疑能增加我们的程序的用户体验。

实现这个功能也不复杂,我们需要引入一个库叫 clipboard,然后在需要复制到剪切板的地方用下面的代码即可完成我们的需求。

clipboard.copy(string)

好,其他都是之前学过的内容了。完美~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏非典型程序猿

从源码透析gRPC调用原理

gRPC是如何work的,清楚的理解其调用逻辑,对于我们更好、更深入的使用gRPC很有必要。因此我们必须深度解析下gRPC的实现逻辑,在本文中,将分别从客户端和...

5.3K80
来自专栏闻道于事

vim命令

9410
来自专栏崔庆才的专栏

用Flask+Aiohttp+Redis维护动态代理池

59150
来自专栏向治洪

Android性能优化之TraceView和Lint使用详解

Android lint工具是Android studio中集成的一个代码提示工具,它主要负责对你的代码进行优化提示,包括xml和java文件,很强大。编写完代...

26760
来自专栏友弟技术工作室

vim精简版教程

vim编辑器 ? vim trree 编辑器的分类 文本编辑器,ASCII码 字处理器:word 全称 vi:Visual interface vim: Vis...

24050
来自专栏大数据钻研

9 个让 JavaScript 调试更简单的 Console 命令

一、显示信息的命令 <!DOCTYPE html> <html> <head> <title>常用console命令</title> ...

350100
来自专栏技术碎碎念

OS存储器管理(二)

离散分配 分页(Paging),分段,段页式 一、分页 一个进程的物理地址可以是非连续的; 将物理内存分成固定大小的块,称为块(frame); 将逻辑内存分为同...

34880
来自专栏linux驱动个人学习

Linux CFS调度器之队列操作--Linux进程的管理与调度(二十七)

完全公平调度器CFS中有两个函数可用来增删队列的成员:enqueue_task_fair和dequeue_task_fair分别用来向CFS就绪队列中添加或者删...

18620
来自专栏CSDN技术头条

Java 9的14个新特性总结

Java 9 包含了丰富的特性集。虽然Java 9没有新的语言概念,但是有开发者感兴趣的新的API和诊断命令。 我们将快速的,着重的浏览其中的几个新特性: ? ...

22350
来自专栏云计算教程系列

如何在CVM上同步自建数据库的数据?

Transporter是一种用于在不同数据存储之间移动数据的开源工具。开发人员经常为诸如跨数据库移动数据,将数据从文件移动到数据库或反之亦然等任务编写一次性脚本...

226120

扫码关注云+社区

领取腾讯云代金券