【python】python入门基础理论+实践,这一篇就够了

news2024/9/21 16:34:34

文章目录

    • 简介:第一个hello world
    • 字符串str
      • 多引号
      • 字符串拼接
      • 字符串方法
        • 格式化方法
        • 判断方法
        • 查、改、计数、替换
        • 特殊方法
    • 布尔型bool
    • 列表类型
      • 深浅copy
      • 列表生成式
      • 练习
        • 列表去重(不能用set)
        • 找到列表中第二大的数(不能用sort)
        • 判断一个列表是不是另外一个列表的子列表
        • 找到离最大&最小的平均值最近的值
        • 双色球福利彩票选购程序
    • 常用运算符
      • 逻辑运算
      • 成员运算
    • 读取用户指令
    • 循环
      • for循环
      • while 循环
      • for...else/while...else
      • 练习
        • 存款多少年才能翻倍?
        • 小球坠落反弹经过多少米
        • 小猴子吃桃
        • 寻找列表中的最大值和最小值
        • 求2组列表的数据组合
    • 数据类型-元组
    • 数据类型-字典dict
      • dict定义
      • dict特性
      • dict⽤法
      • dict 为何查询速度快
      • 练习
        • 数值分类
        • 同字⺟异序词
    • 数据类型-集合set
      • 增删查
      • 关系测试
    • 二进制
      • ⼆进制与⼗进制转换
      • ⼆进制位运算
    • 初识编码
      • ASCII编码
      • 计算机如何识别中文?
      • Unicode编码
      • UTF-8
      • 常⽤编码介绍⼀览表
      • py2 vs py3 编码区别
    • ⼗六进制
    • 三元运算
    • 函数
      • 函数的定义
      • 函数的返回值
      • 函数传值类型
      • 参数类型-位置参数和关键参数
        • 必备参数(位置参数)
        • 关键字参数
        • 和位置参数混用
      • 参数类型-默认参数&不定长参数
        • 默认参数
        • 不定长参数
      • 函数嵌套
      • 全局变量 VS 局部变量
      • 匿名函数lambda
      • 高阶函数
      • 函数的递归
      • 内置函数
    • ⽂件操作
      • open⽅法基本使⽤
      • 创建模式:创建⽂件
      • 读模式:循环读取⽂件&查找
      • 追加模式
      • flush、seek、tell、truncate
      • 修改文件
      • 处理不同编码的文件
      • 2进制模式与编解码

简介:第一个hello world

print("hello world!");

for i in range(10):
    print('run:',i);

import time;
time.sleep(10);

字符串str

在Python中,加了引号的字符都被认为是字符串!

name = "zhangsan"

多引号

多引号什么作⽤呢?作⽤就是多⾏字符串必须⽤多引号

message = '''
这是多行的字符串,
换行了哈,
再一次换行了.
'''
print(message)

字符串拼接

字符串只能进⾏”相加”和”相乘”运算。

name = "zhangsan"
hobbie = 'football'

info = name  + hobbie
print(info) # zhangsanfootball

allname = name * 2
print(allname) # zhangsanzhangsan

字符串的拼接只能是双⽅都是字符串,不能跟数字或其它类型拼接。

name = "zhangsan"
age = 20
hobbie = 'football'
print(type(name)),print(type(age)) #<class 'str'> <class 'int'>

# 打印多行信息 python2.x 语法
# %s 字符串占位符
# %d 数字占位符
# %f 浮点数占位符
msg = '''
-------- %s info ----------
name: %s
age: %d
hobbie: %s   
------------end ------------
''' % (name,name,age,hobbie)
print(msg)


# 打印多行信息python3.x 语法
# 添加 f 解析{} 占位符内容
msg2 = f'''
-------- {name} info ----------
name: {name}
age: {age}
hobbie: {hobbie}   
------------end ------------
'''
print(msg2)

字符串方法

格式化方法
a = 'tom'
a.capitalize() # Tom 首字母大写

b = 'Zhang San'
b.casefold() # zhang san  为了方便字符串对比,把字符串都转化为小写

c = 'jack center'
# string.center() 字符串两边填充
c.center(50,'-') # -------------------jack center--------------------

d = 'Hello\tworld' # 使用默认制表符大小(8个空格) 
d1 = 'Hello\tworld\tfrom\tPython' 
d2 = "Hello world"

r1 = d1.expandtabs(4) # 指定制表符大小为4个空格 
r2 = d2.expandtabs() # 没有制表符的字符串
# print(d)
# print(r1)
# print(r2)

a2 = 'left string'
a2 = a2.ljust(40,'-') # 字符串从左边根据长度开始填充
# print(a2) # left string-----------------------------

a3 = 'right string'
a3 = a3.rjust(40,'-') # 字符串从右边根据长度开始填充
# print(a3) # ----------------------------right string

a4 = 'Tom Jack'
a4 = a4.lower() # 全变小写
# print(a4) # tom jack

a5 = 'Tom Jack'
a5 = a5.swapcase() # 大小写互换
# print(a5) # tOM jACK

a6 = 'hello world'
a6 = a6.title() # 改成标题,即每个单词首字母大写
# print(a6) # Hello World

a7 = 'hello world'
a7 = a7.upper() # 改大写
# print(a7) # HELLO WORLD

a8 = 'hello world'
a8 = a8.zfill(50) # 字符串空的地方填0
# print(a8) # 000000000000000000000000000000000000000hello world

a9 = ' hello world \n '
# print(a9) #  hello world 
a9 = a9.strip() # 去掉两边的空格换行符
# print(a9) #hello world

a10 = ' hello world'
a10 = a10.lstrip() # 去掉左边的空格
# print(a10)  # hello world

a11 = ' hello world'
a11 = a11.rstrip() # 去掉右边的空格
# print(a11) #  hello world

a12 = 'my name is {name}, i am {age} old.'
a12 = a12.format(name = 'Tom',age = 28) # 引用外部变量
# print(a12) # my name is Tom, i am 28 old.

# format 使用方式二
a13 = 'my name is {0}, i am {1} old.'
a13 = a13.format('Tom', 28)
# print(a13) # my name is Tom, i am 28 old.

判断方法
a1 = 'hello world'
r1 = a1.startswith('he')
# print(r1) # True

a2 = 'hello world'
r2 = a2.endswith('ld')
# print(r2) # True

a3 = 'hello world'
r3 = a3.isalpha() # 是不是字母,不能包括空格
# print(r3) # False

a4 = 'zhangsan25'
r4 = a4.isalnum() # 是不是字符or数字
# print(r4) # True

a5 = '123'
r5 = a5.isdigit() # 是不是数字,不能有小数点
# print(r5) # True
# print('12.3'.isdigit()) # False

a6 = '2name'
r6 = a6.isidentifier() # 是不是合法的变量名字
# print(r6) # False

a7 = 'Tom'
r7 = a7.islower() # 是否是小写
# print(r7) # False

a8 = '26'
r8 = a8.isnumeric() # 判断是不是数字,中文的数字描述也能判断
# print(r8) # True
# print('二十六'.isnumeric()) # True


a9 = 'hello'
r9 = a9.isprintable() # 是否能打印,比如图片资源就不能被打印
# print(r9) # True

a10 = ' '
r10 = a10.isspace() # 是不是空格
# print(r10) # True

a11 = 'The Title'
r11 = a11.istitle() # 判断是不是标题(首字母大写)
# print(r11) # True

a12 = 'THE TITLE'
r12 = a12.isupper() # 是不是都是大写
print(r12) # True

查、改、计数、替换
a1 = 'hello world'
r1 = a1.find('l') # 查找字符串第一次出现的索引,找不到结果会返回-1
# print(r1) # 2

a2 = 'hello world'
r2 = a2.rfind('l') # 从右侧开始查找字符串第一次出现的索引
# print(r2) # 9

a3 = 'hello world'
r3 = a3.index('l') # 查找字符串的索引,跟find的区别是,index找不到会报错
# print(r3) # 2

a4 = 'hello world'
r4 = a4.rindex('l') # 从右侧开始查找字符串第一次出现的索引,跟rfind的区别是,rindex找不到索引会报错
# print(r4) # 9
# print(a4.rindex('H')) # 找不到报错了

a5 = 'hello world'
r5 = a5.count('l') # 字符串出现的次数
# print(r5) # 3

a6 = 'hello world'
r6 = a6.split() # 默认以空格切分,并返回列表
# print(r6) # ['hello', 'world']

a7 = 'hello world python'
r7 = a7.rsplit() # 从右边开始切,默认看不出区别
# print(r7) # ['hello', 'world', 'python']
# print(a7.rsplit(maxsplit = 1)) # ['hello world', 'python'] 意思是从右边切一下,形成了2个列表的元素

a8 = 'hello\nworld\npython'
r8 = a8.splitlines() # 根据\n分割字符串形成列表
# print(r8) # ['hello', 'world', 'python']

a9 = 'hello world'
r9 = a9.removeprefix('he') # 移除从前面匹配的字符串
# print(r9) # llo world

a10 = 'hello world'
r10 = a10.removesuffix('ld') # 移除从后边开始匹配的字符串
# print(r10) # hello wor

a11 = 'hello world'
r11 = a11.replace('hello','pyton') # 替换字符串
print(r11) # pyton world
print(a11.replace('l','T',2)) #  heTTo world  把l替换成T,并且指定替换的次数为2

特殊方法
names = ['zhangsan','lisi','tom']
r1 = '-'.join(names) # 把列表转成字符串方法
# print(r1) # zhangsan-lisi-tom

source = 'abcdefghi' # 数据源
output = '012345678' # 对等加密输入
password_table = str.maketrans(source,output) # 生成密码本
msg = 'hello world'
r2 = msg.translate(password_table) # 加密
print(r2) # 74llo worl3

字符串文本加密示例:

import string
source = string.printable 
# print(source) # 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 
output = string.printable[::-1] # 反转
# print(output) # ~}|{`_^]\[@?>=<;:/.-,+*)('&%$#"!ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9876543210

password_table = str.maketrans(source,output) # 输出一个密码本
msg = 'hello world' # 需要加密的原文
encrypt_msg = msg.translate(password_table) # 加密后的内容
# print(encrypt_msg) # ?\;;.5&.+;]

password_table2 = str.maketrans(output,source) # 密码本
decrypt_msg = encrypt_msg.translate(password_table2) # 解密后的内容
print(decrypt_msg) # hello world

统计字符个数示例:

while True:
    msg = input(">:").strip() # my name is zhangsan,age is 25.
    if not msg: continue # if len(msg) == 0
    str_count = 0
    int_count = 0
    space_count = 0
    special_count = 0
    for i in msg:
        if i.isalpha():
            str_count += 1
        elif i.isdigit():
            int_count += 1
        elif i.isspace():
            space_count += 1
        else:
            special_count += 1
    print(f"str_count:{str_count},int_count:{int_count},space_count:{space_count},special_count:{special_count}") # str_count:21,int_count:2,space_count:5,special_count:2

布尔型bool

布尔类型很简单,就两个值 ,⼀个True(真),⼀个False(假), 它的作⽤主要是⽤作逻辑判断.

score = 540
good_score = 600

if score >= good_score:
    print("You passed the exam!")
else:
    print("You failed the exam.")

列表类型

list = []
listType = type(list)
# print(listType) #<class 'list'>

a_list = ['zhangsan','lisi','lili','a','b']
b_list = ['1','2']

# 索引
a_list[0] #找第0个位置的值(取第一个元素): zhangsan
a_list[-1] #找最后一个值: b
a_list[:] #取所有列表元素: ['zhangsan', 'lisi', 'lili', 'a', 'b']
a_list[:len(a_list)] #取所有列表元素: ['zhangsan', 'lisi', 'lili', 'a', 'b']
a_list[0:len(a_list)] #取所有列表元素: ['zhangsan', 'lisi', 'lili', 'a', 'b']
#a_list[0:n] #从0号取到n-1号元素
a_list[0:2] #取0号到1号元素: ['zhangsan', 'lisi']
a_list.index('b')  #反向索引找到b的位置: 4

# list的组合及复制
c_list = a_list + b_list #两个list组合成一个: ['zhangsan', 'lisi', 'lili', 'a', 'b', '1', '2']
d_list = a_list * 2 # a_list每个元素重复2次变新的list: ['zhangsan', 'lisi', 'lili', 'a', 'b', 'zhangsan', 'lisi', 'lili', 'a', 'b']

#是否存在
'b' in a_list # True b在a_list里面

#新增元素
a_list.append('c') #最后面新增一个元素
a_list.extend(['d','e']) # 一次新增多个元素
a_list.insert(0,'aa') # 在索引为0的元素前面新增元素

#删除元素
del a_list[0] #删除位置在0的值
a_list.pop() #删除最后一个元素
a_list.pop(2) #删除索引为2的值
a_list.remove('b') #删除第一个b的值


##列表删除所有指定元素
while 'lili' in a_list: 
	a_list.remove('lili') #删除所有lili元素
	
#循环生成list
e_list = [x+'a' for x in a_list] #循环生成新list: ['zhangsana', 'lisia', 'aa', 'ca', 'da']

#循环访问每个元素
for a in a_list:
	print('当前元素:',a)
	
#常用在list的函数
len(a_list) #长度
max(a_list) #取大
min(a_list) #取小

#其他常用的list函数
a_list.sort() #排序
a_list.reverse() #倒序,反转,原列表修改
a_list[::-1] #倒序,反转,生成一个新的列表
print(a_list.count('a')) #统计某个元素出现的次数

深浅copy

import copy

a = [1,2,3,['a','b'],4,5]
b = a.copy() # 浅copy
b[0] = 'd'
print(a[0],b[0]) # 1 d
b[3][0] = 'aa'
print(a[3][0],b[3][0]) # aa aa

c = copy.deepcopy(a) # 深copy
c[3][0] = 'cc' 
print(a[3][0],c[3][0]) # aa cc

列表生成式

# 生成一个list列表,如:['staff_0','staff_1',....]

# 方式一
staff_list = []
for i in range(30):
  staff_list.append(f"staff_{i}")
print(staff_list)

# 方式二:
staff_list2 = [f"staff_{i}" for i in range(30)]
print(staff_list2)

练习

列表去重(不能用set)
li = [1,2,5,10,2,6,34,56,2,17,89,5,34,10]
duplicate_num = [] # 存放需要去重的数,以及重复的次数

for i in li:
  i_show_count = li.count(i) # 每个值重复的次数
  if i_show_count > 1 and [i,i_show_count] not in duplicate_num:
    duplicate_num.append([i,i_show_count])

for item in duplicate_num:
  # n = item[0] # 重复的值
  # times = item[1] #重复值的次数
  n,times = item
  for j in range(times - 1):
    li.remove(n)
    print(f"删除了一次的值:{n}")

print(li)

打印结果:

除了一次的值:2
删除了一次的值:2
删除了一次的值:5
删除了一次的值:10
删除了一次的值:34
[1, 6, 56, 2, 17, 89, 5, 34, 10]
找到列表中第二大的数(不能用sort)
li = [1,2,5,10,2,6,34,56,2,17,89,5,34,10]
# 冒泡排序实现
for n in range(2): # 冒泡一次最后一位得到最大值,冒泡两次,倒数第二位得到第二最大值....以此类推
  for index in range(len(li) - 1):
    # 让当前索引值index,跟index+1比较
    item = li[index]
    if item > li[index + 1]: # index索引的值> index+1索引的值,进行交换
      li[index] = li[index + 1]
      li[index + 1] = item
  
print(li)
print(li[len(li)-2]) # 56
判断一个列表是不是另外一个列表的子列表
li = [1,2,5,10,2,6,34,56,2,17,89,5,34,10]
li2 = [1,5,10,11]

is_sub_list = True
for i in li2:
    if i not in li:
        is_sub_list = False
        print('li2不是li的子列表')
        break

if is_sub_list:
    print("li2是li的子列表")
找到离最大&最小的平均值最近的值
li = [1,2,5,10,2,6,33,56,2,17,89,5,34,10]

max_n = li[0]
min_n = li[1]

for i in li:
    if i > max_n:
        max_n = i
    if i < min_n:
        min_n = i
avg_n = (max_n + min_n) / 2
print(max_n,min_n,avg_n)

closest_n = li[0]
for n in li:
    if abs(avg_n - n) < abs(avg_n - closest_n):
        closest_n = n
        print(f'找到了更近的数:{closest_n}')

print(f'最终的答案:{closest_n}')
双色球福利彩票选购程序

双色球福利彩票:1个蓝球和6个红球,蓝球1-16数字,红球1-33数字。

red_ball = []
blue_ball = []

red_count = 0
while red_count < 6:
    input_number = input(f"请输入第{red_count + 1}个红球:")
    if not input_number.isdigit():
        print("输入的不是数字,请重新输入")
        continue
    input_number = int(input_number)
    if 0 < input_number <= 33 and input_number not in red_ball:
        red_ball.append(input_number)
        red_count += 1

blue_count = 0
while blue_count < 1:
    input_number = input(f"请输入第{blue_count + 1}个蓝球:")
    if not input_number.isdigit():
        print("输入的不是数字,请重新输入")
        continue
    input_number = int(input_number)
    if 0 < input_number <= 16 and input_number not in blue_ball:
        blue_ball.append(input_number)
        blue_count += 1

print(f"您选择的蓝球是:{blue_ball},红球是:{red_ball}")

上面代码进行优化,优化后的代码:

red_ball = []
blue_ball = []

li = [[6,33,'红球',red_ball],[1,16,'蓝球',blue_ball]]

for item in li:
    print(f"开始选择{item[2]}".center(50,'-'))
    count = 0
    while count < item[0]:
        input_number = input(f"请输入第{count + 1}个{item[2]}:").strip()
        if not input_number.isdigit():
            print("输入的不是数字,请重新输入")
            continue
        input_number = int(input_number)
        if 0 < input_number <= item[1] and input_number not in item[3]:
            item[3].append(input_number)
            count += 1

print(f"您选择的蓝球是:{blue_ball},红球是:{red_ball}")

常用运算符

其他省略

逻辑运算

  • and
  • or
  • not:取反(示例:not a > b)

成员运算

只有in, not in 2种, ⽤来测试数据中是否包含了⼀系列的成员

  • in:如果在指定的序列中找到值返回True,否则返回False。
  • not in:如果在指定的序列中没有找到值返回True,否则返回False。
>>> names
[ 'Jack', 'zhangsan', 'lisi', 'wangmazi', '⼩强']
>>> "Jack" in names
True
>>> "Jack" not in names
False
>>> s = "我是沙河最帅的仔"
>>> "沙河" in s
True

注意,可以⽤来测试字符串、列表、元组、字典、集合,但是不能测试数字类型

读取用户指令

name = input("What is your name? ").strip()
age = int(input("How old are you? "))
hobbie = input("What is your favorite hobby? ")
job = input("What is your job? ")

msg = f'''
---------- {name} ------------
name: {name}
age: {age},wow still young! in {40-age} years you will be 40
hobbie: {hobbie}
job: {job}
-------------  end ---------
'''
print(msg)

最终打印结果:

What is your name? mr zhang
How old are you? 28
What is your favorite hobby? money
What is your job? coder

---------- mr zhang ------------
name: mr zhang
age: 28,wow still young! in 12 years you will be 40
hobbie: money
job: coder
------------- end ---------

上面代码中strip方法就是把输入的前后的空格也去掉。

int方法就是把输入的字符串转换为数字类型。

循环

for循环

# 打印100 以内的偶数
for i in range(101):
    if i % 2 == 0:
        print(i)

# 打印50-100以内的偶数
for i in range(50,101):
    if i % 2 == 0:
        print(i)

# 打印100-50以内的偶数
for i in range(100,50,-1):
    if i % 2 == 0:
        print(i)

嵌套循环示例:

# 嵌套循环,打印1-6层的楼,每层楼10个房间
for floor in range(1,7):
    print(f"当前在{floor}层".center(50,'-'))
    for room in range(1,10):
        print(f"当前房间是{floor}0{room}室.")

控制台打印效果如下所示:

----------------------当前在1层-----------------------
当前房间是101室.
当前房间是102室.
当前房间是103室.
当前房间是104室.
当前房间是105室.
当前房间是106室.
当前房间是107室.
当前房间是108室.
当前房间是109室.
----------------------当前在2层-----------------------
当前房间是201室.
当前房间是202室.
当前房间是203室.
.........

跳出循环:

# break、continue的使用
# 第三层的时候跳出循环,执行下面的循环
# 第四层第四间房间的时候,跳出当前循环
for floor in range(1,7):
    print(f"当前在{floor}层".center(50,'-'))
    if floor == 3:
        print('第三层跳出...')
        continue
    for room in range(1,10):
        if floor == 4 and room == 4:
            print('第四层第四个房间跳出...')
            break
        print(f"当前房间是{floor}0{room}室.")

注意:上面代码中break只是跳出了第二个for循环,下面第五层会接着循环,那如何跳出这两个for循环呢,示例代码:

# 跳出多层循环
should_break  = False
for floor in range(1,7):
    print(f"当前在{floor}层".center(50,'-'))
    if floor == 3:
        print('第三层跳出...')
        continue
    for room in range(1,10):
        if floor == 4 and room == 4:
            print('第四层第四个房间跳出...')
            should_break = True
            break
        print(f"当前房间是{floor}0{room}室.")
    if should_break:
        break

打印9*9乘法表:

# 9*9乘法表
for i in range(1,10):
  for j in range(1,i + 1):
    print (f"{i}X{j} = {i * j}",end= ' ' if j < i else '\n')

方式二:主要是换行的方式:

for i in range(1,10):
  for j in range(1,i + 1):
    print (f"{i}X{j} = {i * j}",end= " ")
  print() #  换行 默认\n

最终结果:

1X1 = 1
2X1 = 2 2X2 = 4
3X1 = 3 3X2 = 6 3X3 = 9
4X1 = 4 4X2 = 8 4X3 = 12 4X4 = 16
5X1 = 5 5X2 = 10 5X3 = 15 5X4 = 20 5X5 = 25
6X1 = 6 6X2 = 12 6X3 = 18 6X4 = 24 6X5 = 30 6X6 = 36
7X1 = 7 7X2 = 14 7X3 = 21 7X4 = 28 7X5 = 35 7X6 = 42 7X7 = 49
8X1 = 8 8X2 = 16 8X3 = 24 8X4 = 32 8X5 = 40 8X6 = 48 8X7 = 56 8X8 = 64
9X1 = 9 9X2 = 18 9X3 = 27 9X4 = 36 9X5 = 45 9X6 = 54 9X7 = 63 9X8 = 72 9X9 = 81

求出100以内的所有素数

素数(Prime Number) 是指在一个大于1的自然数中,除了1和此整数自身外,不能被其他自然数整除的数。换句话说,只有两个正因数(1和自己)的自然数即为素数。最小的素数是2,它也是唯一的偶数素数。

例如,数字5有因数1和5;数字7有因数1和7;数字11有因数1和11……这些数字都是素数。而数字4除了因数1和4外,还有因数2,所以它不是素数。

# 求出100以内的所有素数
prime_num = 0 # 累积100内的素数个数
for i in range(2,101):
  is_prime_number = True
  for j in range(2,i):
    if i % j == 0:
      is_prime_number = False
      break
  if is_prime_number:
    prime_num += 1
    print(f"{i}是素数,累计的素数个数:{prime_num}")

上面代码我们可以使用for…else进行优化:

prime_num = 0 # 累积100内的素数个数
for i in range(2,101):
  for j in range(2,i):
    if i % j == 0:
      break
  else:
    prime_num += 1
    print(f"{i}是素数,累计的素数个数:{prime_num}")

打印3角形:

# 打印3角形
for i in range(11):
    if i <= 5:
        print("* " * i)
    else:
        print("* " * (11 - i))

展示效果:

*
* *
* * *
* * * *
* * * * *
* * * * *
* * * *
* * *
* *
*

while 循环

# while 循环
count = 0
while count < 10:
    count += 1
    print('loop:',count)

用while实现循环猜年龄,允许用户猜3次,若还不对,告诉他,你真笨,还想继续猜么?如果用户选择yes,就让他继续,如果选择no,就退出。

age = 20
count = 0

while count < 3:
  guess = input('请猜下年龄>:')
  if guess.isdigit():
      guess = int(guess)
  else:
     print('不识别的指令,请重新输入...')
     continue
  if guess > age:
      print('猜大了...')
  elif guess < age:
      print('猜小了...')
  else:
      print('猜对了...')
      break
  count += 1
  if count == 3:
      cmd = input('你笨,你猜了3次,还想继续猜么?(y/n)').strip()
      if cmd in ['y','Y','yes','Yes']:
          count = 0
      else:
          print('退出游戏...')

for…else/while…else

for…else:

for i in range(10):
  print(i)
  if i == 5:
    break
else: #当循环正常结束时(没有被break,exit...),则执行
  print('循环结束')

print('done....')

while…else:

count = 0
while count < 10:
  print(count)
  count += 1
  if count == 5:
    break
else: #当循环正常结束时(没有被break,exit...),则执行
  print('循环结束')

练习

存款多少年才能翻倍?

1万本金,利息是0.0325每年,问年本带息多少年能翻倍?

money = 10000
year = 0
while money <= 20000:
  money = money * (1 + 0.0325)
  year += 1
  print(f"第{year}年,本金是{money}元")

结果如下所示:

第1年,本金是10325.0元
第2年,本金是10660.5625元
第3年,本金是11007.03078125元
第4年,本金是11364.759281640625元
第5年,本金是11734.113958293945元
第6年,本金是12115.472661938498元
第7年,本金是12509.2255234515元
第8年,本金是12915.775352963674元
第9年,本金是13335.538051934993元
第10年,本金是13768.94303862288元
第11年,本金是14216.433687378123元
第12年,本金是14678.467782217911元
第13年,本金是15155.517985139993元
第14年,本金是15648.072319657043元
第15年,本金是16156.634670045896元
第16年,本金是16681.725296822387元
第17年,本金是17223.881368969116元
第18年,本金是17783.65751346061元
第19年,本金是18361.62638264808元
第20年,本金是18958.37924008414元
第21年,本金是19574.526565386874元
第22年,本金是20210.698678761946元
小球坠落反弹经过多少米

一个小球,从100米高空坠落,每次反弹回原来一半高度,问第10次反弹完,小球经过多少米?

height = 100
distance = 0
for i in range(10):
  distance += height + height /2 
  height = height / 2
  print(f"{i + 1}次反弹玩,小球经过的高度为{distance}")

结果如下:

1次反弹玩,小球经过的高度为150.0
2次反弹玩,小球经过的高度为225.0
3次反弹玩,小球经过的高度为262.5
4次反弹玩,小球经过的高度为281.25
5次反弹玩,小球经过的高度为290.625
6次反弹玩,小球经过的高度为295.3125
7次反弹玩,小球经过的高度为297.65625
8次反弹玩,小球经过的高度为298.828125
9次反弹玩,小球经过的高度为299.4140625
10次反弹玩,小球经过的高度为299.70703125
小猴子吃桃

有一堆桃子,猴子每天吃桃子总数的一半并多吃一个。吃了10天,到第11天只剩下一个桃子。问,猴子吃之前,一共是多少个桃子。

n = 1
day = 11
while day > 1:
   n = (n + 1) * 2 # 上一天吃之前的桃子数量
   day -= 1
   print(f"第{day}天,没有吃之前桃子数量:{n}")

结果:

第10天,没有吃之前桃子数量:4
第9天,没有吃之前桃子数量:10
第8天,没有吃之前桃子数量:22
第7天,没有吃之前桃子数量:46
第6天,没有吃之前桃子数量:94
第5天,没有吃之前桃子数量:190
第4天,没有吃之前桃子数量:382
第3天,没有吃之前桃子数量:766
第2天,没有吃之前桃子数量:1534
第1天,没有吃之前桃子数量:3070
寻找列表中的最大值和最小值
data = [2,6,23,22,19,50,29,8,14,1]
max_data = data[0]
min_data = data[0]
for i in data:
  if i > max_data:
      max_data = i
  if i < min_data:
      min_data = i

print(max_data,min_data)
求2组列表的数据组合

从两个列表中各取1个数,如果这两个数的和等于10,则以列表的方式输出这两个数。

data1 = [4,8,9,20,5,12,22]
data2 = [9,12,6,1,5,14,7]

for i in data1:
  for j in data2:
    if i + j == 10:
      print([i,j])

结果:

[4, 6]
[9, 1]
[5, 5]

数据类型-元组

元组是只读列表,一旦创建,不可修改。只可进行查询、切片、循环操作。

# 元组定义
names = ('zhangsan','lisi','tom')

index = names.index('lisi')
# print(f"索引为{index}的元素为{names[index]}")

# 切片
r1 = names[0:3]
# print(r1) # ('zhangsan', 'lisi', 'tom')

r2 = names[0::2]
# print(r2) # ('zhangsan', 'tom')  步长为2

# 不能修改
# names[0] = 'zhangsan1' # TypeError: 'tuple' object does not support item assignment

注意点,如果在括号内只加一个数字,没有逗号,那么它的类型就是数字类型。示例代码如下:

n = (10)
print(type(n)) # <class 'int'>

m = (10,)
print(type(m)) # <class 'tuple'>

数据类型-字典dict

dict定义

{key1:value1, key2:value2}

:号左边是key, 右边是value

dict特性

  • 1.key-value结构
  • 2.key必须为不可变数据类型(字符串、数字、元组), (hashtable)
  • 3.key 必须唯⼀ ,(hashtable)
  • 4.⼀个key对应的value可存放任意数据类型,可修改、可以不唯⼀
  • 5.可嵌套,即value也可是dict
  • 6.py3.7之前是⽆序的, 3.7开始变成有序的了, ordered_dict
  • 7.查询速度快,且不受dict的⼤⼩影响。

dict⽤法

# 创建:方法一
info = {
  "name": 'zhangsan',
  "age": 18
}
# print(info) # {'name': 'zhangsan', 'age': 18}

# 创建:方法二
info2 = dict(name='zhangsan', age=18)
# print(info2) # {'name': 'zhangsan', 'age': 18}

# 新增
info3 = {
  "name": 'zhangsan',
  "age": 18
}
info3['sex'] = 'male'
# print(info3) # {'name': 'zhangsan', 'age': 18, 'sex': 'male'}

# 检查式新增
info4 = {
   "name": 'zhangsan',
  "age": 18
}
info4.setdefault('sex', 'male') 
# print(info4) # {'name': 'zhangsan', 'age': 18, 'sex': 'male'}
res = info4.setdefault('name','lisi')
# print(res) # zhangsan 如果原来存在当前新增的属性,那么会直接返回原来属性的值

# 修改
info5 = {
  "name": 'zhangsan',
  "age": 18
}
info5['name'] = 'lisi'
# print(info5) # {'name': 'lisi', 'age': 18}

# 合并修改
info6 = {
  "name": 'zhangsan',
  "age": 18
}
info6_1 = {
  "name": 'lisi',
  "sex": 'male'
}
info6.update(info6_1)
# print(info6) # {'name': 'lisi', 'age': 18, 'sex': 'male'}

# 查
info7 = {
  "name": 'zhangsan',
  "age": 18
}

re7 = info7.get('name')
# print(re7) # zhangsan
re8 = info7.get('sex') # 如果取不到,就返回None
# print(re8) # None

# re9 = info7['sex'] # 这种方式取值如果取不到,会报错
# print(re9) # KeyError: 'sex'

re10 = "name" in info7 # 判断是否包含某个属性
# print(re10) # True

re10_1 = info7.keys() # 返回⼀个包含字典所有KEY的列表;
# print(re10_1) # dict_keys(['name', 'age'])
re10_2 = info7.values() # 返回⼀个包含字典所有value的列表;
# print(re10_2) # dict_values(['zhangsan', 18])
re10_3 = info7.items() # 返回⼀个包含所有(键,值)元组的列表;
# print(re10_3) # dict_items([('name', 'zhangsan'), ('age', 18)])


# 删
info8 = {
  "name": 'zhangsan',
  "age": 18,
  "sex": 'male',
  "address": 'beijing'
}
info8.pop('name') # 删除存在的属性,并返回删除属性的值
# print(info8) # {'age': 18}

del info8['age'] # 删除指定key,同pop⽅法
# print(info8) # {'sex': 'male'}

info8.popitem() #  以LIFO的⽅式删除⼀对值
# print(info8) # {'sex': 'male'}
info8.clear() # 清空字典
# print(info8) # {}

# 循环
info9 = {
  "name": 'zhangsan',
  "age": 18,
  "sex": 'male',
  "address": 'beijing'
}

# for k in info9.keys(): # 遍历字典的key
#   print(k)

# for k,v in info9.items(): # 遍历字典的key和value
#   print(k,v)

# for k in info9: # 遍历字典的key,推荐⽤这种,效率速度最快
#   print(k,info9[k])


# 特殊⽅法-fromkeys : 批量⽣成多个k,v的dict
names = ['zhangsan','lisi','wangwu']
info10 = dict.fromkeys(names,'test') # 如果不设置默认值,默认是None
# print(info10) # {'zhangsan': 'test', 'lisi': 'test', 'wangwu': 'test'}

# 特殊⽅法-Copy: 浅copy , 同列表的copy⼀样
info11 = {
  "name": 'zhangsan',
  "age": 18,
  "sex": 'male',
  "address": 'beijing'
}
info12 = info11.copy()
# print(info12)

# 求长度-len 方法
info13 = {
  "name": 'zhangsan',
  "age": 18,
  "sex": 'male',
  "address": 'beijing'
}
print(len(info13)) # 4

dict 为何查询速度快

因为dict是基于hashtable实现的, hashtable的原理导致你查询速度就是O(1),意思就是你即使有1亿个数据,查询某个值也只需1次搞定。

先⽤最简单的例⼦理解,看以下列表nums,让你⽤最快最⾼效的⽅式找出100这个数,你怎么找?

>>> nums
[125, 247, 53, 260, 33, 6, 132, 198, 151, 110, 95, 163, 116, 295, 289, 200, 142, 153,
126, 41, 294, 290, 31, 34, 241, 132, 191, 82, 246, 123, 19, 171, 37, 130, 139, 250,
53, 241, 84, 172, 14, 120, 138, 92, 294, 116, 269, 104, 278, 146, 12, 293, 135, 240,
289, 121, 295, 50, 60, 198, 10, 57, 248, 79, 169, 298, 292, 64, 298, 3, 9, 152, 268,
178, 0, 136, 165, 53, 146, 78, 270, 104, 116, 283, 177, 145, 142, 71, 176, 33, 235,
134, 188, 29, 39, 15, 136, 137, 16, 189]
  • 1.先排序
  • 2.再折半(2分)算法查找

粗识hashtable

hashtable(散列表) ⽤了个更nb的⽅式 , 直接把你的key通过hash函数算出来个数字,然后扔在hashtable的某个位置。

在这里插入图片描述

你再去通过dict.get(“alex”)获取的时候,它只需要把 alex再变成⼀个hash值,去找在这个表⾥的值 就可以了。这样, ⽆论你的dict多⼤, 你查询速度都不会受影响。

练习

数值分类

把下⾯列表中的值进⾏分类 ,变成dict。

Input : test_list = [4, 6, 6, 4, 2, 2, 4, 8, 5, 8]
Output : {4: [4, 4, 4], 6: [6, 6], 2: [2, 2], 8: [8, 8], 5: [5]}
需求 : 值⼀样的要分类存在⼀个key⾥

代码实现:

test_list = [4, 6, 6, 4, 2, 2, 4, 8, 5, 8]
obj = {}
for i in test_list:
    if i not in obj:
        obj[i] = [i]
    else:
        obj[i].append(i)

print(obj) # {4: [4, 4, 4], 6: [6, 6], 2: [2, 2], 8: [8, 8], 5: [5]}
同字⺟异序词

把所有下表中同字⺟异序词找出来:

arr = ['cat', 'dog', 'tac', 'god', 'act']

结果:[ ['cat','tac','act'],['god','dog']]

代码实现:

arr = ['cat', 'dog', 'tac', 'god', 'act']

dic = {
    
}

for i in arr:
    token_key = list(i)
    token_key.sort()
    token_key = tuple(token_key) # 把列表转换成元组当字典的key
    if token_key not in dic:
        dic[token_key] = [i]
    else:
        dic[token_key].append(i)

result = dic.values() # dict_values([['cat', 'tac', 'act'], ['dog', 'god']])
result = list(result) # [['cat', 'tac', 'act'], ['dog', 'god']] 相对于上面去掉了dict_values
# print(result)

数据类型-集合set

  • ⾥⾯的元素不可变,代表你不能存⼀个list、dict 在集合⾥,字符串、数字、元组等不可变类型可以存
  • 天⽣去重,在集合⾥没办法存重复的元素
  • ⽆序,不像列表⼀样通过索引来标记在列表中的位置 ,元素是⽆序的,集合中的元素没有先后之分,如集
    合{3,4,5}和{3,5,4}算作同⼀个集合
  • 关系测试(作⽤)

基于上⾯的特性,我们可以⽤集合来⼲2件事,去重和关系运算

在这里插入图片描述

增删查

# 去重
a = {1,2,3,4,5,2,3,5}
a = set(a)
a = list(a)
# print(a) # [1, 2, 3, 4, 5]

# 增
a1 = {1,2,3,4,5}
a1.add(8)
# print(a1) # {1, 2, 3, 4, 5, 8}

# 查
a2 = {1,2,3,4,5}
# print(1 in a2) # True

# 删除
a3 = {1,2,3,4,5}
a3.remove(1) # {2, 3, 4, 5} 若不存在,会报错
a3.discard(1) # {3, 4, 5}  删除指定的值 ,若该值不存在,也不会报错
a3.pop() # 随机删除一个值,并返回该值
a3.clear() # 清空所有
a3.copy() # 复制

注:不能修改,⼀旦创建,不可修改⾥⾯的值

关系测试

# 去重
a = {1,2,3,4,5,2,3,5}
a = set(a)
a = list(a)
# print(a) # [1, 2, 3, 4, 5]

# 增
a1 = {1,2,3,4,5}
a1.add(8)
# print(a1) # {1, 2, 3, 4, 5, 8}

# 查
a2 = {1,2,3,4,5}
# print(1 in a2) # True

# 删除
a3 = {1,2,3,4,5}
a3.remove(1) # {2, 3, 4, 5} 若不存在,会报错
a3.discard(1) # {3, 4, 5}  删除指定的值 ,若该值不存在,也不会报错
a3.pop() # 随机删除一个值,并返回该值
a3.clear() # 清空所有
a3.copy() # 复制


# 交集
names1 = {'zhangsan','lisi','tom'}
names2 = {'zhangsan','lisi','jack'}
rs1 = names1 & names2 
# print(rs1) #  {'zhangsan', 'lisi'}
rs2 = names1.intersection(names2)
# print(rs2) #  {'zhangsan', 'lisi'}

# 并集
names_u1 = {'zhangsan','lisi','tom'}
names_u2 = {'zhangsan','lisi','jack'}
rs_u1 = names_u1 | names_u2 
rs_u2 = names_u1.union(names_u2) 
# print(rs_u1) # {'jack', 'tom', 'zhangsan', 'lisi'}
# print(rs_u2) # {'jack', 'tom', 'zhangsan', 'lisi'}

# 差集
names_d1 = {'zhangsan','lisi','tom'}
names_d2 = {'zhangsan','lisi','jack'}
rs_d1 = names_d1 - names_d2 
rs_d2 = names_d1.difference(names_d2)
# print(rs_d1) # {'tom'}
# print(rs_d2) # {'tom'}
rs_d3 = names_d2 - names_d1
rs_d4 = names_d2.difference(names_d1)
# print(rs_d3) # {'jack'}
# print(rs_d4) # {'jack'}

# 对称差集
names_sd1 = {'zhangsan','lisi','tom'}
names_sd2 = {'zhangsan','lisi','jack'}
rs_sd1 = names_sd1 ^ names_sd2
rs_sd2 = names_sd1.symmetric_difference(names_sd2)
# print(rs_sd1) # {'tom', 'jack'}
# print(rs_sd2) # {'tom', 'jack'}

# ⼦集、⽗集
names_s1 = {'zhangsan','lisi','tom'}
names_s2 = {'zhangsan','lisi','jack'}
names_s3 = {'zhangsan','lisi','jack','tom'}
# print(names_s1.issubset(names_s3)) # True  names_s1 是不是 names_s3的子集
# print(names_s1.issuperset(names_s3)) # False names_s1是不是 names_s3的⽗集
# print(names_s3.issuperset(names_s1)) # True names_s3 是不是 names_s1的⽗集

# 测试后修改
test_names1 = {'zhangsan','lisi','tom'}
test_names2 = {'zhangsan','lisi','jack'}
test_names1.difference_update(test_names2) # 把差集的结果赋值给test_names1
print(test_names1) # {'tom'}

二进制

⼆进制是计算技术中⼴泛采⽤的⼀种数制。⼆进制数据是⽤0和1两个数码来表示的数。它的基数为2,进位规则是“逢⼆进⼀”,由18世纪德国数理哲学⼤师莱布尼兹发现。当前的计算机系统使⽤的都是⼆进制系统,数据在计算机中主要是以补码的形式存储的。计算机中的⼆进制则是⼀个⾮常微⼩的开关,⽤“开”来表示1,“关”来表示0

⼆进制与⼗进制转换

⼆进制的第n位代表的⼗进制值都刚好遵循着2的n次⽅这个规律

填位⼤法:
先把他们代表的值依次写出来,然后再根据10进制的值把数填到相应位置,就好了。
⼗进制转⼆进制⽅法相同,只要对照⼆进制为1的那⼀位对应的⼗进制值相加就可以了。

在这里插入图片描述

⼆进制位运算

程序中的所有数在内存中都是以⼆进制的形式储存的。位运算就是直接对整数在内存中的⼆进制位进⾏操作。

下表中变量 a 为 60,b 为 13,⼆进制格式如下:

a = 0011 1100
b = 0000 1101
  • &:按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0(快记法:与运算, 位相乘)
(a & b) 输出结果 12 ,⼆进制解释: 00001100
  • |:按位或运算符:只要对应的⼆个⼆进位有⼀个为1时,结果位就为1。(快记:或运算, 位相加)
(a | b) 输出结果 61 ,⼆进制解释: 00111101
  • ^:按位异或运算符:当两对应的⼆进位相异时,结果为1(快记:位相减)
(a ^ b) 输出结果 49 ,⼆进制解释: 00110001
  • ~:按位取反运算符:对数据的每个⼆进制位取反,即把1变为0,把0变为1 。(快记:~x=-(x+1)
(~a ) 输出结果 -61 ,⼆进制解释: 11000011,在⼀个有符号⼆进制数的补码形式。
  • <<:左移动运算符:运算数的各⼆进位全部左移若⼲位,由 <<右边的数字指定了移动的位数,⾼位丢弃,低位补0。
a << 2 输出结果 240 ,⼆进制解释: 11110000
  • :右移动运算符:把">>"左边的运算数的各⼆进位全部右移若⼲位,>> 右边的数字指定了移动的位数

a >> 2 输出结果 15 ,⼆进制解释: 00001111

按位取反深⼊:https://blog.csdn.net/Coder__CS/article/details/79186677?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-8&spm=1001.2101.3001.4242

初识编码

ASCII编码

计算机只认识⼆进制,⽣活中的数字要想让计算机理解就必须转换成⼆进制。⼗进制到⼆进制的转换只能解决计算机理解数字的问题,那么⽂字要怎么让计算机理解呢?

于是我们就选择了⼀种曲线救国的⽅式,既然数字可以转换成⼗进制,我们只要想办法把⽂字转换成数字,这样⽂字不就可以表示成⼆进制了么?

在这里插入图片描述

可是⽂字应该怎么转换成数字呢?我们可以拿着⼀个数字来对⽐对应表找到相应的⽂字

在这里插入图片描述

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字⺟的⼀套电脑编码系统,主要⽤于显示现代英语和其他⻄欧语⾔。它是现今最通⽤的单字节编码系统,并等同于国际标准ISO/IEC 646。

由于计算机是美国⼈发明的,因此,最早只有127个字⺟被编码到计算机⾥,也就是⼤⼩写英⽂字⺟、数字和⼀些符号,这个编码表被称为 ASCII 编码,⽐如⼤写字⺟ A 的编码是 65 ,⼩写字⺟ z 的编码是 122 。后128个称为扩展ASCII码,主要是⼀些特殊字符。

Ord('a')
Chr(90)

如下示例:

⼀个空格对应的数字是0 翻译成⼆进制就是0(注意字符'0'和整数0是不同的)
⼀个对勾√对应的数字是251 翻译成⼆进制就是11111011

提问:假如我们要打印两个空格⼀个对勾 写作⼆进制就应该是 0011111011, 但是问题来了,我们怎么知道从哪⼉到哪⼉是⼀个字符呢?

既然⼀共就这255个字符,那最⻓的也不过是11111111⼋位,不如我们就把所有的⼆进制都转换成8位的,不⾜的⽤0来替换。

这样⼀来,刚刚的两个空格⼀个对勾就写作000000000000000011111011,读取的时候只要每次读8个字符就能知道每个字符的⼆进制值啦。

在这⾥,每⼀位0或者1所占的空间单位为bit(⽐特),这是计算机中最⼩的表示单位

每8个bit组成⼀个字节,这是计算机中最⼩的存储单位(毕竟你是没有办法存储半个字符的)

bit 位,计算机中最⼩的表示单位
8bit = 1bytes 字节,最⼩的存储单位,1bytes缩写为1B
1KB=1024B
1MB=1024KB
1GB=1024MB
1TB=1024GB
1PB=1024TB
1EB=1024PB
1ZB=1024EB
1YB=1024ZB
1BB=1024YB

计算机如何识别中文?

我们设计出了GB2312编码表,⻓成下⾯的样⼦。⼀共存了6763个汉字。
在这里插入图片描述

这个表格⽐较⼤,像上⾯的⼀块块的⽂字区域有72个,这导致通过⼀个字节是没办法表示⼀个汉字的(因为⼀个字节最多允许256个字符变种,你现在6千多个,只能2个字节啦,2**16=65535个变种)。

如何区别连在⼀起的2个字节是代表2个英⽂字⺟,还是⼀个中⽂汉字呢? 中国⼈如此聪明,决定,如果2个字节连在⼀起,且每个字节的第1位(也就是相当于128的那个2进制位)如果是1,就代表这是个中⽂,这个⾸位是128的字节被称为⾼字节。也就是2个⾼字节连在⼀起,必然就是⼀个中⽂。你怎么如此笃定?因为0-127已经表示了英⽂的绝⼤部分字符,128-255是ASCII的扩展表,表示的都是极特殊的字符,⼀般没什么⽤。所以中国⼈就直接拿来⽤了

⾃1980年发布gb2312之后,中⽂⼀直⽤着没啥问题,随着个⼈电脑进⼊千家万户,有⼈发现,⾃⼰的名字竟然打印不出来,因为起的太⽣僻了。

于是1995年, 砖家们⼜升级了gb2312, 加⼊更多字符,连什么藏语、维吾尔语、⽇语、韩语、蒙古语什么的统统都包含进去了,国家统⼀亚洲的ᰀ⼼从这些基础⼯作中就可⻅⼀斑哈。 这个编码叫GBK,⼀直到现在,我们的windows电脑中⽂版本的编码就是GBK.

Unicode编码

中国⼈在搞⾃⼰编码的同时,世界上其它⾮英语国家也得⽤电脑呀,于是都搞出了⾃⼰的编码,你可以想得到的是,全世界有上百种语⾔,⽇本把⽇⽂编到Shift_JIS⾥,韩国把韩⽂编到Euc-kr⾥。

ISO(国际标谁化组织)的国际组织决定着⼿解决这个问题。他们采⽤的⽅法很简单:废了所有的地区性编码⽅案,᯿新搞⼀个包括了地球上所有⽂化、所有字⺟和符号 的编码!他们打算叫它”Universal Multiple-Octet Coded Character Set”,简称 UCS, 俗称 “unicode“。

Unicode把所有语⾔都统⼀到⼀套编码⾥,这样就不会再有乱码问题了。Unicode 2-4字节 已经收录136690个字符,并还在⼀直不断扩张中…

Unicode标准也在不断发展,但最常⽤的是⽤两个字节表示⼀个字符(如果要⽤到⾮常偏僻的字符,就需要4个字节)

Unicode有2个特点:

  • ⽀持全球所有语⾔
  • 包含跟各种语⾔的映射关系,所以可以跟各种语⾔的编码⾃由转换,也就是说,即使你gbk编码的⽂字 ,想转成unicode很容易。

为何unicode可以跟其它语⾔互相转换呢? 因为有跟所有语⾔都有对应关系哈,这样做的好处是可以让那些已经⽤gbk或其它编码写好的软件容易的转成unicode编码 ,利于unicode的推⼴。 下图就是unicode跟中⽂编码的对应关系:

在这里插入图片描述

UTF-8

帝国(unicode)统⼀后,新的问题⼜出现了:如果统⼀成Unicode编码,乱码问题从此消失了。但是,如果你写的⽂本基本上全部是英⽂的话,⽤Unicode编码⽐ASCII编码需要多⼀倍的存储空间,由于计算机的内存⽐较⼤,并且字符串在内容中表示时也不会特别⼤,所以内容可以使⽤unicode来处理,但是存储和⽹络传输时⼀般数据都会⾮常多,且互联⽹刚出现时,⽹速⼜慢,这个数据占⽤空间⼤⼀倍将是⽆法容忍的。

为了解决存储和⽹络传输的问题,出现了Unicode Transformation Format,学术名UTF,即:对unicode字符进⾏转换,以便于在存储和⽹络传输时可以节省空间!

  • UTF-8: 使⽤1、2、3、4个字节表示所有字符;优先使⽤1个字符、⽆法满⾜则使增加⼀个字节,最多4个字节。英⽂占1个字节、欧洲语系占2个、东亚占3个,其它及特殊字符占4个
  • UTF-16: 使⽤2、4个字节表示所有字符;优先使⽤2个字节,否则使⽤4个字节表示。
  • UTF-32: 使⽤4个字节表示所有字符;

注意:UTF 是为unicode编码 设计 的⼀种 在存储 和传输时节省空间的编码⽅案,它是Unicode的⼀种实现⽅式.

如果你要传输的⽂本包含⼤ᰁ英⽂字符,⽤UTF-8编码就能节省空间:

在这里插入图片描述

从上⾯的表格还可以发现,UTF-8编码有⼀个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的⼀部分,所以,⼤量只⽀持ASCII编码的历史遗留软件可以在UTF-8编码下继续⼯作。

搞清楚了ASCII、Unicode和UTF-8的关系,我们就可以总结⼀下现在计算机系统通⽤的字符编码⼯作⽅式:

在这里插入图片描述

unicode官⽹:https://home.unicode.org/
unicode 中⽂表: http://www.chi2ko.com/tool/CJK.htm

常⽤编码介绍⼀览表

在这里插入图片描述

py2 vs py3 编码区别

  • py2默认ASCII
  • py3默认unicode,文件编码utf-8

py2写中⽂的正确姿势,在代码⽂件第⼀⾏,做声明,告诉py解释器,后⾯的代码是⽤utf-8编码的,你⽤utf-8编码来解析它

# -*- encoding:utf-8 -*-
name = "张三"
print(name)

不过注意如果你的电脑 是windows系统 , 你的系统默认编码是GBK ,你声明的时候要声明成GBK, 不能是utf-8, 否则依然是乱码,因为gbk⾃然不认识utf-8。

到了Py3推出后,终于把默认编码改成了unicode, 同时⽂件存储编码变成了utf-8,意味着,不⽤任何声明,你就可以写各种语⾔⽂字在你的Python程序⾥。

⼗六进制

16进制,英⽂名称Hexadecimal(简写Hex), 在数学中是⼀种逢16进1的进位制。⼀般⽤数字0到9和字⺟A到F(或 a~f )表示,其中: A~F 表示10~15,这些称作⼗六进制数字,⽐如⼗进制13⽤16进制表示是D, 28⽤16进制是1C。

0 1 2 3 4 5 6 7 8 9  A  B  C  D  E  F
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

每个16进制,占4-bit, 所以要⽤16进制来表示⼀个字节的话,正好2个16进制数字就可以啦

⽐如拿234这个数来算:

在这里插入图片描述

展示起来,更简洁,应该是16进制在计算机⾥被⼴泛应⽤的主要原因.

16进制在计算机领域应⽤普遍,常⻅的有html\css的颜⾊表、mac地址、字符编码等都⽤16进制来表示。 这是因为将4个位元(Bit)化成单独的16进制数字不太困难。1字节可以表示成2个连续的16进制数字, 也可以表示8个2进制数。这种混合表示法就容易令⼈混淆,因此需要⼀些字⾸、字尾或下标来显示这个值到底是16进制还是2进制 ,所以在C语⾔、C++、Shell、Python、Java语⾔及其他相近的语⾔使⽤字⾸“0x”来标示16进制,例如“0x5A3”代表1443。

在这里插入图片描述

示例:

a = hex(234)
print(a) # 0xea

三元运算

⼜称三⽬运算,是对if…else…的⼀种简写

假设现在有两个数字,我们希望获得其中较⼤的⼀个,那么可以使⽤ if else 语句,例如:

if a>b: 
 max = a
else: 
 max = b

⽤三元运算:

max = a if a > b else b

上⾯语句的含义是:

  • 如果 a>b 成⽴,就把 a 作为整个表达式的值,并赋给变ᰁ max;
  • 如果 a> b 不成⽴,就把 b 作为整个表达式的值,并赋给变ᰁ max.

三元嵌套

Python 三元运算符⽀持嵌套,就可以构成更加复杂的表达式。在嵌套时需要注意 if 和 else 的配对,例如:

>>> a,b,c,d = 3,5,7,9
>>>
>>> a if a > b else c if c > d else d
9

应该理解为:

 a if a > b else (c if c > d else d)

函数

函数的定义

def sayhello(name):
    print('hello',name)

sayhello('张三')

函数的返回值

def mobile_check(phone_num):
    if len(phone_num) == 11:
        if phone_num.isdigit():
            if phone_num.startswith('1'): # 1开头
                return True

s = '13651054609'
if mobile_check(s): # 结果是True
    print("合法手机号...")

特点:

  • 默认返回值就None,
  • 可返回任意数据类型
  • 可返回多个值

函数返回多个值:

def stu_registriation_form():
    form = {
        "name": input("Name:").strip(),
        "age": input("Age:").strip(),
        "phone": input("Phone:").strip()
    }

    info_pass_flag = True  # 如果字段全填了,就是True
    for k, v in form.items():
        if len(v) == 0:  # 没写东西
            info_pass_flag = False
            break

    return form, info_pass_flag


stu_info, flag = stu_registriation_form() # 接收2个值 
print(stu_info)
print(flag)

函数传值类型

传值类型:可以把任意值做为参数传递给函数,这些值可整体分为2种,可变类型、不可类型,2种值传给函数,在函数里修改时,产生的效果不同

  • 不可变类型做参数:在函数内修改外部传进来的不可变类型时, 会在函数内部生成一个该参数的copy , 并不会影响原来函数外部的值
  • 可变类型做参数:可变类型,如列表、dict, 传到函数内部,其实只是传递了该列表\dict的整体内存地址,函数内部可直接修改函数外部的这个list or dict

示例:

def change_data(name,hobbies):
    name = "zhangsan"   # 修改只在函数内生效
    hobbies.append("wangwu")  # 在函数内往外部列表添加值 
    hobbies[1] = "dog"   # 修改列表元素
    print("in func:",name,hobbies)


my_name = "张三" # 不可变类型
my_hobbies = ["Money","Cat"] # 可变类型
change_data(my_name,my_hobbies)
print(my_name,my_hobbies) # 张三 ['Money', 'dog', 'wangwu']

从上面打印结果可以看出:列表被函数修改了,而外面的字符串并无变化

参数类型-位置参数和关键参数

必备参数(位置参数)
  • 必备,不传值会报错
  • 传的值是有顺序的,从左到右,每个参数一一对应
关键字参数
  • 赋值时指定参数名,不按位置顺序了
  • 如果和必备参数混用,必须放在位置参数后边
def stu_form(name, age, major, phone):
    info = f'''
    Name : {name},
    Age  : {age},
    Major: {major},
    Phone: {phone}
    '''
    print(info)
stu_form(major="Computer Science", name="zhangsan", phone=11000000000, age=22)

打印结果:


    Name : zhangsan,
    Age  : 22,
    Major: Computer Science,
    Phone: 11000000000

和位置参数混用
def stu_form(name, age, major, phone):
    info = f'''
    Name : {name},
    Age  : {age},
    Major: {major},
    Phone: {phone}
    '''
    print(info)
stu_form('zhangsan',22,phone=1100000000,major="Computer Science") # 和位置参数混用

参数类型-默认参数&不定长参数

默认参数

对于一些调用时非必选的参数,可设置成默认参数,这样,即使用户不填,也不影响函数正常运行.

def stu_form(name, age, major, phone, nationality='CN'):
    info = f'''
    Name : {name},
    Age  : {age},
    Major: {major},
    Phone: {phone},
    Nation: {nationality}
    '''
    print(info)


stu_form( "zhangsan",  major="IT", age=25, phone='1334444')
不定长参数

有时, 我们在设计函数时,可能只定了固定数量的参数, 但过了一段时间,有新需求了,需要再加2个参数,这时候你就要改源代码,一改源代码就需要重新进行测试环境、预生成环境的各种严格的测试流程,没问题后,再能再重新部署到生产系统。 如果能一开始设计时就留好后期扩展的空间,就省事了,也提高了程序的可扩展性。

这就可用不定长参数来实现, 共2种方式,*args 和**kwargs

  • 1.*args 元组传值:多给的值 ,都会给到 *args 参数里,以元组形式。
def stu_form(name, age, major, phone, nationality='CN',*args):
    info = f'''
    Name : {name},
    Age  : {age},
    Major: {major},
    Phone: {phone},
    Nation: {nationality}
    '''
    print(info)
    print("不定长列表参数:",args)


stu_form("zhangsan",23,"Finance",15510777777,"US",'lili','Movies') #多写了最后2个参数

输出结果:


    Name : zhangsan,
    Age  : 23,
    Major: Finance,
    Phone: 15510777777,
    Nation: US

不定长列表参数: ('lili', 'Movies')
  • 2.**kwargs 字典传值:接收多余的关键字参数,并以dict形式给到kwargs
def stu_form(name, age, major, phone, nationality='CN',*args,**kwargs):
    info = f'''
    Name : {name},
    Age  : {age},
    Major: {major},
    Phone: {phone},
    Nation: {nationality}
    '''
    print(info)
    print("不定长列表参数args:",args)
    print("不定长列表参数kwargs:",kwargs)

stu_form("zhangsan",23,"Finance",15510099999,"US",'Alex','Movies', hometown="HeNan",university="BeiDaQingNiao") # 多写了hometown, university 2个指定参数

输出结果:


    Name : zhangsan,
    Age  : 23,
    Major: Finance,
    Phone: 15510099999,
    Nation: US

不定长列表参数args: ('Alex', 'Movies')
不定长列表参数kwargs: {'hometown': 'HeNan', 'university': 'BeiDaQingNiao'}
  • 3.直接传列表or dict
    接按下面这种方式 传也可以, 但要加上* 和**符号, 输出效果跟上面一样。
def stu_form(name, age, major, phone, nationality='CN',*args,**kwargs):
    info = f'''
    Name : {name},
    Age  : {age},
    Major: {major},
    Phone: {phone},
    Nation: {nationality}
    '''
    print(info)
    print("不定长列表参数args:",args)
    print("不定长列表参数kwargs:",kwargs)

info = {'hometown':"河南",'university':"北大青鸟"}
hobbies = ["lili",'Movies',"LiveHouse"]
stu_form("zhangsan",23,"Finance",15510099999,"US",*hobbies,**info) 

函数嵌套

def stu_form():

    form = {
        "name": input("Name:").strip(),
        "age": input("Age:").strip(),
        "major": input("Major:").strip(),
        "phone": input("Phone:").strip()
    }

    print(form)
    # 下面边个子函数,是写了一个可以改form dict值 的功能
    def change_form(form_data):  # 这个函数只能在stu_form内调用
        print(form_data.keys())
        print("--------------修改信息--------------")
        while True:
            key = input("输入要改的key>:").strip()
            if not key:continue
            if key in form_data.keys():
                print(f"({key})的当前值{form_data[key]}")
                key_new_val = input("输入要改的新值:").strip()
                form_data[key] = key_new_val
                break
            else:
                print("不合法的key...")

    change_form(form) # 内部调用 
    print("new form:",form) 

    return form

stu_form()

全局变量 VS 局部变量

在函数内部声明的变量叫局部变量, 它只在函数内部生效,函数执行结束后,该变量也行将消亡

def change_name():
    name = "lisi" # 局部变量,只在函数内部生效
    print("in func:", name)

name = "张三"  # 全局变量, 整个代码文件全局生效

change_name()
print("global var:",name)

输出结果:

in func: lisi
global var: 张三

为什么在函数内部改了name的值后, 在外面print的时候却没有改呢? 因为这两个name根本不是一回事

  • 在函数中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
  • 全局变量作用域(即有效范围)是整个程序,局部变量作用域是定义该变量的函数。
  • 变量的查找顺序是局部变量>全局变量
  • 当全局变量与局部变量同名时,在定义局部变量的函数内,局部变量起作用;在其它地方全局变量起作用。
  • 在函数里是不能直接修改全局变量的

目前函数内部的name变量, 和外部的name没任何关系 , 是存活在2个内存空间里的。

如果想在函数内部,修改外面的name变量怎么办呢?

globa声明全局变量

globa 语法告诉解释器, 我要在函数内部引用并修改全局变量

def change_name():
    global name # 声明要引用全局变量
    name = "lisi" # 局部变量,只在函数内部生效
    print("in func:", name)

name = "张三"  # 全局变量, 整个代码文件全局生效

输出结果:

in func: lisi
global var: lisi

匿名函数lambda

匿名函数就是不需要显式的指定函数名的函数

func = lambda x,y:x*y  
res = func(2,3)
print(res) # 6

相当于传统函数

def func(x,y):
  return x*y 

注意lambda后边的代码,一般只写一行,不能像传统函数一样,写很多行。

匿名函数有啥用?

就是为了省事,有的时候 只为了实现个简单的功能,懒得再单独写一个函数,就可用匿名函数。 一般会搭配在各种其它方法里使用。

示例,结合内置函数map的使用:

def add_one(n):
  return n+1
li = [9,11,2,3,4,8,19,12,30]
print(list(map(add_one, li))) # 给列表里每个值+1 , 用传统函数

print(list(map(lambda n:n+1, li))) # 给列表里每个值+1

打印结果:

[10, 12, 3, 4, 5, 9, 20, 13, 31]
[10, 12, 3, 4, 5, 9, 20, 13, 31]

高阶函数

变量可以指向函数名,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

只需满足以下任意一个条件,即是高阶函数:

  • 接受一个或多个函数作为输入
  • return 返回另外一个函数

示例:

def get_abs(n):
    if n < 0 :
        n = int(str(n).strip("-"))
    return n
  
def add(x,y,f):
    return f(x) + f(y)
res = add(3,-6,get_abs)
print(res) # 9

函数的递归

如下示例,求100不断除以2直到商为0为止,打印每次除的商, 用循环实现:

n = 100
while n > 0:
    n = int(n/2)
    print(n)

输出结果:

50
25
12
6
3
1
0

用函数实现:

def divide_calc(n):
    print(n)
    if n > 0 :
        divide_calc(int(n/2))
    return n
res = divide_calc(10)
print('结果:',res)

结果:

10
5
2
1
0
结果: 10

函数在每进入下一层的时候,当前层的函数并未结束,它必须等它调用的下一层函数执行结束返回后才能继续往下走。 所以最下面的那句return n会等最里层的函数执行时才会执行,然后不断往外退层,所以最后一次的return n执行的是最外层调用函数的, 那个n一开始就是10

递归特性:

  • 必须有一个明确的结束条件()
  • 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  • 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

递归在特定场景下还是挺有用的,以后学的一些算法就得用到递归,比如堆排、快排等.

练习:用递归实现2分查找的算法,以从列表 a = [1,3,4,6,7,8,9,11,15,17,19,21,22,25,29,33,38,69,107] 查找指定的值。

def b_search(start,end,li,find_n):

    mid_index = int( (start + end ) / 2 ) # 每次找到列表中间的位置的索引
    if len(li[start:end]) == 1: # 碰头了,查完了
        if li[start] != find_n: # 完了,找不到了
            print("找不到该值.")
            return
        else:
            print("找到了,",li[start])
            return
    if li[mid_index] > find_n: # the val you looking for should be in the left part
        print("去左边一半的数据里查:",li[mid_index], li[start:mid_index])
        b_search(start,mid_index,li,find_n)
    else: # val in right
        print("去右边一半的数据里查:",li[mid_index], li[mid_index:end])
        b_search(mid_index,end,li,find_n)

b_search(0,len(a)-1,a,38)

打印结果:

去右边一半的数据里查: 17 [17, 19, 21, 22, 25, 29, 33, 38, 69]
去右边一半的数据里查: 25 [25, 29, 33, 38, 69]
去右边一半的数据里查: 33 [33, 38, 69]
去右边一半的数据里查: 38 [38, 69]
去左边一半的数据里查: 69 [38]
找到了, 38

内置函数

abs # 求绝对值
all #Return True if bool(x) is True for all values x in the iterable.If the iterable is empty, return True.
any #Return True if bool(x) is True for any x in the iterable.If the iterable is empty, return False.
ascii #Return an ASCII-only representation of an object,ascii(“中国”) 返回”‘\u4e2d\u56fd’”
bin #返回整数的2进制格式
bool # 判断一个数据结构是True or False, bool({}) 返回就是False, 因为是空dict
bytearray # 把byte变成 bytearray, 可修改的数组
bytes # bytes(“中国”,”gbk”)
callable # 判断一个对象是否可调用
chr # 返回一个数字对应的ascii字符 , 比如chr(90)返回ascii里的’Z’
classmethod #面向对象时用,现在忽略
compile #py解释器自己用的东西,忽略
complex #求复数,一般人用不到
delattr #面向对象时用,现在忽略
dict #生成一个空dict
dir #返回对象的可调用属性
divmod #返回除法的商和余数 ,比如divmod(4,2),结果(2, 0)
enumerate #返回列表的索引和元素,比如 d = [“alex”,”jack”],enumerate(d)后,得到(0, ‘alex’) (1, ‘jack’)
eval #可以把字符串形式的list,dict,set,tuple,再转换成其原有的数据类型。
exec #把字符串格式的代码,进行解义并执行,比如exec(“print(‘hellworld’)”),会解义里面的字符串并执行
exit #退出程序
filter #对list、dict、set、tuple等可迭代对象进行过滤, 例子:filter(lambda x:x>10,[0,1,23,3,4,4,5,6,67,7])过滤出所有大于10的值
float #转成浮点
format #没用
frozenset #把一个集合变成不可修改的
getattr #面向对象时用,现在忽略
globals #打印全局作用域里的值
hasattr #面向对象时用,现在忽略
hash #hash函数
help
hex #返回一个10进制的16进制表示形式,hex(10) 返回’0xa’
id #查看对象内存地址
input
int
isinstance #判断一个数据结构的类型,比如判断a是不是fronzenset, isinstance(a,frozenset) 返回 True or False
issubclass #面向对象时用,现在忽略
iter #把一个数据结构变成迭代器,讲了迭代器就明白了
len
list
locals  # 打印所有的局部变量
map # map(lambda x:x**2,[1,2,3,43,45,5,6,]) 输出 [1, 4, 9, 1849, 2025, 25, 36]
max # 求最大值
memoryview # 一般人不用,忽略
min # 求最小值
next # 生成器会用到,现在忽略
object #面向对象时用,现在忽略
oct # 返回10进制数的8进制表示
open
ord # 返回ascii的字符对应的10进制数 ord(‘a’) 返回97,
print
property #面向对象时用,现在忽略
quit
range
repr #没什么用
reversed # 可以把一个列表反转
round #可以把小数4舍5入成整数 ,round(10.15,1) 得10.2
set
setattr #面向对象时用,现在忽略
slice # 没用
sorted # 
staticmethod #面向对象时用,现在忽略
str
sum #求和,a=[1, 4, 9, 1849, 2025, 25, 36],sum(a) 得3949
super #面向对象时用,现在忽略
tuple 
type
vars #返回一个对象的属性,面向对象时就明白了
zip #可以把2个或多个列表拼成一个, a=[1, 4, 9, 1849, 2025, 25, 36],b = [“a”,”b”,”c”,”d”],
  list(zip(a,b)) #得结果 
  [(1, 'a'), (4, 'b'), (9, 'c'), (1849, 'd')]

示例:

# abs 求绝对值
#print(abs(-1)) # 1

# all 判断是否所有元素都为真
# print(all([1, 2, 3])) # True
# print(all([1, 2, 0])) # False
# print(all([1, 2, ''])) # False
# print(all([1, 2, None])) # False
# print(all([1, 2, False])) # False
# print(all([1, 2, True])) # True

# any 判断是否至少有一个元素为真
# print(any([1, 2, 3])) # True
# print(any([1, 2, 0])) # True
# print(any([1, 2, ''])) # True
# print(any([1, 2, None])) # True
# print(any([1, 2, False])) # True
# print(any([1, 2, True])) # True

# bin 返回一个整数的二进制表示形式的字符串
# print(bin(10))  # 输出: 0b1010  
# print(bin(15))  # 输出: 0b1111  
# print(bin(255)) # 输出: 0b11111111

# bool 返回一个布尔值
# print(bool(0)) # 输出: False
# print(bool(1)) # 输出: True


# bytearray 把byte变成 bytearray, 可修改的数组
# b_array = bytearray(b'abc')
# print(b_array[0]) # 输出: 97
# b_array[0] = 98 # 修改
# print(b_array) # bytearray(b'bbc')

# bytes bytes(“中国”,”gbk”)
# s = '中国'
# res1 = s.encode(encoding = 'gbk')
# print(res1) # b'\xd6\xd0\xb9\xfa'
# res2 = bytes(s, 'gbk')
# print(res2) # b'\xd6\xd0\xb9\xfa'


# callable # 判断一个对象是否可调用
# print(callable(print)) # 输出: True
# print(callable('中国')) # 输出: False



# chr # 返回一个数字对应的ascii字符 , 比如chr(90)返回ascii里的’Z’
# print(chr(90)) # 输出: Z
# print(chr(65)) # 输出: A
# print(chr(97)) # 输出: a

# ord # 返回一个字符对应的ascii数字,比如ord('A')返回65
# print(ord('A')) # 输出: 65
# print(ord('Z')) # 输出: 90
# print(ord('a')) # 输出: 97
# print(ord('z')) # 输出: 122

# dict #生成一个空dict
# dir #返回对象的可调用属性
# divmod #返回除法的商和余数 ,比如divmod(4,2),结果(2, 0)

# enumerate #返回列表的索引和元素
# 示例1:枚举列表中的元素及其索引  
# lst = ['a', 'b', 'c', 'd']  
# for index, value in enumerate(lst):  
#     print(f"Index: {index}, Value: {value}")  
# 结果:
# Index: 0, Value: a
# Index: 1, Value: b
# Index: 2, Value: c
# Index: 3, Value: d

# eval #可以把字符串形式的list,dict,set,tuple,再转换成其原有的数据类型。
# print(eval('[1,2,3]')) # 输出: [1, 2, 3]
# print(eval('{1:2,3:4}')) # 输出: {1: 2, 3: 4}


# exec #把字符串格式的代码,进行解义并执行,比如exec(“print(‘hellworld’)”),会解义里面的字符串并执行
# exec("print('helloworld')") # 输出: helloworld
# exec("print(a)") # 输出: a

# exit #退出程序

#filter #对list、dict、set、tuple等可迭代对象进行过滤
#  示例:过滤出所有大于10的值
# res = filter(lambda x:x>10,[0,1,23,3,4,4,5,6,67,7])
# print(list(res)) # 输出: [23, 67]

# float #转成浮点
# print(float(1)) # 输出: 1.0
# print(float(1.1)) # 输出: 1.1
# print(float('1.1')) # 输出: 1.1
# print(float('1')) # 输出: 1.0


# frozenset #把一个集合变成不可修改的
# s = {1, 2, 3}
# res = frozenset(s)
# print(res)
# res.add(4) #  报错:'frozenset' object has no attribute 'add'

# globals 打印全局作用域里的值
# locals  打印所有的局部变量
# def test():
#     a = 1
#     b = 2
#     c = 3
#     # print(globals())
#     print(locals()) # {'a': 1, 'b': 2, 'c': 3}
# test()


# hash #hash函数
# hex #返回一个10进制的16进制表示形式,hex(10) 返回’0xa’
# print(hex(10)) # 输出: 0xa
# print(hex(1)) # 输出: 0x1
# print(hex(11)) # 输出: 0xb

# id #查看对象内存地址

# isinstance 判断一个数据结构的类型,比如判断a是不是fronzenset, isinstance(a,frozenset) 返回 True or False
# a = {1, 2, 3}
# print(isinstance(a, set)) # True
# print(isinstance(a, frozenset)) # False


# min # 求最小值
# max # 求最大值

# reversed 可以把一个列表反转
# lst = [1, 2, 3, 4, 5]
# res = reversed(lst)
# print(list(res)) # [5, 4, 3, 2, 1]
# str = 'abc'
# res = list(reversed(str))
# print(res) # ['c', 'b', 'a']
# print(str[::-1]) # cba

# round #可以把小数4舍5入成整数 ,round(10.15,1) 得10.2
# print(round(10.15, 1)) # 输出: 10.2
# print(round(10.15, 2)) # 输出: 10.15
# print(round(10.15, 3)) # 输出: 10.15
# print(round(10.15, 4)) # 输出: 10.15
# print(round(10.15, 5)) # 输出:10.15


# sorted #对list、dict、set、tuple等可迭代对象进行排序
# 示例:对列表进行排序
# lst = [3, 1, 2, 4, 5]
# res = sorted(lst)
# print(res) # [1, 2, 3, 4, 5]
# #示例:对字典进行排序
# d = {'b': 2, 'a': 1, 'c': 3}
# res = sorted(d.items())
# print(res) # [('a', 1), ('b', 2), ('c', 3)]

# 示例2,我们以成绩进行排序
# scores = [
#   ['zhangsan',99],
#   ['lisi',39],
#   ['tom', 89],
#   ['jack', 59]
# ]
# res = sorted(scores, key=lambda x:x[1],reverse=True)
# print(res) # [['zhangsan', 99], ['tom', 89], ['jack', 59], ['lisi', 39]]

# sum #求和,a=[1, 4, 9, 1849, 2025, 25, 36],sum(a) 得3949

# zip #可以把2个或多个列表拼成一个
# a = [1, 4, 9, 1849, 2025, 25, 36]
# b = ['a','b','c','d']
# print(list(zip(a,b))) # [(1, 'a'), (4, 'b'), (9, 'c'), (1849, 'd')]
# 从上面结果可以看出,zip函数把a和b中的元素一一对应起来,然后生成一个元组,然后生成一个列表,然后返回。

# compile 编译
# f = open("函数递归.py")
# data =compile(f.read(),'','exec')
# exec(data) 

# print
# msg = "又回到最初的起点"
# f = open("tofile","w")
# print(msg,"记忆中你青涩的脸",sep="|",end="",file=f)

⽂件操作

对⽂件的操作有2种,⽂本⽂件、⼆进制⽂件(视频、图⽚等)

open⽅法基本使⽤

open(file, mode='r', encoding=None)

⼏种打开模式:

'r' open for reading (default)
'w' open for writing, truncating the file first(写模式,如果⽂件 在,先清空【危险】)
'x' create a new file and open it for writing(创建模式:如果⽂件在,会报错)
'a' open for writing, appending to the end of the file if it exists(⽇志)
'b' binary mode(2进制模式)
't' text mode (default) (⽂本)
'+' open a disk file for updating (reading and writing)

注:The default mode is ‘rt’ (open for reading text)

⼀个⽂件对象被open⽅法创建后,这个对象可⽤的有下⾯这些方法:

close       关闭⽂件
closed      查看⽂件是否已关闭
encoding    返回⽂件的编码
flush       把缓存⾥的写⼊的数据强制刷新硬盘
isatty      返回⽂件是否是'interactive'数据流,⽐如是个命令⾏终端,(在unix系统,⼀切皆⽂件)
mode        返回当前⽂件模式
name        返回⽂件名
read        读指定⻓度的内容,f.read(1024) 读1024字节, 不指定参数的话,就读所有内容
readable    ⽂件是否可读
readline    读⼀⾏
readlines   读所有,每⾏列表形式返回
seek        把光标移到指定位置
seekable    该⽂件光标是否可移动
tell        返回当前光标位置
truncate    截断⽂件, f.truncate(100), 从⽂件 开头截断100个字符,后边的都扔掉
writable    是否可写
write       写内容
writelines  把⼀个列表写⼊,每个元素是⼀⾏

创建模式:创建⽂件

f = open("contacts.txt", 'w') # 创建⼀个⽂件对象(⽂件句柄),存为变量f
f.write("zhangsan 133332") # 写⼊
f.write("zhangsan 133332")
f.close() # 关闭这个⽂件
f.write('dddd') # 关闭后,没办法再写⼊了

注意:在 w 模式是创建⼀个⽂件 ,但若该⽂件 已存在,则会清空原⽂件,如果不⾏清空原⽂件,安全起⻅,⽤ x 模式,
若原⽂件存在,会报错,不会直接清空它

读模式:循环读取⽂件&查找

如下有一个model_contacts.txt文件,文件内容如下:

姓名 地区 身⾼ 体重 电话
况咏蜜 北京 171 48 13651054608
王⼼颜 上海 169 46 13813234424
⻢纤⽻ 深圳 173 50 13744234523
乔亦菲 ⼴州 172 52 15823423525
罗梦⽵ 北京 175 49 18623423421
刘诺涵 北京 170 48 18623423765
岳妮妮 深圳 177 54 18835324553
贺婉萱 深圳 174 52 08933434452
叶梓萱 上海 171 49 18042432324
杜姗姗 北京 167 49 13324523342

按⾏读取&循环:

f = open('../../gitee/python/file/model_contacts.txt','rt',encoding='utf-8') # 默认rt模式
# data = f.read() # 读取所有内容
# print(data)
print(f.readline()) # 读取一行
print(f.readline()) # 读取二行
print(f.readline()) # 读取三行

print('----循环读后⾯的-----')
for line in f:
 print(f.readline())

结果如下:

姓名 地区 身⾼ 体重 电话

况咏蜜 北京 171 48 13651054608

王⼼颜 上海 169 46 13813234424

----循环读后⾯的-----
乔亦菲 ⼴州 172 52 15823423525

刘诺涵 北京 170 48 18623423765

贺婉萱 深圳 174 52 08933434452

杜姗姗 北京 167 49 13324523342

打开⽂件后,光标位置在⽂件开头,每读⼀⾏,光标向下移动⼀⾏,因此可以⼀⾏⾏的往后读,已读了的内容不会重复被读
取。

读取指定字符个数:

f = open('../../gitee/python/file/model_contacts.txt','rt',encoding='utf-8') # 默认rt模式
print(f.read(2)) # 读取2个字符  姓名

注意:在⽂本模式下,这个2是代表2个字符,在2进制模式,这个2是指2个字节

⽂件⾥查找内容:

要想在⽂件内找某个词,并打印出所在⾏,只能循环⼀遍⽂件,每⾏依次判断⼀下

for line in f:
 if "梦⽵" in line:
    print(line) # 罗梦⽵ 北京 175 49 18623423421

追加模式

只会往⽂件最后追加,⼀般⽤于写⽇志的场景

f.write("张三 北京 165 50 18834252322\n")
f.write("张三 北京 165 50 18834252322\n")

最终,我们看到txt文件的内容新增了2条:

姓名 地区 身⾼ 体重 电话
况咏蜜 北京 171 48 13651054608
王⼼颜 上海 169 46 13813234424
⻢纤⽻ 深圳 173 50 13744234523
乔亦菲 ⼴州 172 52 15823423525
罗梦⽵ 北京 175 49 18623423421
刘诺涵 北京 170 48 18623423765
岳妮妮 深圳 177 54 18835324553
贺婉萱 深圳 174 52 08933434452
叶梓萱 上海 171 49 18042432324
杜姗姗 北京 167 49 13324523342
张三 北京 165 50 18834252322
张三 北京 165 50 18834252322

注意: 追加模式,即使通过f.seek()把光标移到其它位置 ,再f.write()的时候 ,依然是写到最后的。但是f.seek(10),然后再f.truncate(),会实现⽂件截断,只保留10个字符

flush、seek、tell、truncate

flush:把缓存⾥的写⼊的数据强制刷新硬盘

f = open('flush_txt.txt','w',encoding='utf-8') 
f.write('helloworld welcome to python\n')
f.write('helloworld welcome to python\n')
f.flush()

最后生成一个flush_txt.txt文件,文件内容如下:

f = open('flush_txt.txt','w',encoding='utf-8') 
f.write('helloworld welcome to python\n')
f.write('helloworld welcome to python\n')
f.flush()
  • seek 把光标移到指定位置
  • tell 返回当前光标位置
  • truncate 截断⽂件, f.truncate(100), 从⽂件 开头截断100个字符,后边的都扔掉(默认不传值,就是从光标后面的内容都被截断)
f = open('truncate_txt.txt','w',encoding='utf-8') 
f.write('helloworld welcome to python\n')
f.write('helloworld welcome to python\n')
f.seek(10)
print(f.tell()) # 10
f.truncate() # 结果truncate_txt.txt文件内容只剩下 helloworld

修改文件

r+是修改模式

直接调⽤f.write(),会从开头开始写, 然后会往后覆盖… 如果只覆盖了后边某个⽂字的⼀半,就会出现 乱码

seek是移动字节
tell返回字节数

想把数据源⾥的 罗梦⽵ 换成 张三呀123 , 怎么搞?

例如update.txt文件:

姓名 地区 身⾼ 体重 电话
况咏蜜 北京 171 48 13651054608
王⼼颜 上海 169 46 13813234424
⻢纤⽻ 深圳 173 50 13744234523
乔亦菲 ⼴州 172 52 15823423525
罗梦⽵ 北京 175 49 18623423421
刘诺涵 北京 170 48 18623423765
岳妮妮 深圳 177 54 18835324553
贺婉萱 深圳 174 52 08933434452
叶梓萱 上海 171 49 18042432324
杜姗姗 北京 167 49 13324523342

update.py:

f = open('../../gitee/python/file/update.txt', 'r+',encoding='utf-8')

data = f.read()

# 备份
back_file = open('update.txt.bak','w',encoding='utf-8')
back_file.write(data)
back_file.close()

# 更新
data_new = data.replace('罗梦⽵','张三呀123')
f.seek(0) # 光标移到0
f.truncate() # 清空
f.write(data_new)  # 写⼊新内容
f.close()

# 删除
import os
os.remove('update.txt.bak')

处理不同编码的文件

比如我在mac系统打开window编码的gbk文件,给open⽅法也指定 encoding=“gbk” ,这样,就会按gbk来读⽂件内容:

f = open("from_win/file_gbk2.txt",'r',encoding="gbk")
print(f.read())

2进制模式与编解码

遇到图⽚、视频等⾮⽂本⽂件, 该如何处理呢?直接⽤⽂本模式操作的话,会报错.

因为什么utf-8、gbk呀,只是⽂本的编码,肯定不适⽤于图⽚。

⼆进制读⽂件

所以处理⾮⽂本⽂件,就可直接⽤⼆进制模式,以2进制制形式读取数据,不进⾏解码…

f = open('../../gitee/python/file/icon.jpg', 'rb')

for line in f:
  print(line)

打印结果:

b'\n'
b'\t\x08\t\t\n'
b'\x0c\x0f\x0c\n'
b'\x0b\x0e\x0b\t\t\r\x11\r\x0e\x0f\x10\x10\x11\x10\n'
b'\x0c\x12\x13\x12\x10\x13\x0f\x10\x10\x10\xff\xdb\x00.....

打印这个图⽚的内容看到,都是字节类型。

⼆进制写⽂件

当以2进制模式创建⼀个⽂件时,那你只能写⼆进制数据,不能写⽂本啦

f = open('../../gitee/python/file/二进制写文件.txt', mode='wb')
s = '你好,中国'

s_utf8 = s.encode('utf-8') # utf-8编码成字节类型
s_gbk = s.encode('gbk')
f.write(s_utf8)

print('utf-8:',s_utf8)

print('解码:',s_utf8.decode('utf-8')) # 解码: 你好,中国
print('解码:',s_gbk.decode('gbk')) #  解码: 你好,中国

编码转换

以后我们在开发⽹络程序时,如果远程⼀台电脑发送过来的消息是GBK的, 你的电脑是utf-8的,你想把对⽅的消息正确显
示,就要按gbk来 decode 解码

在这里插入图片描述

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

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

相关文章

python selenium网页操作

一、安装依赖 pip install -U seleniumselenium1.py&#xff1a; from selenium import webdriver from selenium.webdriver.common.by import Bydriver webdriver.Chrome() driver.get("https://www.selenium.dev/selenium/web/web-form.html") title driver.ti…

网络安全学习(二)初识kali

kali有两种界面模式&#xff0c;为了更好的适应windows用户&#xff0c;需要操作一下。 先更新一下kali&#xff0c;执行命令 sudo apt-get update 然后换界面 sudo apt install kali-desktop-gnome 等待&#xff0c;出现如下界面时&#xff0c;选择gdm3&#xff08;键盘&a…

计算机视觉 对比学习 串烧一

文章目录 【文章列表】一、 Inst Disc1.1 文章摘要1.2 实验结果1.3 文章图示图一 超级学习结果的可视化图二 非参数softmax分类器的流程图三 近端正则化的效果图四 训练和测试目标的一致性图五 图像检索的结果表 1: CIFAR10 数据集上的分类准确率表 2: ImageNet 数据集上的分类…

临工30装载机多路阀

如图&#xff0c;因为螺丝太紧实&#xff0c;只好使用冲击螺丝刀卸下来了。 如图&#xff0c;防尘圈型号为FA 28 40 5/9 如图所示 28杆

【双方演化博弈】研究理论学习

1. 演化基础 1.1.演化博弈常用软件 载学习软件: Matlab、Vensim PLE、 Visio 其中,Matlab和Vensim PLE主要是用做演化博弈仿真,Matlab是演化博弈最常用的仿真软件&#xff0c;VensimPLE是系统动力学(SD)仿真软件也是常用仿真软件之一。 Python、Netlogo等软件也可以用来做演…

Vue 也能这样玩?Vuetify 打造超强大的UI体验

Vue 也能这样玩&#xff1f;Vuetify 打造超强大的UI体验&#xff01; 在前端开发的世界里&#xff0c;选择一个合适的 UI 组件库就像选择一把趁手的兵器。Vuetify 作为一款基于 Vue 的 Material Design 组件库&#xff0c;凭借其强大的功能和活跃的社区&#xff0c;已经成为了无…

深度学习-神经网络构造

文章目录 一、正则化惩罚1.L1正则化2.L2正则化 二、梯度下降&#xff08;Gradient Descent&#xff09;1.基本原理2.注意事项 三、BP神经网络1.基本原理2.网络结构3.特点 四、总结 一、正则化惩罚 正则化惩罚&#xff08;Regularization Penalty&#xff09;是机器学习中常用的…

CTF——简单的《MICS》

文章目录 一、MICS1、MISC-LSB2、MISC-循环解压3、MISC-一个不同的压缩包4、MISC-异性相吸5、MISC-仔细找找6、MISC-再来一题隐写7、MISC-找找吧8、MISC-这是一张单纯的图片9、MISC-真假flag10、MISC-真正的黑客才可以看到本质11、MISC-追象者12、MICS-鸡蛋别放在一起 一、MICS…

【GO开发】MacOS上搭建GO的基础环境-Hello World

文章目录 一、引言二、安装Go语言三、配置环境变量&#xff08;可跳过&#xff09;四、Hello World五、总结 一、引言 Go语言&#xff08;Golang&#xff09;因其简洁、高效、并发性强等特点&#xff0c;受到了越来越多开发者的喜爱。本文将带你一步步在Mac操作系统上搭建Go语…

spring mvc详细讲解(前后端分离模式)

在前后端分离模式下&#xff0c;Spring MVC 的作用主要集中在处理后端的业务逻辑和 API 接口&#xff0c;而不再直接管理视图部分。也就是说&#xff0c;Spring MVC 的重点是如何处理客户端的请求并返回数据&#xff08;通常以 JSON 或 XML 格式&#xff09;&#xff0c;而视图…

python 自动化测试接口

比如我们要测试接口&#xff1a;identity/chatRecords/pages 已在Postman中有&#xff0c;那我们就可以直接从里面复制出Python脚本 新建&#xff1a; pagerequest.py import requests import jsonurl "http://192.168.31.132:70/identity/chatRecords/pages"payl…

集成网口连接器国产化替代--RJ45内置网络变压器网口生产工厂在行动

Hqst盈盛&#xff08;华强盛&#xff09;电子导读&#xff1a;集成网口连接器的国产化替代&#xff0c;是很多在寻找成本优化和被要求使用国产化元器件的企业普遍寻找的途径&#xff0c;今天就给大家介绍几款国产化的集成万兆网络变压器的RJ45网口 下面我们一起来看看网通设备有…

JavaWeb——Vue(3/3):Vue生命周期(Vue生命周期-介绍、状态图、实例演示)

目录 Vue生命周期-介绍 状态图 实例演示 Vue生命周期-介绍 生命周期&#xff1a;指一个对象从创建到销毁的整个过程。生命周期的八个阶段&#xff1a;每触发一个生命周期事件&#xff0c;会自动执行一个生命周期方法(钩子)。 状态阶段周期beforeCreate创建前created创建后…

光伏板热斑缺陷检测数据集

项目背景&#xff1a; 光伏板是太阳能发电系统的核心组件之一&#xff0c;其性能直接影响到发电效率。光伏板上的热斑&#xff08;Hot Spot&#xff09;和热点&#xff08;Hot Point&#xff09;等问题会导致局部过热&#xff0c;进而影响光伏板的寿命和发电效率。及时发现并解…

OpenAI o1:AI推理的未来,如何平衡性能与成本?

OpenAI o1&#xff1a;AI推理的未来&#xff0c;如何平衡性能与成本&#xff1f; &#x1f680;人工智能的未来&#xff0c;已经悄然走向一个新的拐点&#xff01;9月14日&#xff0c;OpenAI正式推出了两款新型模型——o1-preview与o1-mini。虽然这并非是GPT-4的简单升级版&am…

supermap iclient3d for cesium场景加载雨雪效果,并加载相应材质

首先新建一个文件夹来存放材质&#xff0c;我选择src/assets/MaterialJson snow.json,复制粘贴,雨雪用一个就行了 {"material": {"id": "DA82AFCB-129A-4E66-995A-9F519894F58D","cullMode": "none","alphaMode"…

告别繁琐粘贴,CleanClip Mac 版,让复制粘贴变得简单快捷!粘贴队列功能太强大了!

告别繁琐粘贴&#xff0c;CleanClip Mac 版&#xff0c;让复制粘贴变得简单快捷&#xff01; CleanClip for Mac &#x1f4cb; 是一款专为Mac用户设计的高效剪贴板管理工具。它解决了传统复制粘贴过程中的繁琐问题&#xff0c;让你的工作流程更加顺畅和高效。 &#x1f504;…

数据结构基础详解:哈希表【理论计算篇】开放地址法_线性探测法_拉链法详解

文章目录 哈希表&#xff08;散列表&#xff09;1. 哈希表(散列表)的基本概念2. 常见的散列函数2.1 除留余数法2.2 直接定址法2.3 数字分析法2.4 平方取中法 3. 处理冲突的方法3.1 拉链法3.2 开放定址法3.2.1开放地址法的定义3.2.2 开放地址法的三种方法 3.3 再散列法(再哈希法…

NC 矩阵最长递增路径

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 描述 给定一个 n 行…

网络安全学习(一)初识kali

kali是一个操作系统,和我们平时用的windows系统类似,只是kali是一个集合了很多工具的专用操作系统。 其官网是https://www.kali.org 点击download,选择安装到虚拟机 因为要安装在虚拟机上,所以我们先要安装VM。 使用下载好的kali虚拟机文件(下载后大约3.1G,解压后大约G,…