Python语言系列-03-文件操作和函数





## 深浅拷贝
#!/usr/bin/env python3
# author:Alnk(李成果)

# 赋值运算
# 可变的数据类型:由于数据类型可变,修改数据会在原来的数据的基础上进行修改,
# 可变的数据类型有:列表,字典
l1 = [1, 2, 3]
l2 = l1
l3 = l2
# l1 = [1, 2, 3, 4]  # 注意这不是修改数据,而是在内存中重新创建了一份数据,然后L1 指向了这份新数据
l1.append(666)  # 在原来的数据上修改
print(l1, l2, l3)  # [1, 2, 3, 666] [1, 2, 3, 666] [1, 2, 3, 666]
print(id(l1), id(l2), id(l3))  # 140349669255176 140349669255176 140349669255176
print("--" * 30)


# 不可变的数据类型:由于数据类型是不可变的,不可修改,会在内存中在重新创建一份新的数据
# 不可变的数据类型有:字符串,数字,bool值,元组等
l4 = 'abcd'
l5 = l4
l4 = [1, 2, 3]
print(l4, l5)  # [1, 2, 3] abcd
print(id(l4), id(l5))  # 140230928510856 140230926894952
print("--" * 30)


# 浅copy
# copy一个新列表(dict),列表在内存中是新的,但是列表里面的元素,完全沿用之前的元素。
l5 = [1, 2, 3, [22, 33]]
l6 = l5.copy()
print(id(l5), id(l6))  # 140589566668360 140589566718024
l5.append(666)
l5.remove(1)
print(l5, l6)  # [2, 3, [22, 33], 666] [1, 2, 3, [22, 33]]
print("--" * 30)

# 列表在内存中是新的,但是列表里面的元素,完全沿用之前的元素
l5 = [1, 2, 3, [22, 33]]
l6 = l5.copy()
print(id(l5[0]))  # 4459755568
print(id(l6[0]))  # 4459755568
l5[-1].append(666)
print(l5, l6)  # [2, 3, [22, 33, 666], 666] [1, 2, 3, [22, 33, 666]]
print("--" * 30)


# 深copy
# 总结 深copy则会在内存中开辟新空间,将原列表以及列表里面的可变的数据类型重新创建一份,
# 不可变的数据类型则沿用之前的,指向之前的数据
import copy
l7 = [1, 2, 3, [22, 33]]
l8 = copy.deepcopy(l7)
print(id(l7), id(l8))  # 140686186753032 140686186752968
l7[-1].append(666)
l7.remove(1)  # 只是删除了l1列表中和内存中的数据1的指向关系,并不是在内存中删除了数据1
print(l7, l8)  # [2, 3, [22, 33, 666]] [1, 2, 3, [22, 33]]
print("--" * 30)


# id 对象的内存地址
# == 比较两边的数值是否相等
# is 判断的两边对象的内存地址是否是同一个
print(2 == 2)
print("--" * 30)


# 切片是浅copy ******
l1 = [1, 2, 3, [22, 33]]
l2 = l1[:]  # 切片是浅copy
l1[-1].append(666)
print(id(l1), id(l2)) # 40282048785864 140282048785608
print(l1, l2)  # [1, 2, 3, [22, 33, 666]] [1, 2, 3, [22, 33, 666]]



文件操作

文件操作介绍

#!/usr/bin/env python3
# author:Alnk(李成果)

"""
文件三参数
    path:文件的路径
    encoding:文件以什么编码方式存储,就以什么编码方式读取
    mode:读,写,读写,写读,追加,改等等

    三个大方向:
        带b的模式操作对象都是非文字类的文件:视频,音频,图片。

        读(r rb r+ rb+)
            r   读模式
            rb
            r+  读写模式
            rb+

        写 w wb w+ w+b :如果原文件存在,则清空原文件,在写入。这个慎用
            w   写模式
            wb
            w+  写读模式
            wb+

        追加(a ab a+ a+b)
            a   追加
            ab
            a+
            ab+

    文件操作的其他方法:
        f.read()
        f.write()
        f.readline()
        f.readlines()
        f.close()
        f.seek()
        f.tell()
"""


f1 = open("test.txt",encoding='utf-8',mode='r')
content = f1.read()
print(content)
f1.close()
"""
f1变量,文件句柄。
open 内置函数,底层调用的操作系统的操作文件功能的接口。
windows: gbk,linux:utf-8  ios: utf-8
操作文件总共3步;
    1,打开文件,产生文件句柄。
    2,对文件句柄进行操作。
    3,关闭文件句柄。
"""


"""
# 错误示范:
# 1,UnicodeDecodeError: 'gbk' codec can't decode...   编解码错误。
# 2,路径错误。路径分隔符 与后面的字符产生特殊的意义。 解决方式 r 或者 \
    #f1 = open(r"d:\test\r文件读写test.txt",encoding='utf-8',mode='r')
"""


文件操作-读模式

#!/usr/bin/env python3
# author:Alnk(李成果)

# 读模式(r rb r+ rb+)

# r模式
# 默认就是r模式
# 1.1 read()    # 全部读取文件内容,如果文件过大,可能会导致内存不足
f1 = open('test.txt', encoding='utf-8', mode='r')
content = f1.read()
print(content, type(content))  # <class 'str'> 对文件进行读取出来的都是字符串类型
print("=" * 30)

# 1.2 read(n)
# r模式下,  n代表字符。
f1 = open('test.txt', encoding='utf-8', mode='r')
content = f1.read(3)
print(content)
print("=" * 30)

# 1.3 readline() 按行读取
f1 = open('test.txt', encoding='utf-8', mode='r')
print(f1.readline().strip())
print(f1.readline().strip())
print(f1.readline().strip())
f1.close()
print("=" * 30)

# 1.4 readlines()  返回一个列表,列表里面的元素是原文件每一行
f1 = open('test.txt', encoding='utf-8', mode='r')
content = f1.readlines()
print(content)
f1.close()
print("=" * 30)

# 1.5 for循环  *****注意平常读取大文件就需要用这种方法
f1 = open('test.txt', encoding='utf-8', mode='r')
for line in f1:
    print(line.strip())
f1.close()
print("=" * 30)


# rb模式 读取一些非文字类的文件,如图片,视频等
# 5种读的模式, read()  read(n)  readline()  readlines()  for循环读取
# 如果是 rb 模式,就不需要规定编码了 encoding不是编码或解码,它是规定你这个文件到底采用哪种编码模式而已
f1 = open('test.txt', mode='rb')
content = f1.read()
print(content)
print(content.decode('utf-8'))  # 解码 utf-8 ---> unicode
f1.close()
print("---rb---")
print("=" * 30)

# rb 模式读取图片
f1 = open('time1.jpg', mode='rb')
content = f1.read()
print(content)
f1.close()
print("=" * 30)


# r+ 读写模式
f = open('log1', encoding='utf-8', mode='r+')
print(f.read())
f.write('666\n')
f.close()
print("=" * 30)

# 先写后读会出问题 会覆盖
f = open('log1', encoding='utf-8', mode='r+')
f.write('松岛岛')
print(f.read())
f.close()
print("=" * 30)


# rb+ 模式


文件操作-写模式

#!/usr/bin/env python3
# author:Alnk(李成果)

# w 写模式
# 没有文件,创建文件写入内容
# 有文件,先清空内容后写入
f = open('log1', encoding='utf-8', mode='w')
f.write('123456')
f.write('深圳 ~~~')
f.write('深圳 ~~~')
f.write('深圳 ~~~')
f.write('深圳 ~~~')
f.write('深圳 ~~~')
f.close()

# wb 写模式(以bytes类型写入到文件)
# 把bytes类型写入到文件 --图片
f1 = open('time1.jpg', mode='rb')
content = f1.read()
f1.close()
f2 = open('time2.jpg', mode='wb')
f2.write(content)
f2.close()

# w+ 写读模式
f = open('log1', encoding='utf-8', mode='w+')
f.write('老男孩教育...')
f.seek(0)   # 调整光标(指针)到最开始
print(f.read())
f.close()

# wb+ 写读模式(bytes)


文件操作-追加模式

#!/usr/bin/env python3
# author:Alnk(李成果)

# a 追加
# 没有文件创建文件追加内容,有文件,在文件最后追加内容。
f = open('log3', encoding='utf-8', mode='a')
f.write('老男孩')
f.close()

# 有文件,在文件最后追加内容。
f = open('log1', encoding='utf-8', mode='a')
f.write('666')
f.close()


文件操作-修改

#!/usr/bin/env python3
# author:Alnk(李成果)

# 文件的修改:所有的文件编辑器都要经过下面这5步才能对文件进行修改
#     1,以读的模式打开原文件
#     2,以写的模式打开新文件
#     3,读取原文件对源文件内容进行修改形成新内容写入新文件
#     4,将原文件删除
#     5,将新文件重命名成原文件


# # 方法一 小文件可以
# # 1,以读的模式打开原文件
# # 2,以写的模式打开新文件
# import os
# with open('tom个人简历', encoding='utf-8') as f1, open('tom个人简历.bak', encoding='utf-8', mode='w') as f2:
#     # 3,读取原文件对源文件内容进行修改形成新内容写入新文件
#     old_content = f1.read()
#     new_content = old_content.replace('tom', 'SB')
#     f2.write(new_content)
# # 4,将原文件删除。
# os.remove('tom个人简历')
# # 5,将新文件重命名成原文件。
# os.rename('tom个人简历.bak', 'tom个人简历')


# 方法二: 推荐使用这种方法
# 1,以读的模式打开原文件。
# 2,以写的模式打开新文件。
import os
with open('tom个人简历', encoding='utf-8') as f1, open('tom个人简历.bak', encoding='utf-8', mode='w') as f2:
    # 3,读取原文件对源文件内容进行修改形成新内容写入新文件。
    for old_line in f1:
        new_line = old_line.replace('SB', 'tom')
        f2.write(new_line)

# 4,将原文件删除。
os.remove('tom个人简历')
# 5,将新文件重命名成原文件。
os.rename('tom个人简历.bak', 'tom个人简历')


文件操作-其他常用方法

#!/usr/bin/env python3
# author:Alnk(李成果)

# 其他操作方法:
# readable() writable()  ***      文件句柄是否可读,可写
# seek 调整光标位置 按照字节   ***
# seek(0)  将光标移动到开始
# seek(0,2)  将光标移动到最后。
# tell 获取光标位置 按照字节。  ***
# flush 刷新 保存  ***
# truncate 截取原文件,从头开始截,
f = open('log3', encoding='utf-8')
f.seek(1)
print(f.read())
print(f.tell())
f.seek(0)  # 将光标移动到开始
print(f.read())
f.seek(0, 2)  # 将光标移动到最后
print(f.read())
f.close()
print("---" * 30)

# writable() 是否可写
f = open('log3', encoding='utf-8')
print(f.read())
print(f.writable())  # False 是否可写
if f.writable():
    f.write('111')
f.close()
print("---" * 30)

# flush()
f = open('log3', encoding='utf-8', mode='w')
f.write('fjdsklafjdfjksaadfadf')
f.flush()
f.close()


# 截取原文件,从头开始截,需要在可写的模式下,并且不清空原文件
f = open('log3', encoding='utf-8', mode='r+')
f.truncate(3)
f.close()



函数

函数的初识

#!/usr/bin/env python3
# author:Alnk(李成果)

"""
# 面向过程编程
s1 = 'hello jerry'
count = 0
for i in s1:
    count += 1
print(count)

l1 = [1, 2, 3, 4, 5]
count = 0
for i in l1:
    count += 1
print(count)

# 缺点:
# 1,代码重复太多。
# 2,代码的可读性差。
"""


# 函数的初识
def my_lf_len(s):
    sun = 0
    for _ in s:
        sun += 1
    print(sun)


s1 = 'hello word'
my_lf_len(s1)
l1 = [1, 2, 3, 3, 5, 56, 6, 6]
my_lf_len(l1)


# 1,函数是什么?
# 功能体,一个函数封装的一个功能
# 结构:
'''
def 函数名():
    函数体
'''


# 2,函数什么时候执行
# 被调用的时候执行 函数名+()
def my_lf_len(s):
    sum = 0
    for _ in s:
        sum += 1
    print(sum)


my_lf_len('how are you?')


# 3,函数的返回值 return
def tantan():
    print('搜索')
    print('左滑动一下')
    print('右滑动一下')
    # return
    print('发现美女,打招呼')
    # return '美女一枚'
    # return ['恐龙一堆']
    # return '小萝莉', '肯德基', '御姐'
    return {'name': 'alnk', 'age': 18}, [1, 2, 3, 4, 5]    # 这算多个值


ret = tantan()
print(ret, type(ret))
# 调用一次执行一次
tantan()
tantan()
tantan()

# 返回值
'''
return: 
    1,终止函数
    2,给函数的调用者(执行者)返回值
        return             --->  None 
        return   单个值    --->  单个值   --被返回的数据是什么数据类型就是什么类型
        return   多个值    ---> (多个值,) --元组
'''


函数的参数

#!/usr/bin/env python3
# author:Alnk(李成果)


# 实参和形参
def Tantan(sex):  # 函数的定义:sex形式参数,形参
    print('搜索')
    print('左滑动一下')
    print('右滑动一下')
    print('发现美女,打招呼')
    return '小萝莉', '肯德基', '御姐'

# 函数的参数
Tantan('女')  # 函数的执行:'女' 实际的数据, 实参


# 从两方面讲函数的参数:实参 和 形参
# 一 实参角度
# 1.位置参数 从左至右,一一对应
def Tantan(sex, age):
    print('筛选性别%s,年龄%s左右' % (sex, age))
    print('搜索')
    print('左滑动一下')
    print('右滑动一下')
    print('发现美女,打招呼')

Tantan('女', 28)
print("----" * 30)


# 练习:比大小,返回大的数字
def max_(a, b):
    # if a > b:
    #     return a
    # else:
    #     return b
    # return a if a > b else b
    return a if a > b else b

print(max_(100, 200))
print("----" * 30)

# 扩展:三元运算符
a = '饼'
b = '西瓜'
ret = a if 3 > 2 else b
print(ret)
print("----" * 30)


# 2.关键字参数 一一对应。
# 函数参数较多 记形参顺序较麻烦时,需要关键字参数
def Tantan(sex,age,area):
    print('筛选性别%s, %s附近,年龄%s左右的美女' %(sex,area,age))
    print('搜索')
    print('左滑动一下')
    print('右滑动一下')
    print('发现美女,打招呼')

Tantan(sex='女',area='南山区',age='28')
print("----" * 30)


# 3.混合参数  一一对应,关键字参数必须要在位置参数后面。
def Tantan(sex,age,area):
    print('筛选性别%s,%s 附近,年龄%s左右的美女' %(sex,area,age))
    print('搜索')
    print('左滑动一下')
    print('右滑动一下')
    print('发现美女,打招呼')

Tantan('女',28,area='南山区')
print("----" * 30)


# 二 形参角度
# 1.位置参数 从左至右,一一对应。
def Tantan(sex,age):
    print('筛选性别%s,年龄%s左右' %(sex,age))
    print('搜索')
    print('左滑动一下')
    print('右滑动一下')
    print('发现美女,打招呼')

Tantan('女', 28)
print("----" * 30)


# 2.默认参数  : 使用最多的一般不更改的参数,默认参数一定放在位置参数后面
def Tantan(area,age,sex='girl'):
    print('筛选性别%s, %s 附近,年龄%s左右的美女' %(sex,area,age))
    print('搜索')
    print('左滑动一下')
    print('右滑动一下')
    print('发现美女,打招呼')

Tantan('南山区',28,'laddboy')
print("----" * 30)


# 3.万能参数(动态参数) *args, **kwargs
def Tantan(*args, **kwargs):
    # 函数的定义: * 代表聚合。
    # * 将实参角度所有的位置参数放到一个元祖中,并将元组给了args
    # ** 将实参角度所有的关键字参数放到一个字典中,并将字典给了kwargs
    print(args)
    print(kwargs)
    # print('筛选地域:%s,年龄%s' % args)
    # print('搜索')
    # print('左滑动一下')
    # print('右滑动一下')
    # print('发现美女,打招呼')
    # print(kwargs)

# Tantan('南山区','28', '性格好','身材好', '家境好')
Tantan('南山区', '28', body='身材好', voice='萝莉音', money='白富美')
print("----" * 30)


def Tantan(*args,**kwargs):
    # 函数的定义: * 代表聚合。
    # *  将实参角度所有的位置参数放到一个元祖中,并将元组给了args
    # ** 将实参角度所有的关键字参数放到一个字典中,并将字典给了kwargs
    print(args)
    print(kwargs)

Tantan('南山区','28',body='身材好',voice='萝莉音',money='白富美')
print("---- 1 -----------------------------------------")

l1 = [1, 2, 3]
l2 = (4, 5, 6)
Tantan(*l1, *l2)  # 函数的执行:*iterable 将l1打散,添加到args
print("---- 2 -----------------------------------------")

Tantan(1, 2, 3, 4, 5, 6)
print("---- 3 -----------------------------------------")

dic1 = {'name': "tom"}
dic2 = {'age': 46}
Tantan(**dic1, **dic2)  # **dic1 将dic1打散,将所有的键值对添加到kwargs
print("---- 4 -----------------------------------------")


# 函数参数
    # 实参
        # 位置参数
        # 关键字参数
        # 混合参数

    # 形参
        # 位置参数
        # 默认参数
        # 万能参数

# 形参的最终顺序
# 位置参数  *args  默认参数  **kwargs
def func(a, b, *args, sex='女', **kwargs):
    print(a, b, sex, args, kwargs)

func(1, 2, 4, 5, 6, name='tom', age=73)


函数的名称空间和顺序

#!/usr/bin/env python3
# author:Alnk(李成果)

"""
函数里面的变量,在函数外面能直接引用么?
def func1():
    m = 1
    print(m)
print(m)  #这行报的错

报错了:
NameError: name 'm' is not defined

我们首先回忆一下Python代码运行的时候遇到函数是怎么做的,从Python解释器开始执行之后,就在内存中开辟里一个空间
每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读入内存,
表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。等执行到函数调用的时候,
Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,
而函数中的变量会储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

我们给这个‘存放名字与值的关系’的空间起了一个名字 --- 命名空间。
代码在运行伊始,创建存储“变量名与值的关系”的空间叫做全局命名空间;
在函数的运行中开辟的临时的空间叫做局部命名空间。
"""
# python的空间分三种:
# 全局名称空间
# 局部名称空间
# 内置名称空间  print() len() 内置函数
#
# 举例
# def func():
#     name = 'tom'
# func()
# print(name)  # 报错
# func()
# python中的作用域分两种:
# 全局作用域:内置名称空间 全局名称空间
# 局部作用域:局部名称空间


# 取值顺序: 就近原则
# 局部变量先到局部寻找,局部没找到才去全局找,全局没找到,去内置找,都没找到,就报错
# 全局变量直接在全局查找,全局没有就去内置空间查找,如果没有,就报错
# 局部名称空间 ———> 全局名称空间 ———> 内置名称空间    (这个顺序不可逆)
input = 'tom'
def func():
    input = 'jerry'
    print(input)
func()
print(input)


# 加载顺序
# 所有的东西要加载到内存才运行
# 内置名称空间  --->  全局名称空间 --->  局部名称空间


函数的嵌套

#!/usr/bin/env python3
# author:Alnk(李成果)

# 函数的嵌套
# 举例1
def func():
    print(111)

def func1():
    print(222)
    func()

def func3():
    print(333)
    func1()

print(444)
func()
print(555)
## 444 111 555
print("---------------- 1 -------------------------")


#举例2
def func():
    print(111)

def func1():
    print(222)
    func()

def func3():
    print(333)
    func1()

print(444)
func3()
print(555)
# 444 333 222 111 555
print("---------------- 2 -------------------------")


def wrapper():
    print(222)
    def inner():
        print(111)
    print(444)
    inner()
    print(333)

wrapper()
# 222 444 111 333


内置函数globals、locals

#!/usr/bin/env python3
# author:Alnk(李成果)

# 内置函数globals() locals()

name = 'tom'
age = 46


def func():
    sex = '男'
    hobby = '女'
    print(globals())  # 返回一个字典:全局作用域的所有内容
    # {..., 'name': 'tom', 'age': 46, ...} 两边还有其他的内容

    print(locals())   # 返回一个字典:当前位置的内容
    # {'hobby': '女', 'sex': '男'}

func()

print(globals())  # 返回一个字典:全局作用域的所有内容
# {..., 'name': 'tom', 'age': 46, ...} 两边还有其他的内容

print(locals())   # 返回一个字典:当前位置的内容
# {..., 'name': 'tom', 'age': 46, ...} 两边还有其他的内容


函数名的应用

#!/usr/bin/env python3
# author:Alnk(李成果)

# 函数名的应用
# 1,函数名是一个特殊的变量 函数名() 执行此函数
def func():
    print(666)
func()
print("--------------- 1 ------------------")

# 2,函数名可以当做变量进行赋值运算。
def func():
    print(666)
f = func
f()
print("--------------- 2 ------------------")

# 3,函数名可以作为容器型数据的元素 ***
def func():
    print(666)

def func1():
    print(777)

def func2():
    print(888)

def func3():
    print(999)

l1 = [func, func1, func2, func3]
for i in l1:
    i()

dic = {
    1: func,
    2: func1,
    3: func2,
    4: func3,
}

# while 1:
#     num = input('请输入序号:').strip()
#     num = int(num)
#     dic[num]()
print("--------------- 3 ------------------")


# 4,函数名可以作为函数的参数。
def func1():
    print(111)

def func2(x):
    x()
    print(222)

func2(func1)
print("--------------- 4 ------------------")

# 5,函数名可以作为函数的返回值。
def func1():
    print(111)

def func2(x):
    print(222)
    return x

ret = func2(func1)
ret()


关键字global、nonlocal

#!/usr/bin/env python3
# author:Alnk(李成果)

# global nonlocal

# global
# 1,声明一个全局变量。
def func():
    global name
    name = 'tom'
func()
print(name)
print("--------------- 1 ------------------")

# 2,修改一个全局变量。
# 原因:局部作用域只能引用全局变量而不能改变全局变量。如果改变则报错
# global 可以实现通过局部作用域而去改变全局变量
count = 1
def func1():
    global count
    count += 1
print(count)
func1()
print(count)
print("--------------- 2 ------------------")


# nonlocal: 子级函数可以通过nonlocal修改父级(更高级非全局变量)函数的变量。
# 现象:子级函数可以引用父级函数的变量但是不能修改。
def func():
    count = 1
    def func1():
        def inner():
            nonlocal count
            count += 1
            print(count)  # 第二个打印 2
        print(count)      # 第一个打印 1
        inner()
        print(count)      # 第三个打印 2
    func1()

func()  # 1 2 2
print("--------------- 3 ------------------")


# 这个不行,会报错
# count = 1
# def func1():
#     def inner():
#         nonlocal count  # 这里会报错,因为count是全局变量了,不能使用nonlocal
#         count += 1
#         print(count)
#     inner()
#
# func1()




练习题1

#!/usr/bin/env python3
# author:Alnk(李成果)

"""
# 1、 文件a1.txt内容
# 序号 部门 人数 平均年龄 备注
# 1 python 30 26 单身狗
# 2 Linux 26 30 没对象
# 3 运营部 20 24 女生多
# 通过代码,将其构建成这种数据类型:
# [{'序号':'1','部门':Python,'人数':30,'平均年龄':26,'备注':'单身狗'},......]
"""
# 方法1
l1 = []
with open('a1.txt', encoding='utf-8', mode='r') as f:
    k1, k2, k3, k4, k5 = f.readline().strip('').split()
    for line in f:
        dic = {}
        v1, v2, v3, v4, v5 = line.strip('').split()
        dic[k1] = v1
        dic[k2] = v2
        dic[k3] = v3
        dic[k4] = v4
        dic[k5] = v5
        l1.append(dic)
print(l1)
print("----------------------- 1 --------------------------------")

# 方法2
l1 = []
with open('a1.txt', encoding='utf-8', mode='r') as f:
    # 读取第一行作为键
    head_list = f.readline().strip('').split()
    # print(head_list)
    for line in f:
        # 获取每一行为一个列表
        line_list = line.strip().split()
        # print(line_list)
        dic = {}
        # 循环上面的列表 enumerate函数的用法 会返回索引k和值v
        for k, v in enumerate(line_list):
            # print(k, v)
            dic[head_list[k]] = v
        l1.append(dic)
print(l1)
print("----------------------- 2 --------------------------------")


# 2、 传入函数的字符串中,统计[数字]、[字母]、[空格] 以及 [其他]的个数,并返回结果。
def my_count(str1):
    """
    统计数字,字母,空格,其他的字符个数
    :param str1: 字符串
    :return: 数字,字母,空格,其他
    """
    count_num = 0
    count_letter = 0
    count_space = 0
    count_other = 0
    for i in str1:
        if i.isdigit():
            count_num += 1
        elif i.isalpha():
            count_letter += 1
        elif i == ' ':
            count_space += 1
        else:
            count_other += 1
    return '数字[%s] 字母[%s] 空格[%s] 其他[%s]' % (count_num, count_letter, count_space, count_other)

print(my_count('1 b # 3s'))
print("----------------------- 3 --------------------------------")


# 3、 写函数,接收两个数字参数,返回比较大的那个数字
def my_compare(*args):
    """
    比较两个数大小
    :param args:传入2个数字
    :return: 大的数字
    """
    return args[0] if args[0] > args [1] else args[1]

print(my_compare(3,62))
print("----------------------- 4 --------------------------------")


# 4、 写函数,检查传入字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者
# dic = {"k1": "v1v1", "k2": [11,22,33,44]}   PS:字典中的value只能是字符串或列表
def func(**kwargs):
    """
    检查字典值的长度,大于2,保留前两个长度的内容
    :param kwargs: 字典
    :return: 新列表
    """
    for k,v in kwargs.items():
        kwargs[k] = v[:2] if len(v) > 2 else v
    return kwargs
dic = {"k1": "v1v1", "k2": [11,22,33,44]}
ret = func(**dic)
print(ret)
print("----------------------- 5 --------------------------------")


# 5、写函数,此函数只接收一个参数且此参数必须是列表数据类型,
# 此函数完成的功能是返回给调用者一个字典,此字典的键值对为此列表的索引及对应的元素。例如传入的列表为:[11,22,33]
# 返回的字典为{0:11,1:22,2:33}
def fun(lis):
    """
    接受列表数据类型,返回字典
    :param args: 列表
    :return: 字典
    """
    if type(lis) is list:
        dic = {}
        for k in range(len(lis)):
            dic[k] = lis[k]
        return dic
    else:
        return '参数必须为列表'

l1 = [11,22,33,]
print(fun(l1))
print("----------------------- 6 --------------------------------")


# 6、写函数,函数接收四个参数分别是:姓名,性别,年龄,学历。用户通过输入这四个内容,然后将这
# 四个内容传入到函数中,此函数接收到这四个内容,将内容追加到一个student_msg文件中
def func(name,sex,age,edu):
    """
    接收四个参数,将接收的内容追加到student_msg文件中
    :param name: 姓名
    :param sex: 性别
    :param age: 年龄
    :param edu: 学历
    :return:
    """
    with open('student_msg', encoding='utf-8', mode='a+') as f:
        f.write('%s %s %s %s \n' % (name, sex, age, edu) )
        f.flush()
# name = input('name>>>:')
# sex = input('sex>>>:')
# age = input('age>>>:')
# edu = input('edu>>>:')
# func(name,sex,age,edu)
print("----------------------- 7 --------------------------------")


# 7、 对第6题升级:支持用户持续输入,Q或者q退出,性别默认为男,如果遇到女学生,则把性别输入女
def func(name,age,edu,sex='男'):
    """
    接收四个参数,将接收的内容追加到student_msg文件中
    :param name: 姓名
    :param sex: 性别
    :param age: 年龄
    :param edu: 学历
    :return:
    """
    with open('student_msg', encoding='utf-8', mode='a+') as f:
        f.write('%s %s %s %s \n' % (name, sex, age, edu) )
        f.flush()

# while 1:
#     name = input('name(Q/q exit)>>>:')
#     if name.strip().lower() == 'q':
#         break
#     sex = input('sex>>>:')
#     age = input('age>>>:')
#     edu = input('edu>>>:')
#
#     if sex.strip() == '男':
#         func(name,age,edu)
#     else:
#         func(name,age,edu,sex)
print("----------------------- 8 --------------------------------")


# 8、写函数,用户传入修改的文件名,与要修改的内容,执行函数,完成整个文件的批量修改操作
import os
def modify_file(file_name,old_modify,new_modify):
    """
    文本修改
    :param file_name: 文件
    :param old_modify: 被修改的内容
    :param new_modify: 修改的内容
    :return: True
    """
    if os.path.exists(file_name):
        with open(file_name, encoding='utf-8', mode='r') as f1, open(file_name+'.bak', encoding='utf-8',mode='w') as f2:
            for old_line in f1:
                new_line = old_line.replace(old_modify,new_modify)
                f2.write(new_line)
                f2.flush()
        os.remove(file_name)
        os.rename(file_name+'.bak',file_name)
        return  True
    else:
        return '文件不存在'

# file_name = input("请输入文件名称:")
# old_modify = input("请输入需要修改的内容:")
# new_modify = input("请输入修改后的内容:")
# ret = modify_file(file_name,old_modify,new_modify)
# print(ret)
print("----------------------- 9 --------------------------------")


# 9、读代码,回答:代码中,打印出来的值a,b,c分别是什么?为什么?
a = 10
b = 20
def test5(a, b):  # a=20 b=10
    a=3
    b=5
    print(a, b)      #a=3 b=5

c = test5(b, a)  # a=3 b=5 因为在函数内部打印的,先从局部变量开始找
print(c)  #none 函数没有return,所以没有返回值C=None。
print("----------------------- 10 --------------------------------")


# 10、写函数,传入函数中多个实参(均为可迭代对象如字符串,列表,元祖,集合等),将每个实参的每个元素依次
# 添加到函数的动态参数args里面
# 例如 传入函数两个参数[1,2,3] (22,33)最终args为(1,2,3,22,33)
def func(*args):
    """
    :param args:
    :return:
    """
    print(args)

l1 = [1, 2, 3]
t1 = (22, 33)
func(*l1, *t1)
print("----------------------- 11 --------------------------------")


# 11、写函数,传入函数中多个实参(实参均为字典),将每个实参的键值对依次添加到函数的动态参数kwargs里面
# 例如 传入函数两个参数{‘name’:’alex’} {‘age’:1000}最终kwargs为{‘name’:’alex’ ,‘age’:1000}
def fun(**kwargs):
    """
    :param kwargs:
    :return:
    """
    print(kwargs)
dic1 = {'name': 'alex'}
dic2 = {'age': 1000}
fun(**dic1, **dic2)
print("----------------------- 12 --------------------------------")


# 12、下面代码成立么?如果不成立为什么报错?怎么解决?
# 题目一:
a = 2
def wrapper():
    print(a)
wrapper()  # 2

# 题目二:
# a = 2
# def wrapper():
#     a += 1  # 报错
#     print(a)
# wrapper()

# 题目三:
def wrapper():
    a = 1
    def inner():
        print(a)
    inner()
wrapper()  # 1

# 题目四:
# def wrapper():
#     a = 1
#     def inner():
#         a += 1  # 报错
#         print(a)
#     inner()
# wrapper()

# 题目二修改为如下
a = 2
def wrapper():
    global a
    a += 1
    print(a)
wrapper()

# 题目四修改为如下
def wrapper():
    a = 1
    def inner():
        nonlocal a
        a += 1
        print(a)
    inner()
wrapper()
print("----------------------- 13 --------------------------------")


# 13、写函数,接收两个数字参数,将较小的数字返回
def min_(a,b):
    return a if a < b else b
print(min_(13,2))
print("----------------------- 14 --------------------------------")


# 14、写函数,接收一个参数(此参数类型必须是可迭代对象),将可迭代对象的每个元素以’_’相连接,形成新的字符串,并返回
# 例如 传入的可迭代对象为[1,'老男孩','武sir']返回的结果为’1_老男孩_武sir’
def fun(item):
    """
    :param item:
    :return:
    """
    s = ''
    for i in item:
        s = s + '%s_' % (i)
    s = s.rstrip('_')
    return s
l1 = [1, '深圳', '南山']
ret = fun(l1)
print(ret)
print("----------------------- 15 --------------------------------")


# 15、写函数,传入n个数,返回字典{‘max’:最大值,’min’:最小值}
# 例如:如:min_max(2,5,7,8,4) 返回:{‘max’:8,’min’:2}(此题用到max(),min()内置函数)

def min_max(*args):
    dic = {'max':max(args),'min':min(args)}
    return dic

ret = min_max(2,5,7,8,4)
print(ret)
print("----------------------- 16 --------------------------------")


# 16、写函数,传入一个参数n,返回n的阶乘
# 例如:cal(7) 计算7*6*5*4*3*2*1
def fun(n):
    s = 1
    for i in range(1, n+1):
        s = s * i
    print(s)
fun(7)
print(7 * 6 * 5 * 4 * 3 * 2 * 1)
print("----------------------- 17 --------------------------------")


# 17、写函数,返回一个扑克牌列表,里面有52项,每一项是一个元组
# 例如:[(‘红心’,2),(‘草花’,2), …(‘黑桃’,‘A’)]

def poker():
    poker_list = []
    l1 = ['红心','草花','黑桃','方片']
    l2 = ['A',2,3,4,5,6,7,8,9,10,'J','Q','K']
    for i in l1:
        for k in l2:
            poker_list.append((i,k))
    return poker_list
print(poker())
print("----------------------- 18 --------------------------------")


# 18、 有如下函数:
# def wrapper():
#     def inner():
#         print(666)
# wrapper()
# 你可以任意添加代码,用两种或以上的方法,执行inner函数

#方法1
def wrapper():
    def inner():
        print(666)
    inner()

wrapper()

#方法2
def wrapper():
    def inner():
        print(666)
    return inner

ret = wrapper()
ret()




练习题2

#!/usr/bin/env python3
# author:Alnk(李成果)
import os

"""
题目:用函数完成登录注册以及购物车的功能
需求:
    1,启动程序,用户可选择四个选项:登录,注册,购物,退出。
    2,用户注册,用户名不能重复,注册成功之后,用户名密码记录到文件中。
    3,用户登录,用户名密码从文件中读取,进行三次验证,验证不成功则退出整个程序。
    4,用户登录成功之后才能选择购物功能进行购物,购物功能(就是将购物车封装到购物的函数中)。
    5,退出则是退出整个程序。
"""

# 设定登录标志位
login_flag = False


def register():
    """
    注册
    :return:None
    """
    while 1:
        username = input('\n请输入你想注册的账户名称>>>:').strip()
        userpwd = input('请输入你想设置的登录密码>>>:').strip()
        # 存储用户信息目录
        if not os.path.exists("user_info"):
            os.mkdir("./user_info")

        if os.path.exists("user_info/%s" % (username)):
            print("该用户名已经被注册,请重新输入\n")
            continue

        with open("user_info/%s" % (username), encoding='utf-8', mode='w') as f:
            f.write("%s|%s|0" % (username,userpwd) )
            f.flush()
            print('账号注册成功!\n')
            return


def login():
    """
    登录
    :return:None
    """
    # 密码可输错次数
    count = 3
    while 1:
        username = input("\n请输入登录账号(返回B/b)>>>:").strip()
        if username.strip().lower() == 'b':
            print('\n')
            break
        userpwd = input("请输入登录密码>>>:").strip()
        # 用户是否存在
        if os.path.exists('user_info/%s' % (username) ):
            # 获取用户登录密码和密码输错次数
            with open('user_info/%s' % (username), encoding='utf-8', mode='r') as f1:
                user_l1 = f1.readline().strip().split('|')
                pwd = str(user_l1[1])
                count_pwd = int(user_l1[2])
                # 账号是否冻结
                if count_pwd == count:
                    print("账号 [%s] 已经被冻结,请联系管理员解除冻结或使用其他账号登陆\n" % (username))
                    continue
                # 密码是否正确
                if userpwd == pwd:
                    print('登录成功!\n')
                    # 重置密码输错次数
                    count_pwd = 0
                    user_l1[2] = count_pwd
                    with open('user_info/%s' % (username), encoding='utf-8', mode='w') as f2:
                        f2.write("%s|%s|%s" % (user_l1[0], user_l1[1], user_l1[2]))
                        f2.flush()
                    # 登录成功,修改默认的标志位
                    global login_flag
                    login_flag = True
                    return
                else:
                    # 登录失败,密码输错次数 +1
                    count_pwd += 1
                    user_l1[2] = count_pwd
                    with open('user_info/%s' % (username), encoding='utf-8', mode='w') as f3:
                        f3.write("%s|%s|%s" % (user_l1[0] ,user_l1[1], user_l1[2]) )
                        f3.flush
                    # 密码连续输错3次,直接退出程序
                    if count_pwd == count:
                        exit('[%s] 账号密码连续输错3次,程序退出!' % (username))
                    print('密码错误。\n')
                    continue
        else:
            print('用户不存在!')


def recharge():
    """
    充值
    :return:True,用户余额
    """
    while 1:
        user_balance = input("请先给账号充值(返回B/b):")
        if user_balance.lower() == "b":
            print('')
            return False
        elif user_balance.isdigit():
            user_balance = int(user_balance)
            print("账号充值成功!余额为[%s]元\n" % (user_balance))
            return True,user_balance
        else:
            print("输入有误,请重新输入。")


def jiesuan(user_shopping_cart,user_balance):
    """
    结算功能
    :param user_shopping_cart: 用户选购商品的临时字典
    :param user_balance: 用户充值的余额
    :return:None
    """
    while 1:
        # 显示购物车里的商品
        print("\n您的购车里商品如下:")
        for k in user_shopping_cart:
            print("\t商品[%s] 数量[%s] 价格[%s]" % (k, user_shopping_cart[k]['number'], user_shopping_cart[k]['price']))
        # 购物车所有商品总价
        shopp_cart_total = 0
        print("\n\n正在结算,请稍候...")
        # 计算商品总价格
        for k in user_shopping_cart:
            shopp_cart_total = shopp_cart_total + user_shopping_cart[k]['number'] * user_shopping_cart[k]['price']
        # 余额是否能够支付
        if user_balance >= shopp_cart_total:
            print("您本次总共需要支付[%s]元,余额为[%s]元" % (shopp_cart_total, user_balance))
            print("\n您本次购买的商品详单如下:")
            for k in user_shopping_cart:
                print('\t商品[%s] 数量[%s] 价格[%s]'%(k,user_shopping_cart[k]['number'],user_shopping_cart[k]['price']))
            print("\n本次总共消费[%s]元,账户余额为[%s]元" % (shopp_cart_total, user_balance - shopp_cart_total))
            print("\n购买成功!\n")
            return
        else:
            print("本次总共需要支付[%s]元 你的余额为[%s]元" % (shopp_cart_total, user_balance))
            print("余额不足,请先删除购物车里的一些商品再去结算哟\n")
            while 1:
                print("\n购物车的商品列表如下:")
                for k in user_shopping_cart:
                    print('\t商品[%s] 数量[%s] 价格[%s]' % (k, user_shopping_cart[k]['number'], user_shopping_cart[k]['price']))
                user_choice2 = input("请输入你想删除的商品名称:")
                # 从购物车删除商品
                if user_shopping_cart.get(user_choice2):
                    # 商品数量为1,直接删除。否则减少商品的数量1
                    if user_shopping_cart[user_choice2]['number'] == 1:
                        del user_shopping_cart[user_choice2]
                        print('商品[%s]已从购物车删除' % (user_choice2))
                    elif user_shopping_cart[user_choice2]['number'] > 1:
                        user_shopping_cart[user_choice2]['number'] -= 1
                        print("商品[%s]数量减少1件" % (user_choice2))
                    break
                else:
                    print("\n输入的商品名称有误,请重新输入")


def buy():
    """
    购物
    :return:None
    """
    # 默认标志为是否被修改,即是否已经登录
    if login_flag:
        print('\n')
        # 获取充值函数返回值,为一个元组(True,user_balance)
        ret = recharge()
        if ret[0]:
            # 用户余额
            user_balance = ret[1]
            # 用户选购商品临时购物车
            user_shopping_cart = {}
            # 商品列表
            goods_dic = {
                "1": {"name": "电脑", "price": 1999, },
                "2": {"name": "鼠标", "price": 10, },
                "3": {"name": "键盘", "price": 60, },
                "4": {"name": "手机", "price": 4000, },
                "5": {"name": "ipad", "price": 2999, },
                "n": {"name": "购物车结算", "price": '', },
            }
            while 1:
                print("下列是您可以选购的商品(退出Q/q):")
                for key in goods_dic:
                    print('\t', key, goods_dic[key]['name'], goods_dic[key]['price'])
                user_choice = input("请输入你想购买的商品序号:")
                if user_choice.lower() == "q":
                    print("退出购物商城")
                    break
                # 结算
                elif user_choice == "n":
                    jiesuan(user_shopping_cart,user_balance)
                    break
                # 添加商品到用户购物车
                elif goods_dic.get(user_choice):
                    # 判断购物车是否已经有该商品,如果有直接数量加1,没有则创建一个新的键值对
                    if user_shopping_cart.get(goods_dic[user_choice]['name']):
                        user_shopping_cart[goods_dic[user_choice]['name']]['number'] += 1
                    else:
                        user_shopping_cart[goods_dic[user_choice]['name']] = {"number": 1,"price": goods_dic[user_choice]['price']}
                    print("\n商品[%s] 价格[%s] " % (goods_dic[user_choice]['name'], goods_dic[user_choice]['price']))
                    print('添加到购物车成功!\n')
                else:
                    print("输入有误,请重新输入哦\n")
    else:
        print('请先登录哦\n')


def sign_out():
    """
    退出程序
    :return:None
    """
    exit('退出程序!')


def display():
    """
    程序入口,显示
    :return:None
    """
    msg = """---- 欢迎来到老男孩购物商城 ----
        1 注册
        2 登录
        3 购物
        4 退出
    """
    dic = {
        '1': register,
        '2': login,
        '3': buy,
        '4': sign_out,
    }
    while 1:
        print(msg)
        keys = input('请输入你要选择的操作序号>>>:')
        if keys in dic:
            dic[keys]()
        else:
            print('输入有误,请输入序号哟')
            continue


if __name__ == '__main__':
    display()

posted @ 2021-04-12 17:33  李成果  阅读(92)  评论(0编辑  收藏  举报