综合练习

一. 基础题

1. 集合内元素的三个特征什么是?

"""
1. 集合内元素无序
2. 集合内元素必须为不可变类型
3. 集合内元素唯一
"""

2. 集合的用途是什么?

"""
去重, 关系运算
"""

3. 如何解决python3乱码问题

"""
你使用的编辑器使用什么字符编码存入硬盘的,你就指定文件头 (encoding: 存入硬时的字符编码) 就使用什么编码类型.

# 标准: 指定文件头 # encoding: 与文件存的编码格式一致
"""

4. 控制文件读写内容的模式

"""
t: 文本模式, 只能读取文本文件.
b: bytes模式, 可以读取任意类型的文件.  # 补充: b模式也叫二进制模式
"""

5. 控制文件读写操作的模式

"""
r: 只读模式.文件不存在报错,文件存在文件指针在起始位置.
w: 只写模式. 文件不存在创建, 文件存在则清空原文件中的数据.文件指针在起始位置.
a: 只追加模式. 文件不存在创建, 文件存在则在文件末尾追加写内容.文件指针在结束位置.
x: 只写模式. 文件不存在创建, 文件存则报错.文件指针在起始位置.

以下三种模式都是以加号左边的模式为基准来控制文件读写操作: 
r+: 可读可写模式. 
w+: 可写可读模式.
a+: 可追加写刻度模式.
x+: 可写可读模式.
"""

6. 文件操作的基本操作流程是什么(注意)?

"""
1. 调用open功能让操作系统按照指定的路径去打开文件, 并赋值给一个f句柄对象
2. 当执行到f.read()操作,操作系统按照控制文件读写操作的模式去操作文件
3. 操作系统把文件从硬盘读入内存,按照指定的字符编码解码,加载到内存解码为unicode(等同于字符串)
4. 当执行完毕f.read()操作,文件指针移动到文件的末尾.操作完文件以后执行f.close()操作,回收操作系统资源.

# 标准:
1. 打开文件
2. 读取内容
3. 关闭文件
"""

7. 文件处理with的好处是什么(注意)?

"""
with简称上下文管理: 上, 帮我们操作指定文件的一系列操作  下, 帮我们自动回收操作系统资源(自动调用f.close())  

# 标准: with称之为上下文管理, 上文帮你打开文件, 下文帮你关闭文件
"""

8. 为何要用文件?

"""
永久保存数据不丢失  # 详细: 用户或者应用程序可以通过文件, 将数据永久保存到硬盘中
"""

9. 什么是函数?

"""
函数就是执行某一特定功能的工具.   # 订正: 函数就是具备某一功能的工具
"""

10. 函数的使用,必须先遵循什么?

"""
先定义 后调用
"""

11. 为何要用函数?

"""
1. 增加程序的可维护性, 可扩展性
2. 减少代码冗余问题  # 订正: 解决代码冗余问题
3. 让程序体结构清晰,功能区分增强了可读性.
"""

12. 定义函数会发生什么事情?

"""
1. 申请内存空间保存函数体代码
2. 将上述内存地址与函数名进行绑定, # 补充: 且函数名最好使用动词
3. 定义函数阶段不执行函数体代码, 只检测语法.
"""

13. 调用函数发生的事情

"""
1. 通过函数名找到对应的函数体代码的内存地址 # 订正: 通过函数名找到函数的内存地址
2. 通过加括号, 触发函数体代码的执行
3. 这个时候开始检测函数体代码内的语法.
"""

14. 定义函数的三种形式分别是什么?

"""
无参:
def func():
    print("from func")
    
有参:
def func(x):
    print(x)

空函数:
def func():
    pass
"""

15. 函数调用的三种形式分别是什么?

"""
语句形式:
func()

表达式:
赋值表达式
res = func()
print(res)    
    
数学表达式
add(1, 2) * 10

调用结果的返回值作为参数:
add(add(1, 2), 3)
"""

16.函数的返回值是否可以返回多个?是否可以返回所有数据类型?

"""
1. 可以返回多个,每个值以逗号隔开,且返回的是一个元组的格式.
2. 可以返回所有数据类型.
"""

17. 什么是形参?什么是实参?

"""
形参: 定义函数时,函数内定义的形式参数, 简称形参  # 订正: 在函数定义阶段, 定义的形式参数,称之为形参. 形参相当于变量名
实参: 调用函数时,为函数进行传值的实际参数, 简称实参
"""

18. 形参与实参的关系(注意)

"""
形参相当于变量名, 实参相当于变量值. 实参是对形参的一种赋值(引用).

# 订正:  
绑定关系: 在调用阶段,实参的值会绑定给形参名
使用范围: 函数这种绑定关系的参数只能在函数体内使用
生效时间: 实参于形参的绑定关系会在函数调用时生效,函数调用结束后绑定关系解除 
"""

19. 名称空间的加载顺序是什么?

"""
内置名称空间 > 全局名称空间 > 局部名称空间
"""

20. 名称空间的销毁顺序

"""
局部名称空间 > 全局名称空间 > 内置名称空间 
"""

21. 什么是闭包函数(注意)

"""
'闭': 指的是该函数是内嵌函数
'包': 指的是外层函数为该函数提供所需的数据.  # 订正: 指的是该函数对外层函数作用域名字的引用(不是全局名称空间)
"""

22. tail -f access.log程序实现(监听名为 access.log 的文件的末尾 是否增加了数据)

import os
import time


def monitor_log(log_path='access.log'):
    if os.path.isfile(log_path):
        with open(log_path, 'rb') as f:
            f.seek(0, 2)
            while True:
                res = f.readline()
                if res:
                    print(res.decode('utf-8'), end='')
                else:
                    time.sleep(0.3)
# monitor_log()

23. 以下代码的执行结果是什么?为什么?

"""
结果: 报错
为什么: 定义阶段func局部中说我有x,你不要去别的地方找了.调用的时候x却没有定义,这个属于逻辑混乱,语法错误
"""

24. 下述结果为?

# 结果: 1

25. read、readline 和 readlines 的区别?

"""
# 以下读取文件返回值全是字符串类型:
read: 一次性读取 
    在b模式下read(n),n指的是从文件指针当前位置读取的字节个数. 
    在t模式下read(n),n指的是从文件指针当前位置读取的字符个数.
    read(),从文件指针当前位置读取文件到文件末尾
readline:
    以行为单位, 一次读取文件每一行内容.     
readlines: 一次性读取
    读取文件中的所有内容, 返回一个列表, 列表中的每项元素中的内容都是文件的每一行内容.
"""

26. 以下程序的输出结果是?

"""
5
4
3
2
1
"""

二. 综合题

1. 写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数(3分)

def classified_counting(str1: str):
    """分类计算"""
    dic = {
        'numbers': 0,
        'letters': 0,
        'spaces': 0,
        'other': 0,
    }
    for symbol in str1:
        if symbol.isdigit():
            dic['numbers'] += 1
        elif symbol.isalpha():
            dic['letters'] += 1
        elif symbol.isspace():
            dic['spaces'] += 1
        else:
            dic['other'] += 1
    return dic
# print(classified_counting('hfawhuij njf 1uih8if1 y89u1893iofjknjk3 ui13fu89-'))  # {'numbers': 14, 'letters': 30, 'spaces': 4, 'other': 1}

2. 写函数,检查获取传入列表或元组对象的所有偶数位索引对应的元素,并将其作为新列表返回给调用者。

def check_list(list_tuple):
    return list_tuple[::2]
# print(check_list([1, 2, 3, 4, 5]))  # [1, 3, 5]

3. 写函数有大小写字母的字符串,要求是如果字符串中大写字母的数量小于等于小写字母的数量,则把字符串全部变小写,反之则将字符串全部变为大写

# 示例
# solve('coDe')——>>'code'
# solve('CODe')——>>'CODE'

def solve(str1: str):
    upper_count = 0
    lower_count = 0
    for symbol in str1:
        if not symbol.isalpha():
            continue
        if symbol.islower():
            lower_count += 1
        else:
            upper_count += 1
    if upper_count <= lower_count:
        return str1.lower()
    return str1.upper()

4.将字符串"k:1|k1:2|k2:3|k3:4",处理成 Python 字典:

s = "k:1|k1:2|k2:3|k3:4"
li = []
for item in s.split('|'):
    li.append(item.split(':'))
print(dict(li))

三. ATM

1.方式一

# 思路分析:
"""
1. 分成2个界面: 第一个界面,用户注册 登录的界面. 第二个界面,用户操作执行功能的界面
	第一个界面: 用户不注册后,登录,看不到执行操作功能的界面,就算看到了也没有什么意义.只有登录了用户看到对应属于他的功能的操作.
	第二个界面: 用户需要执行他特定的功能,关键点就是用户登录以后,拿到用户名,作为之后用户操作的基本查找条件.
	总结: 2个功能. 1个功能负责用户登录 注册的认证功能. 另一个功能负责用户登录成功以后执行相应功能操作的功能.
	
2. 用户登录及时找到这个用户, 用户操作更具用户名及时拿到用户对应的数据: 
	把所有用户账户信息加载到内存, 用户登录直接内存中判断. 用户登录以后通过用户名在内存中读取或者修改数据, 不需要每次循环读取打开文件的频繁操作. 
	不过注意的是, 你在内存中修改了数据, 硬盘中的数据没有变化, 如果用户退出不能及时的保存数据. 所以但凡有用户修改数据的地方, 都需要一个特定把内存中的数据, 及时覆盖写回硬盘的操作, 保证了硬盘与内存数据都是最新的数据
	总结: 2个功能. 1个功能负责在程序启动的时候就把所有用户信息读到内存. 另1个功能负责当内存中用户数据修改以后覆盖写回原文件.
	
# 注意: 文件内容str. 内存用户余额 用户错误次数都需要进行数学运算格式int.
3. 文件保存用户的账户信息的格式: 
	用户名:密码:用户错误次数:用户余额
	
4. 内存中用户的账户信息的格式:
	字典 = {用户名: [密码, 用户错误次数, 用户余额]}
	
缺点: 没有使用上装饰器
"""
# -*- encoding: utf-8 -*-
"""
需求: 编写ATM程序实现下述功能,数据来源于文件db.txt
    0、注册功能:用户输入账号名、密码、金额,按照固定的格式存入文件db.txt
    1、登录功能:用户名不存在,要求必须先注册,用户名存在&输错三次锁定,登录成功后记录下登录状态(提示:可以使用全局变量来记录)
下述操作,要求登录后才能操作:
    1、充值功能:用户输入充值钱数,db.txt中该账号钱数完成修改
    2、转账功能:用户A向用户B转账1000元,db.txt中完成用户A账号减钱,用户B账号加钱
    3、提现功能:用户输入提现金额,db.txt中该账号钱数减少
    4、查询余额功能:输入账号查询余额
"""
import os

DB_path = r'db.txt'
login_state = set()
accounts_dic = {}

if os.path.isfile(DB_path):
    with open(DB_path, 'r', encoding='utf-8') as f:
        for line in f:
            res = line.strip()
            if not res:
                continue
            username, password, wrong_number, balance = res.split(":")
            accounts_dic[username] = [password, int(wrong_number), int(balance)]


def update_accounts():
    with open(DB_path, 'w', encoding='utf-8') as f:
        for username in accounts_dic:
            password, wrong_number, balance = accounts_dic.get(username)
            f.write(f'{username}:{password}:{str(wrong_number)}:{str(balance)}\n')


def login():
    print("登录".center(50, '-'))
    if not os.path.isfile(DB_path):
        print('哦吼!你是第一个用户,你先注册去吧!')
        return

    name = input("用户名>>:").strip()
    if name in login_state:
        print(f"欢迎[{name}]再次登录!")
        return name

    if name in accounts_dic:
        user_info = accounts_dic.get(name)
        if user_info[1] == 3:
            print("这个用户之前输入了三次密码.已经被锁定")
            return

        pwd = input("用户密码>>:").strip()
        if pwd == user_info[0]:
            print("恭喜登录成功!")
            login_state.add(name)
            accounts_dic.get(name)[1] = 0
            update_accounts()
            return name
        else:
            print("密码输入错误")
            accounts_dic.get(name)[1] += 1
            update_accounts()
    else:
        print('用户名不存在')


def register():
    print("注册".center(50, '-'))
    name = input("用户名>>:").strip()
    if not name:
        print("用户名不输入不能为空.")
        return
    if name in accounts_dic:
        print('该用户名已经被注册,请重新输入')
        return

    pwd = input("用户密码>>:").strip()
    confirm_pwd = input("确认用户密码>>:").strip()
    if pwd == confirm_pwd:
        if not pwd:
            print("用户密码不能为空")
            return

        accounts_dic[name] = [pwd, 0, 0]
        with open(DB_path, 'a', encoding='utf-8') as f:
            f.write(f'{name}:{pwd}:0:0\n')
        print("恭喜你注册成功".center(50, '-'))
    else:
        print("用户密码2次输入不一致")


def check_balance(username):
    print("查询余额".center(50, '-'))
    print(f"您当前余额[{accounts_dic[username][2]}]元")


def withdraw_deposit(username):
    print("提现".center(50, '-'))
    get_money = input("请拿钱>>:").strip()
    if not get_money.isdigit():
        print("请输入数字")
        return
    get_money = int(get_money)
    balance = accounts_dic[username][2]
    if get_money <= balance:
        accounts_dic[username][2] -= get_money
        update_accounts()
        print(f"恭喜你提现[{get_money}]元成功".center(50, '-'))
    else:
        print("钱不够!快去查询以下余额吧!")


def transfer_accounts(username):
    print("转账".center(50, '-'))
    get_user = input('你想给谁赚钱啊!小伙计>>:').strip()
    if get_user not in accounts_dic:
        print("人都没有这人,转格各毛线啊!")
        return

    get_money = input("你要转多少啊!小伙计>>:").strip()
    if not get_money.isdigit():
        print("请输入数字")
        return
    get_money = int(get_money)
    balance = accounts_dic[username][2]
    if get_money <= balance:
        print(f'恭喜你给[{get_user}]用户转账成功!'.center(50, '-'))
        accounts_dic[username][2] -= get_money
        accounts_dic[get_user][2] += get_money
        update_accounts()
    else:
        print("自己的钱都不够,还转给别人,🖊⑩你!")


def recharge(username):
    print("充值".center(50, '-'))
    add_money = input("你要充多少钱>>:").strip()
    if not add_money.isdigit():
        print("请输入数字")
        return
    add_money = int(add_money)
    accounts_dic[username][2] += add_money
    update_accounts()
    print("恭喜你充值成功".center(50, '-'))


def print_info(function_dic, action, username=None):
    """0模式认证, 1模式执行用户功能"""
    for key, value in function_dic.items():
        print(f'''
                 {key}              {value[0]}
        ''')
    cmd = input("请输入命令编号>>:").strip()
    if not cmd.isdigit():
        print("请输入数字")
        return

    if cmd not in function_dic:
        print("输入命令编号范围不存在.")
        return
    if action:
        return function_dic[cmd][1](username)
    return function_dic[cmd][1]()


auth_dic = {
    '0': ('退出', exit),
    '1': ('登录', login),
    '2': ('注册', register),
}


def auth(discard=None):
    print("认证".center(50, '-'))
    while True:
        username = print_info(auth_dic, 0)
        # print('from auth:', username)
        if username:
            return username


func_dic = {
    '0': ('退出', exit),
    '1': ('返回上一层', auth),
    '2': ('查询余额', check_balance),
    '3': ('转账', transfer_accounts),
    '4': ('提现', withdraw_deposit),
    '5': ('充值', recharge),
}


def run():
    username = auth()
    while True:
        # print('from run:', username)
        res = print_info(func_dic, 1, username)
        if res:
            username = res


if __name__ == '__main__':
    run()

2.方式二: 使用装饰器

"""
1. 装饰器在这里的作用:
	为用户操作时之前进行登录验证判断, 如果用户没有登陆不然用户执行当前的操作功能. 
	需要注意的是: 你要判断用户是否登录, 内存中需使用一种方式保存用户登录以后的状态. 如果在全局用不可变类型保存用户的状态, 你在登录功能的函数中就需要使用global进行声明, 不然在函数中会定义它自己局部的相同变量名的变量, 并不能进行修改操作. 如果你使用的是可变类型的对象, 如果程序不退出保留多个用户登录的状态, 那么装饰器就不能使用了. 
	
2. 只有一个界面: 所有功能都在一个界面, 只有用户登录认证成功以后, 才能执行相应的功能操作.	

缺点: 
	不支持保留多个用户当前登录的状态.
"""
# -*- encoding: utf-8 -*-
"""
编写ATM程序实现下述功能,数据来源于文件db.txt
    0、注册功能:用户输入账号名、密码、金额,按照固定的格式存入文件db.txt
    1、登录功能:用户名不存在,要求必须先注册,用户名存在&输错三次锁定,登录成功后记录下登录状态(提示:可以使用全局变量来记录)
下述操作,要求登录后才能操作:
    1、充值功能:用户输入充值钱数,db.txt中该账号钱数完成修改
    2、转账功能:用户A向用户B转账1000元,db.txt中完成用户A账号减钱,用户B账号加钱
    3、提现功能:用户输入提现金额,db.txt中该账号钱数减少
    4、查询余额功能:输入账号查询余额

定义用户账户文件为当前目录下的db.txt中,文件中存放格式如下:
    用户名:密码:用户错误次数:用户余额
"""
import os

DB_path = r'db.txt'
current_user = None
accounts_dic = {}

if os.path.isfile(DB_path):
    with open(DB_path, 'r', encoding='utf-8') as f:
        for line in f:
            res = line.strip()
            if not res:
                continue
            username, password, wrong_number, balance = res.split(":")
            accounts_dic[username] = [password, int(wrong_number), int(balance)]


def auth(func):
    def wrapper(*args, **kwargs):
        if not current_user:
            print("您还没有登录, 请先登录")
        else:
            return func(*args, **kwargs)

    return wrapper


def update_accounts():
    with open(DB_path, 'w', encoding='utf-8') as f:
        for username in accounts_dic:
            password, wrong_number, balance = accounts_dic.get(username)
            f.write(f'{username}:{password}:{str(wrong_number)}:{str(balance)}\n')


def login():
    print("登录".center(50, '-'))
    if not os.path.isfile(DB_path):
        print('哦吼!你是第一个用户,你先注册去吧!')
        return

    name = input("用户名>>:").strip()
    if name == current_user:
        print(f"欢迎[{name}]再次登录!")
        return name

    if name in accounts_dic:
        user_info = accounts_dic.get(name)
        if user_info[1] == 3:
            print("这个用户之前输入了三次密码.已经被锁定")
            return

        pwd = input("用户密码>>:").strip()
        if pwd == user_info[0]:
            print("恭喜登录成功!")
            # 修改全局的不可变类型: 定义global
            global current_user
            current_user = name
            accounts_dic.get(name)[1] = 0
            update_accounts()
            return name
        else:
            print("密码输入错误")
            accounts_dic.get(name)[1] += 1
            update_accounts()
    else:
        print('用户名不存在')


def register(*args):
    print("注册".center(50, '-'))
    name = input("用户名>>:").strip()
    if not name:
        print("用户名不输入不能为空.")
        return
    if name in accounts_dic:
        print('该用户名已经被注册,请重新输入')
        return

    pwd = input("用户密码>>:").strip()
    confirm_pwd = input("确认用户密码>>:").strip()
    if pwd == confirm_pwd:
        if not pwd:
            print("用户密码不能为空")
            return

        accounts_dic[name] = [pwd, 0, 0]
        with open(DB_path, 'a', encoding='utf-8') as f:
            f.write(f'{name}:{pwd}:0:0\n')
        print("恭喜你注册成功".center(50, '-'))
    else:
        print("用户密码2次输入不一致")


@auth  # check_balance = auth(check_balance)
def check_balance():
    print("查询余额".center(50, '-'))
    print(f"您当前余额[{accounts_dic[current_user][2]}]元")


@auth
def withdraw_deposit():
    print("提现".center(50, '-'))
    get_money = input("请拿钱>>:").strip()
    if not get_money.isdigit():
        print("请输入数字")
        return
    get_money = int(get_money)
    balance = accounts_dic[current_user][2]
    if get_money <= balance:
        accounts_dic[current_user][2] -= get_money
        update_accounts()
        print(f"恭喜你提现[{get_money}]元成功".center(50, '-'))
    else:
        print("钱不够!快去查询以下余额吧!")


@auth
def transfer_accounts():
    print("转账".center(50, '-'))
    get_user = input('你想给谁赚钱啊!小伙计>>:').strip()
    if get_user not in accounts_dic:
        print("人都没有这人,转格各毛线啊!")
        return

    get_money = input("你要转多少啊!小伙计>>:").strip()
    if not get_money.isdigit():
        print("请输入数字")
        return
    get_money = int(get_money)
    balance = accounts_dic[current_user][2]
    if get_money <= balance:
        print(f'恭喜你给[{get_user}]用户转账成功!'.center(50, '-'))
        accounts_dic[current_user][2] -= get_money
        accounts_dic[get_user][2] += get_money
        update_accounts()
    else:
        print("自己的钱都不够,还转给别人,🖊⑩你!")


@auth
def recharge():
    print("充值".center(50, '-'))
    add_money = input("你要充多少钱>>:").strip()
    if not add_money.isdigit():
        print("请输入数字")
        return
    add_money = int(add_money)
    accounts_dic[current_user][2] += add_money
    update_accounts()
    print("恭喜你充值成功".center(50, '-'))


func_dic = {
    '0': ('退出', exit),
    '1': ('登录', login),
    '2': ('注册', register),
    '3': ('查询余额', check_balance),
    '4': ('转账', transfer_accounts),
    '5': ('提现', withdraw_deposit),
    '6': ('充值', recharge),
}


def run():
    while True:
        if current_user:
            print(f'当前操作用户: {current_user}'.center(50, '#') )
        for key, value in func_dic.items():
            print(f'({key}){value[0]}   ',  end='')
        print()
        cmd = input("请输入命令编号>>:").strip()
        if not cmd.isdigit():
            print("请输入数字")
            continue

        if cmd not in func_dic:
            print("输入命令编号范围不存在.")
            continue
        func_dic[cmd][1]()


if __name__ == '__main__':
    run()
posted @ 2020-03-21 12:47  给你加马桶唱疏通  阅读(250)  评论(0编辑  收藏  举报