感谢骆昊大佬写的学习文档:学习文档
例子1.寻找水仙花数。
说明:水仙花数也被称为超完全数字不变数、自恋数、自幂数、阿姆斯特朗数,它是一个3位数,该数字每个位上数字的立方之和正好等于它本身.
for i in range(100, 1000):
a = i//100
b = i//10 % 10
c = i % 10
if i == a**3+b**3+c**3:
print(i)
例子2.正整数的反转
num = int(input('请输入正整数'))
## 123456
rever_num = 0
while num >0:
rever_num = rever_num*10 + num%10
num //= 10
print(rever_num)
例子3:百钱百鸡问题。
说明:百钱百鸡是我国古代数学家张丘建在《算经》一书中提出的数学问题:
鸡翁一值钱五,
鸡母一值钱三,
鸡雏三值钱一。
百钱买百鸡,
问鸡翁、鸡母、鸡雏各几何?
for i in range(0,21):
for j in range(0,34):
z = 100 -5*i -3*j
if 5*i + 3*j + z//3 ==100 and z % 3 ==0:
print(f'公鸡{i}只,母鸡{j}只,小鸡{z}只')
公鸡2只,母鸡30只,小鸡0只
公鸡5只,母鸡25只,小鸡0只
公鸡8只,母鸡20只,小鸡0只
公鸡11只,母鸡15只,小鸡0只
公鸡14只,母鸡10只,小鸡0只
公鸡17只,母鸡5只,小鸡0只
公鸡20只,母鸡0只,小鸡0只
例子4:斐波那契数列。输出前20项。
a, b = 1, 1
# 通过递推公式算出后面的18个数
for _ in range(18):
a, b = b, a + b
print(b, end=' ')
例子5:输入M和N计算C(M,N)。
用循环做累乘来计算阶乘
m = int(input('m = '))
n = int(input('n = '))
# 计算m的阶乘
fm = 1
for num in range(1, m + 1):
fm *= num
# 计算n的阶乘
fn = 1
for num in range(1, n + 1):
fn *= num
# 计算m-n的阶乘
fm_n = 1
for num in range(1, m - n + 1):
fm_n *= num
# 计算C(M,N)的值
print(fm//fn//fm_n)
用函数修改上面的求组合数
def fac(num):
fn = 1
for i in range(1,num+1):
fn*=i
return fn
m = int(input('m = '))
n = int(input('n = '))
print(fac(m)//fac(n)//fac(m-n))
定义默认参数
def add(a=0, b=0, c=0):
return a + b + c
print(add(1,2))
任意多个参数:可变参数
# 用星号表达式来表示args可以接收0个或任意多个参数
def add(*args):
total = 0
# 可变参数可以放在for循环中取出每个参数的值
for val in args:
total += val
return total
print(add(1,2,3,4,5,6,7))
用模块管理函数
module1.py
def foo():
print('hello, world!')
module2.py
def foo():
print('goodbye, world!')
test.py
import module1
import module2
# 用“模块名.函数名”的方式(完全限定名)调用函数,
module1.foo() # hello, world!
module2.foo() # goodbye, world!
as关键字
test.py
import module1 as m1
import module2 as m2
m1.foo() # hello, world!
m2.foo() # goodbye, world!
from...import...
from module1 import foo
foo() # hello, world!
from module2 import foo
foo() # goodbye, world!
from module1 import foo as f1
from module2 import foo as f2
f1() # hello, world!
f2() # goodbye, world!
函数是功能相对独立且会重复使用的代码的封装
字符串的定义
所谓字符串,就是由零个或多个字符组成的有限序列
s1 = 'hello, world!'
s2 = "你好,世界!"
print(s1, s2)
# 以三个双引号或单引号开头的字符串可以折行
s3 = '''
hello,
world!
'''
print(s3, end='')
提示:print函数中的end=''表示输出后不换行,即将默认的结束符\n(换行符)更换为''(空字符)。
转义字符和原始字符串
# 头尾带单引号的hello, world!
s1 = '\'hello, world!\''
print(s1)
# 头尾带反斜杠的hello, world!
s2 = '\\hello, world!\\'
print(s2)
反斜杠和字符n
在字符串'hello\n'中,\n表示换行;而在r'hello\n'中,\n不再表示换行,就是反斜杠和字符n。
# 字符串s1中\t是制表符,\n是换行符
s1 = '\time up \now'
print(s1)
# 字符串s2中没有转义字符,每个字符都是原始含义
s2 = r'\time up \now'
print(s2)
拼接和重复
s1 = 'hello' + ' ' + 'world'
print(s1) # hello world
s2 = '!' * 3
print(s2) # !!!
s1 += s2 # s1 = s1 + s2
print(s1) # hello world!!!
s1 *= 2 # s1 = s1 * 2
print(s1) # hello world!!!hello world!!!
比较运算
s1 = 'a whole new world'
s2 = 'hello world'
print(s1 == s2, s1 < s2) # False True
print(s2 == 'hello world') # True
print(s2 == 'Hello world') # False
print(s2 != 'Hello world') # True
s3 = '骆昊'
print(ord('骆'), ord('昊')) # 39558 26122
s4 = '王大锤'
print(ord('王'), ord('大'), ord('锤')) # 29579 22823 38180
print(s3 > s4, s3 <= s4) # True False
is运算符
s1 = 'hello world'
s2 = 'hello world'
s3 = s2
# 比较字符串的内容
print(s1 == s2, s2 == s3) # True True
# 比较字符串的内存地址
print(s1 is s2, s2 is s3) # False True
成员运算 in和not in
s1 = 'hello, world'
print('wo' in s1) # True
s2 = 'goodbye'
print(s2 in s1) # False
获取字符串长度
s1 = 'hello, world'
print(len(s1)) # 12
print(len('goodbye, world')) # 14
索引和切片
如果希望从字符串中取出某个字符,我们可以对字符串进行索引运算,运算符是[n],其中n是一个整数,假设字符串的长度为N,那么n可以是从0到N-1的整数,其中0是字符串中第一个字符的索引,而N-1是字符串中最后一个字符的索引,通常称之为正向索引;在Python中,字符串的索引也可以是从-1到-N的整数,其中-1是最后一个字符的索引,而-N则是第一个字符的索引,通常称之为负向索引。注意,因为字符串是不可变类型,所以不能通过索引运算修改字符串中的字符。
s1 = 'abc123456'
N = len(s1)
# 获取第一个字符
print(s1[0], s1[-N]) # a a
# 获取最后一个字符
print(s1[N-1], s1[-1]) # 6 6
# 获取索引为2或-7的字符
print(s1[2], s1[-7]) # c c
# 获取索引为5和-4的字符
print(s1[5], s1[-4]) # 3 3
s1 = 'abc123456'
# i=2, j=5, k=1的正向切片操作
print(s1[2:5]) # c12
# i=-7, j=-4, k=1的正向切片操作
print(s1[-7:-4]) # c12
# i=2, j=9, k=1的正向切片操作
print(s1[2:]) # c123456
# i=-7, j=9, k=1的正向切片操作
print(s1[-7:]) # c123456
# i=2, j=9, k=2的正向切片操作
print(s1[2::2]) # c246
# i=-7, j=9, k=2的正向切片操作
print(s1[-7::2]) # c246
# i=0, j=9, k=2的正向切片操作
print(s1[::2]) # ac246
# i=1, j=-1, k=2的正向切片操作
print(s1[1:-1:2]) # b135
# i=7, j=1, k=-1的负向切片操作
print(s1[7:1:-1]) # 54321c
# i=-2, j=-8, k=-1的负向切片操作
print(s1[-2:-8:-1]) # 54321c
# i=7, j=-10, k=-1的负向切片操作
print(s1[7::-1]) # 54321cba
# i=-1, j=1, k=-1的负向切片操作
print(s1[:1:-1]) # 654321c
# i=0, j=9, k=1的正向切片
print(s1[:]) # abc123456
# i=0, j=9, k=2的正向切片
print(s1[::2]) # ac246
# i=-1, j=-10, k=-1的负向切片
print(s1[::-1]) # 654321cba
# i=-1, j=-10, k=-2的负向切片
print(s1[::-2]) # 642ca
循环遍历
如果希望从字符串中取出每个字符,可以使用for循环对字符串进行遍历,有两种方式。
方式一:
s1 = 'hello'
for index in range(len(s1)):
print(s1[index])
方式二:
s1 = 'hello'
for ch in s1:
print(ch)
字符串的方法 调用:变量名.方法名()
s1 = 'hello, world!'
# 使用capitalize方法获得字符串首字母大写后的字符串
print(s1.capitalize()) # Hello, world!
# 使用title方法获得字符串每个单词首字母大写后的字符串
print(s1.title()) # Hello, World!
# 使用upper方法获得字符串大写后的字符串
print(s1.upper()) # HELLO, WORLD!
s2 = 'GOODBYE'
# 使用lower方法获得字符串小写后的字符串
print(s2.lower()) # goodbye
查找操作find,index
如果想在一个字符串中查找有没有另外一个字符串,可以使用字符串的find或index方法。
s1 = 'hello, world!'
# find方法从字符串中查找另一个字符串所在的位置
# 找到了返回字符串中另一个字符串首字符的索引
print(s1.find('or')) # 8
# 找不到返回-1
print(s1.find('shit')) # -1
# index方法与find方法类似
# 找到了返回字符串中另一个字符串首字符的索引
print(s1.index('or')) # 8
# 找不到引发异常
print(s1.index('shit')) # ValueError: substring not found
逆向查找 rfind和rindex
s = 'hello good world!'
# 从前向后查找字符o出现的位置(相当于第一次出现)
print(s.find('o')) # 4
# 从索引为5的位置开始查找字符o出现的位置
print(s.find('o', 5)) # 7
# 从后向前查找字符o出现的位置(相当于最后一次出现)
print(s.rfind('o')) # 12
性质判断
可以通过字符串的startswith、endswith来判断字符串是否以某个字符串开头和结尾;还可以用is开头的方法判断字符串的特征,这些方法都返回布尔值
s1 = 'hello, world!'
# startwith方法检查字符串是否以指定的字符串开头返回布尔值
print(s1.startswith('He')) # False
print(s1.startswith('hel')) # True
# endswith方法检查字符串是否以指定的字符串结尾返回布尔值
print(s1.endswith('!')) # True
s2 = 'abc123456'
# isdigit方法检查字符串是否由数字构成返回布尔值
print(s2.isdigit()) # False
# isalpha方法检查字符串是否以字母构成返回布尔值
print(s2.isalpha()) # False
# isalnum方法检查字符串是否以数字和字母构成返回布尔值
print(s2.isalnum()) # True
格式化字符串
s1 = 'hello, world'
# center方法以宽度20将字符串居中并在两侧填充*
print(s1.center(20, '*')) # ****hello, world****
# rjust方法以宽度20将字符串右对齐并在左侧填充空格
print(s1.rjust(20)) # hello, world
# ljust方法以宽度20将字符串左对齐并在右侧填充~
print(s1.ljust(20, '~')) # hello, world~~~~~~~~
字符串格式化
用print函数输出字符串时,可以用下面的方式对字符串进行格式化
1.
a = 321
b = 123
print('%d * %d = %d' % (a, b, a * b))
2.
a = 321
b = 123
print('{0} * {1} = {2}'.format(a, b, a * b))
3.
a = 321
b = 123
print(f'{a} * {b} = {a * b}')
strip 修剪操作
帮我们获得将原字符串修剪掉左右两端空格之后的字符串
还有:lstrip()和rstrip();
s1 = ' [email protected] '
# strip方法获得字符串修剪左右两侧空格之后的字符串
print(s1.strip()) # [email protected]
练习1:设计一个生成指定长度验证码的函数。
第一种方法:
import random
ALL_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
def generate_code(code_len=4):
code = ""
for i in range(code_len):
index = random.randrange(0,len(ALL_CHARS))
code+=ALL_CHARS[index]
return code
print(generate_code(10))
第二种方式:
import random
import string
ALL_CHARS = string.digits + string.ascii_letters
def generate_code(code_len=4):
:param code_len: 验证码的长度(默认4个字符)
:return: 由大小写英文字母和数字构成的随机验证码字符串
return ''.join(random.choices(ALL_CHARS, k=code_len))
print(generate_code(10))
说明:random模块的sample和choices函数都可以实现随机抽样,
sample实现无放回抽样,这意味着抽样取出的字符是不重复的;
choices实现有放回抽样,这意味着可能会重复选中某些字符。
这两个函数的第一个参数代表抽样的总体,而参数k代表抽样的数量。
练习二:设计一个函数返回给定文件名的后缀名。
第一种:
def get_suffix(filename):
获取文件名的后缀名
:param filename: 文件名
:return: 文件的后缀名
index = filename.rfind('.')
return filename[index+1:] if index >0 else ''
print(get_suffix('zhan.pdf'))
第二种:
from os.path import splitext
def get_suffix(filename):
return splitext(filename)[1][1:]
print(get_suffix('zhan.pdf'))
练习3:在终端中显示跑马灯(滚动)文字。
说明:实现跑马灯文字的原理非常简单,
把当前字符串的第一个字符放到要输出的内容的最后面,
把从第二个字符开始后面的内容放到要输出的内容的最前面,
通过循环重复这个操作,就可以看到滚动起来的文字。
两次循环之间的间隔可以通过time模块的sleep函数来实现,
而清除屏幕上之前的输出可以使用os模块的system函数调用系统清屏命令来实现。
import os
import time
content = '北 京 欢 迎 你 为 你 开 天 辟 地 '
while True:
# Windows清除屏幕上的输出
# os.system('cls')
# macOS清除屏幕上的输出
os.system('clear')
print(content)
# 休眠0.2秒(200毫秒)
time.sleep(0.2)
content = content[1:] + content[0]
将相对独立且重复出现的功能封装成函数
常用数据结构之列表
将一颗色子掷6000次,统计每个点数出现的次数.
import random
f1 = 0
f2 = 0
f3 = 0
f4 = 0
f5 = 0
f6 = 0
for i in range(6000):
face = random.randint(1, 6)
if face==1:
f1=f1+1
if face==2:
f2=f2+1
if face==3:
f3=f3+1
if face==4:
f4=f4+1
if face==5:
f5=f5+1
if face==6:
f6=f6+1
print(f'1点出现了{f1}次')
print(f'2点出现了{f2}次')
print(f'3点出现了{f3}次')
print(f'4点出现了{f4}次')
print(f'5点出现了{f5}次')
print(f'6点出现了{f6}次')
定义和使用列表
在Python中,列表是由一系元素按特定顺序构成的数据序列,这样就意味着定义一个列表类型的变量,可以保存多个数据,而且允许有重复的数据。跟上一课我们讲到的字符串类型一样,列表也是一种结构化的、非标量类型,操作一个列表类型的变量,除了可以使用运算符还可以使用它的方法。
items1 = [35, 12, 99, 68, 55, 87]
print(items1)
items2 = ['Python', 'Java', 'Go', 'Kotlin']
print(items2)
list函数将其他序列变成列表
items1 = list(range(1, 10))
print(items1) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
items2 = list('hello')
print(items2) # ['h', 'e', 'l', 'l', 'o']
列表是一种可变数据类型,也就是说列表可以添加元素、删除元素、更新元素,这一点跟我们上一课讲到的字符串有着鲜明的差别。字符串是一种不可变数据类型,也就是说对字符串做拼接、重复、转换大小写、修剪空格等操作的时候会产生新的字符串,原来的字符串并没有发生任何改变。
列表的运算符
items1 = [35, 12, 99, 68, 55, 87]
items2 = [45, 8, 29]
# 列表的拼接
items3 = items1 + items2
print(items3) # [35, 12, 99, 68, 55, 87, 45, 8, 29]
# 列表的重复
items4 = ['hello'] * 3
print(items4) # ['hello', 'hello', 'hello']
# 列表的成员运算
print(100 in items3) # False
print('hello' in items4) # True
# 获取列表的长度(元素个数)
size = len(items3)
print(size) # 9
# 列表的索引
print(items3[0], items3[-size]) # 35 35
items3[-1] = 100
print(items3[size - 1], items3[-1]) # 100 100
# 列表的切片
print(items3[:5]) # [35, 12, 99, 68, 55]
print(items3[4:]) # [55, 87, 45, 8, 100]
print(items3[-5:-7:-1]) # [55, 68]
print(items3[::-2]) # [100, 45, 55, 99, 35]
# 列表的比较运算
items5 = [1, 2, 3, 4]
items6 = list(range(1, 5))
# 两个列表比较相等性比的是对应索引位置上的元素是否相等
print(items5 == items6) # True
items7 = [3, 2, 1]
# 两个列表比较大小比的是对应索引位置上的元素的大小
print(items5 <= items7) # True
列表元素的遍历
如果想逐个取出列表中的元素,可以使用for循环的,有以下两种做法。
方法一:
items = ['Python', 'Java', 'Go', 'Kotlin']
for index in range(len(items)):
print(items[index])
方法二:
items = ['Python', 'Java', 'Go', 'Kotlin']
for item in items:
print(item)
修改掷筛子:
import random
counters = [0] * 6
for _ in range(6000):
face = random.randint(1, 6)
counters[face - 1] += 1
for face in range(1, 7):
print(f'{face}点出现了{counters[face - 1]}次')
添加和删除元素append,insert,remove,pop,clear,del
items = ['Python', 'Java', 'Go', 'Kotlin']
# 使用append方法在列表尾部添加元素
items.append('Swift')
print(items) # ['Python', 'Java', 'Go', 'Kotlin', 'Swift']
# 使用insert方法在列表指定索引位置插入元素
items.insert(2, 'SQL')
print(items) # ['Python', 'Java', 'SQL', 'Go', 'Kotlin', 'Swift']
# 删除指定的元素
items.remove('Java')
print(items) # ['Python', 'SQL', 'Go', 'Kotlin', 'Swift']
# 删除指定索引位置的元素
items.pop(0)
items.pop(len(items) - 1)
print(items) # ['SQL', 'Go', 'Kotlin']
# 清空列表中的元素
items.clear()
print(items) # []
items = ['Python', 'Java', 'Go', 'Kotlin']
del items[1]
print(items) # ['Python', 'Go', 'Kotlin']
元素位置和次数index,count
items = ['Python', 'Java', 'Java', 'Go', 'Kotlin', 'Python']
# 查找元素的索引位置
print(items.index('Python')) # 0
print(items.index('Python', 2)) # 5
# 注意:虽然列表中有'Java',但是从索引为3这个位置开始后面是没有'Java'的
print(items.index('Java', 3))
items = ['Python', 'Java', 'Java', 'Go', 'Kotlin', 'Python']
# 查找元素出现的次数
print(items.count('Python')) # 2
print(items.count('Go')) # 1
print(items.count('Swfit')) # 0
元素排序和反转 sort,reverse
items = ['Python', 'Java', 'Go', 'Kotlin', 'Python']
# 排序
items.sort()
print(items) # ['Go', 'Java', 'Kotlin', 'Python', 'Python']
# 反转
items.reverse()
print(items) # ['Python', 'Python', 'Kotlin', 'Java', 'Go']
列表的生成式
# 创建一个由1到9的数字构成的列表
items1 = []
for x in range(1, 10):
items1.append(x)
print(items1)
# 创建一个由'hello world'中除空格和元音字母外的字符构成的列表
items2 = []
for x in 'hello world':
if x not in ' aeiou':
items2.append(x)
print(items2)
# 创建一个由个两个字符串中字符的笛卡尔积构成的列表
items3 = []
for x in 'ABC':
for y in '12':
items3.append(x + y)
print(items3)
通过生成式创建列表
# 创建一个由1到9的数字构成的列表
强烈建议用生成式语法来创建列表
items1 = [x for x in range(1, 10)]
print(items1) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 创建一个由'hello world'中除空格和元音字母外的字符构成的列表
items2 = [x for x in 'hello world' if x not in ' aeiou']
print(items2) # ['h', 'l', 'l', 'w', 'r', 'l', 'd']
# 创建一个由个两个字符串中字符的笛卡尔积构成的列表
items3 = [x + y for x in 'ABC' for y in '12']
print(items3) # ['A1', 'A2', 'B1', 'B2', 'C1', 'C2']
嵌套的列表
scores = [[0] * 3] * 5
print(scores) # [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
# 嵌套的列表需要多次索引操作才能获取元素
scores[0][0] = 95
print(scores) # [[95, 0, 0], [95, 0, 0], [95, 0, 0], [95, 0, 0], [95, 0, 0]]
scores = [[0] * 3 for _ in range(5)]
scores[0][0] = 95
print(scores) # [[95, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
Python中的列表底层是一个可以动态扩容的数组,列表元素在内存中也是连续存储的,所以可以实现随机访问(通过一个有效的索引获取到对应的元素且操作时间与列表元素个数无关)。我们暂时不去触碰这些底层存储细节以及列表每个方法的渐近时间复杂度(执行这个方法耗费的时间跟列表元素个数的关系),等需要的时候再告诉大家。现阶段,大家只需要知道列表是容器,可以保存各种类型的数据,可以通过索引操作列表元素就可以了。