聪明办法学Python-2023-task05&06

发布时间 2023-11-30 11:20:32作者: Lyanv

参考视频链接:【循环 Loop】聪明办法学Python第二版_哔哩哔哩_bilibili

【字符串】聪明办法学Python第二版_哔哩哔哩_bilibili

task05

循环 Loop

for 循环和循环范围

for 循环的特点

基于提供的范围,重复执行特定次数的操作

例:

def sumFromMToN(m, n):
    total = 0
    # 注意: range(x, y) 是左闭右开区间,包含 x,不包含 y
    for x in range(m, n+1): # 在这个范围内取东西赋给x
        total += x
    return total

sumFromMToN(5, 10)
45
sumFromMToN(5, 10) == 5+6+7+8+9+10
True
range() 是个什么东西?

本质上是一个生成器(生成一个序列)

其实在这里,我们也可以不用循环来完成同样的任务

def sumFromMToN(m, n):
    return sum(range(m, n+1)) # sum可以接收一个生成器
sumFromMToN(5, 10)
45

如果我们省略第一个参数会发生什么?

def sumToN(n):
    total = 0
    # range 起始范围默认为 0
    for x in range(n+1):
        total += x
    return total

sumToN(5)
15

那如果我们添加第三个参数呢?

def sumEveryKthFromMToN(m, n, k):
    total = 0
    # 第三个参数为 “步长” step ## 这里是隔k个取一个
    # 输出m+k个
    for x in range(m, n+1, k):
        total += x
    return total


sumEveryKthFromMToN(5, 20, 7) == (5 + 12 + 19)
True

只对从 mn奇数求和

# 我们也可以通过修改循环内部的代码来改变步长
## 上面的时间复杂度更低,这里的更高
def sumOfOddsFromMToN(m, n):
    total = 0
    for x in range(m, n+1):
        if x % 2 == 1:
            total += x
    return total
    

sumOfOddsFromMToN(4, 10) == sumOfOddsFromMToN(5,9) == (5+7+9)
True

现在我们反着来试一下!

生成反向序列

代码实践中不建议这么做

因为reversed()函数[用于反转],可以达到一样的效果

# 我们将生成一个反向数字序列
# (仅供演示使用,代码实践中不建议这么做)

def sumOfOddsFromMToN(m, n):
    total = 0
    for x in range(n, m-1, -1): # 每个减一,生成m到n的递减序列 ## 永远左闭右开
        if x % 2 == 1:
            total += x
    return total

sumOfOddsFromMToN(4, 10) == sumOfOddsFromMToN(5,9) == (5+7+9)
True

还有更多方法来解决这个问题

for 循环嵌套

要提高程序响应速度就尽量不要用嵌套循环

因为python的for循环真的非常慢...

# 下面的代码将输出二维坐标
## 低效
def printCoordinates(xMax, yMax):
    for x in range(1, xMax+1):
        for y in range(1, yMax+1):
            print(f"( {x} , {y} )  ", end="")
        print()
        

printCoordinates(5, 5)

( 1 , 1 )  ( 1 , 2 )  ( 1 , 3 )  ( 1 , 4 )  ( 1 , 5 )  
( 2 , 1 )  ( 2 , 2 )  ( 2 , 3 )  ( 2 , 4 )  ( 2 , 5 )  
( 3 , 1 )  ( 3 , 2 )  ( 3 , 3 )  ( 3 , 4 )  ( 3 , 5 )  
( 4 , 1 )  ( 4 , 2 )  ( 4 , 3 )  ( 4 , 4 )  ( 4 , 5 )  
( 5 , 1 )  ( 5 , 2 )  ( 5 , 3 )  ( 5 , 4 )  ( 5 , 5 )  

如果换成 * 呢?

def Stars(n, m):
    # 输出一个 n*m 的星型矩阵图
    for row in range(n):
        for col in range(m):
            print("*", end="")
        print()
        
        
Stars(5, 5)
*****
*****
*****
*****
*****

换一种写法

# be careful! 这些代码与之前的有什么不同?
## 采用外层循环的变量值当作内层循环的范围 

def printMysteryStarShape(n):
    for row in range(n):
        print(row, end=" ")
        for col in range(row):
            print("*", end=" ")
        print()
        
printMysteryStarShape(5)
0 
1 * 
2 * * 
3 * * * 
4 * * * * 

while 循环

嘿!

当你不知道循环什么时候停下来的时候,为什么不试试 while

找出一个数最左边的那一位的数值(123451

# 我不知道它什么时候停下来

def leftmostDigit(n):
    n = abs(n)
    while n >= 10:
        n = n//10
    return n 
# 不知道啥时候停下来,反正直到10以内时都是除10取整
   
leftmostDigit(46535248)
4

举个例子:依次找出 n 个 4 或者 7 的整数倍非负整数

def isMultipleOf4or7(x):
    return ((x % 4) == 0) or ((x % 7) == 0)

def nthMultipleOf4or7(n):
    found = 0
    guess = -1
    while found <= n: # 直到我找到了第n个数时停止
        guess += 1  # 输入了几个数 
        ## 变相从1一直遍历到无穷,直到找到n个符合条件的数
        if isMultipleOf4or7(guess):
            found += 1 # 找到了几个数
    return guess
print("4 或 7 的倍数: ", end="")
for n in range(15):
    print(nthMultipleOf4or7(n), end=" ")
    

4 或 7 的倍数: 0 4 7 8 12 14 16 20 21 24 28 32 35 36 40 

Bad Style:在知道循环范围的情况下使用 while

def sumToN(n):
    # 尽管它能正确运行,但是这是非常不推荐的做法!
    # 应该使用 for 循环而不是 while 循环
    ## 因为这使代码更复杂了(for秒了)
    total = 0
    counter = 1
    while counter <= n:
        total += counter
        counter += 1
    return total
    
sumToN(5) == 1+2+3+4+5

True

break 与 continue 语句

for n in range(200):
    if n % 3 == 0:
        continue # 跳过这次循环 ## 这次print()就不会执行
    elif n == 8:
        break # 跳出当前整个循环
    else:
        pass # 啥也不做,占位符(不会被运行)
    print(n, end=" ")

1 2 4 5 7 

如果不想利用(赋值给)变量进行循环遍历[纯粹是想利用次数循环]『推导式常用』则可以写成:

for _ in range(0, n)

假·死循环

环境交互后,在特定条件下终止的循环

很像定时关闭

# 不需要看懂这些代码,关注演示的过程

def readUntilDone():
    linesEntered = 0
    while True:
        response = input("输入一个字符串(输入 done 则退出): ")
        if response == "done":# 实现输入done时退出
            break
        print("你输入了: ", response)
        linesEntered += 1
    print("Bye!")
    return linesEntered


linesEntered = readUntilDone()
print("你输入了", linesEntered, "行 (不包括 'done').")


你输入了:  learn
你输入了:  python
你输入了:  the
你输入了:  smart
你输入了:  way
Bye!
你输入了 5 行 (不包括 'done').

IsPrime

判断一个数是不是质数

# 不是最快的写法,但最容易理解

def isPrime(n):
    if n < 2:
        return False
    for factor in range(2,n):
        if n % factor == 0:
            return False
    return True


for n in range(100):
    if isPrime(n):
        print(n, end=" ")


2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 

faster IsPrime

采用了搜索剪枝

上面采用了遍历每一个比n小的数进行整除,效率很低

暴力遍历

采用更少次数的循环来实现功能(减去了不必要的循环次数)[减少时间复杂度]

# 快了一点

def fasterIsPrime(n):
    if n < 2:
        return False
    if n == 2:
        return True
    if n % 2 == 0:
        return False
    maxFactor = round(n**0.5)
    for factor in range(3, maxFactor+1, 2):
        if n % factor == 0: # 新的一种算法↑
            return False
    return True


for n in range(100):
    if fasterIsPrime(n):
        print(n, end=" ")
        

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 

真的快了?↑

先验证改良后的代码是否还是正确的

不正确的代码再快也没有意义

# 验证他它俩结果是一样的
for n in range(100):
    assert(isPrime(n) == fasterIsPrime(n))
    # 采用了assert断言函数进行判断
    # 判断100以内结果是否完全一致
print("两种解法的结果一致")
两种解法的结果一致

然后计算俩者所需时间

import time

bigPrime = 102030407
print("Timing isPrime(",bigPrime,")", end=" ")

# isPrime
time0 = time.time()
print(", returns ", isPrime(bigPrime), end=" ")

time1 = time.time()
print(", time = ",(time1-time0)*1000,"ms\n")

# fasterIsPrime
print("Timing fasterIsPrime(",bigPrime,")", end=" ")
time0 = time.time()

print(", returns ", fasterIsPrime(bigPrime), end=" ")
time1 = time.time()



print(", time = ",(time1-time0)*1000,"ms")



# result↓
Timing isPrime( 102030407 ) , returns  True , time =  4708.568811416626 ms # 慢算法的时间

Timing fasterIsPrime( 102030407 ) , returns  True , time =  0.4515647888183594 ms
# 快算法的时间

nth Prime

依次找出第 n 位质数

def nthPrime(n):
    found = 0
    guess = 0
    while found <= n:
        guess += 1
        if fasterIsPrime(guess): # 上面源代码
            found += 1
    return guess
    
    
for n in range(10):
    print(n, nthPrime(n))
print("Done!")


0 2
1 3
2 5
3 7
4 11
5 13
6 17
7 19
8 23
9 29
Done!

task05总结

  • For 循环用于指定范围的重复操作。
  • range() 可以生成一个数字范围。
  • 不知道循环什么时间停止的时候,应该试试 While 循环。
  • 循环同样也是可以嵌套的。
  • 巧妙地使用 breakcontinue 语句。
  • 合理的剪枝缩小搜索范围/循环范围,可以大幅提高程序运行效率

task06

字符串 Strings

字符串文字

四种引号

引号的作用就是将文字包裹起来,告诉 Python "这是个字符串!"

单引号 ' 和双引号 " 是最常见的两种字符串引号

大多数情况''""是等价的

print('单引号')
print("双引号")

单引号
双引号

三个引号的情况不太常见,但是它在一些场合有特定的作用(如函数文档 doc-strings

最大的作用就是可以写多行了

print('''三个单引号''')
print("""三个双引号""")
三个单引号
三个双引号

我们为什么需要两种不同的引号?

例:

# 为了写出这样的句子 ## 把专有名词给打印出来
print("聪明办法学 Python 第二版的课程简称是 'P2S'")

聪明办法学 Python 第二版的课程简称是 'P2S'

但如果我们偏要只用一种引号呢?

# 这会导致语法错误,Python 无法正确判断一个字符串的终止位置 ## python只会匹配两个相邻最近的引号
print("聪明办法学 Python 第二版的课程简称是 "P2S"")


Cell In [4], line 2
    print("聪明办法学 Python 第二版的课程简称是 "P2S"")
                                   ^
SyntaxError: invalid syntax

字符串中的换行符号

前面有反斜杠 \ 的字符,叫做转义序列

比如 \n 代表换行,尽管它看起来像两个字符,但是 Python 依然把它视为一个特殊的字符

下面""""""三引号的作用是不会限制多少行

而单引号则会进行限制

# 这两个 print() 在做同样的事情 
print("Data\nwhale")  # \n 是一个单独的换行符号

Data
whale

print("""Data
whale""") # 说明python能够识别键盘中Enter键所执行的换行操作

Data
whale

单个\print()可以用来排除Enter键带来的换行:

print("""你可以在字符串后面使用 反斜杠 `\`  来排除后面的换行。\
比如这里是第二行文字,但是你会看到它会紧跟在上一行句号后面。\
这种做法在 CIL 里面经常使用(多个 Flag 并排保持美观),\
但是在编程中的应用比较少。\
""") # 后面空的全是按了Enter键


你可以在字符串后面使用 反斜杠 `\`  来排除后面的换行。比如这里是第二行文字,但是你会看到它会紧跟在上一行句号后面。这种做法在 CIL 里面经常使用(多个 Flag 并排保持美观),但是在编程中的应用比较少。

去除\后:

print("""你可以在字符串后面使用 反斜杠 `\`  来排除后面的换行。
比如这里是第二行文字,但是你会看到它会紧跟在上一行句号后面。
这种做法在 CIL 里面经常使用(多个 Flag 并排保持美观),
但是在编程中的应用比较少。
""")


你可以在字符串后面使用 反斜杠 `\`  来排除后面的换行。
比如这里是第二行文字,但是你会看到它会紧跟在上一行句号后面。
这种做法在 CIL 里面经常使用(多个 Flag 并排保持美观),
但是在编程中的应用比较少。

其他的转义序列

print("双引号:\"")
双引号:"

print("反斜线:\\")
反斜线:\

print("换\n行")
换
行

# 等效于一个Tab键↓
print("这个是\t制\t表\t符\n也叫\t跳\t格\t键")
这个是	制	表	符
也叫	跳	格	键

转义序列只作为一个字符存在

s = "D\\a\"t\ta"
print("s =", s)
print("\ns 的长度为:", len(s))


s = D\a"t	a

s 的长度为: 7

repr() vs print()

我们现在有两个字符串

s1 = "Data\tWhale"
s2 = "Data        Whale"

它俩看起来似乎是一样的

print("s1:", s1)
print("s2:", s2)

s1: Data	Whale
s2: Data    Whale

但是它们真的一样吗?

s1 == s2
False

如来佛合掌道:“观音尊者,你看那两个行者,谁是真假?”

“谛听,汝之神通,能分辨出谁是真身,可为我说之。”

repr()函数

print(repr(s1))
print(repr(s2))
'Data\tWhale'
'Data        Whale'

可以直接看出python中字符串的内部结构

hack_text = "密码应当大于 8 个字符,小于 16 个字符,包含大写字母、小写字母、数字和特殊符号\t\t\t\t\t\t\t\t\t\t\t\t\t"


print(hack_text)

密码应当大于 8 个字符,小于 16 个字符,包含大写字母、小写字母、数字和特殊符号													

防止一些无法被看见的(隐藏的程序)进行执行

print(repr(hack_text))
# 可以直接现型

'密码应当大于 8 个字符,小于 16 个字符,包含大写字母、小写字母、数字和特殊符号\t\t\t\t\t\t\t\t\t\t\t\t\t'

多行字符串作为注释

python本身没有多行注释,但可以用这种方法实现类似效果

"""
Python 本身是没有多行注释的,
但是你可以用多行字符串实现同样的操作,
还记得我们之前学过的“表达式“吗?
它的原理就是 Python 会运行它,
但是马上扔掉!(垃圾回收机制)
"""

print("Amazing!")

Amazing!

一些字符串常量

import string
print(string.ascii_letters)
# 打印ASCII码

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

单独打印大小写

print(string.ascii_lowercase)
abcdefghijklmnopqrstuvwxyz
print(string.ascii_uppercase) 
ABCDEFGHIJKLMNOPQRSTUVWXYZ

可以用于判断字母是否在这些里面

print("A" in string.ascii_uppercase) 
True
print(string.digits)
# 打印数字类型
0123456789

print(string.punctuation)
# 打印python支持输出的所有特殊符号
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

print(string.printable)
# 打印所有python支持输出的字符
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 	

print(string.whitespace)
# 打印空白字符
 	


可以用上面的repr()函数来看空白字符的本质

print(repr(string.whitespace))

' \t\n\r\x0b\x0c'

一些字符串的运算

字符串的加乘

print("abc" + "def")
print("abc" * 3)
abcdef
abcabcabc

字符串只能和字符串做加乘运算

print("abc" + 3)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [31], line 1
----> 1 print("abc" + 3)

TypeError: can only concatenate str (not "int") to str

in 运算(超级好用!)

可用于查看某部分(前面字符串)是否在(后面的)字符串中

print("ring" in "strings") # True
print("wow" in "amazing!") # False
print("Yes" in "yes!") # False
print("" in "No way!") # True
print("聪明" in "聪明办法学 Python") # True


True
False
False
True
True

字符串索引和切片

单个字符索引

索引可以让我们在特定位置找到一个字符

s = "Datawhale" # 赋值给s
print(s)
print(s[0])
print(s[1])
print(s[2])
print(s[3])
Datawhale
D
a
t
a
len(s)
9
print(s[len(s)-1]) # 最后一位了,因为从0开始的
e
print(s[len(s)])
# 越界报错
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In [36], line 1
----> 1 print(s[len(s)])

IndexError: string index out of range

负数索引

print(s) # 字符串从右到左是从-1开始的
print(s[-5])
print(s[-4])
print(s[-3])
print(s[-2])
print(s[-1]) # 倒数第一个
Datawhale
w
h
a
l
e

切片来获取字符串的一部分

print(s[0:4]) # 左闭右开,第五个取不到
print(s[4:9])
Data
whale
print(s[0:2])
print(s[2:4])
print(s[5:7])
print(s[7:9])
Da
ta
ha
le

切片的默认参数

左边不写东西默认从0开始

右边不写东西默认执行到-1结束

print(s[:4])
print(s[4:])
print(s[:])
Data
whale
Datawhale

切片的第三个参数 step

步长,隔多少个取一次

print(s[:9:3]) # 经过3的长度取一次 ## 这里默认0时取第一次
print(s[1:4:2])
Daa
aa

翻转字符串

# 可以,但是不优雅
print(s[::-1]) # 步长为负数就从右往左切片
elahwataD

# 也可以,但是还是不够优雅
print("".join(reversed(s)))
elahwataD

# 实在是太优雅辣
def reverseString(s):
    return s[::-1]

print(reverseString(s))

elahwataD

第二次的join()可以把一个序列依次添加到字符串内

字符串的循环

用索引的 for 循环

for i in range(len(s)):
    print(i, s[i])
    
0 D
1 a
2 t
3 a
4 w
5 h
6 a
7 l
8 e

其实也可以不用索引(超级好用的 in

for c in s: # 依次取出
    print(c)
    
D
a
t
a
w
h
a
l
e

也可以使用 enumerate() 获得元素的序号

这里同时获取了元素的序号和其对应的元素

for idx, c in enumerate(s):
    print(idx, c) # 也可以用c[idx] 不过不优雅
    
0 D
1 a
2 t
3 a
4 w
5 h
6 a
7 l
8 e

zip(a, b) 可以在一次循环中,分别从 ab同时取出一个元素

for a, b in zip(s, reverseString(s)):
    print(a, b) # 分别取出一个赋给a,b
    
D e
a l
t a
a h
w w
h a
a t
l a
e D

也可以采用enumerate()来分别获取俩个的序号

split() 来循环

默认以空格为分隔符分隔字符串并产生列表

# class_name.split() 本身会产生一个新的叫做“列表”的东西,但是它不存储任何内容

class_name = "learn python the smart way 2nd edition"
for word in class_name.split(): # 以列表输出
    print(word)
    
learn
python
the
smart
way
2nd
edition

splitlines() 来循环

和上面一样的生成一个列表,但是它是默认以换行符来分隔字符串的

# 跟上面一样,class_info.splitlines() 也会产生一个列表,但不存储任何内容

class_info = """\
聪明办法学 Python 第二版是 Datawhale 基于第一版教程的一次大幅更新。我们尝试在教程中融入更多计算机科学与人工智能相关的内容,制作“面向人工智能的 Python 专项教程”。

我们的课程简称为 P2S,有两个含义:

Learn Python The Smart Way V2,“聪明办法学 Python 第二版”的缩写。
Prepare To Be Smart, 我们希望同学们学习这个教程后能学习到聪明的办法,从容的迈入人工智能的后续学习。
"""

for line in class_info.splitlines():
    if (line.startswith("Prepare To Be Smart")):
        print(line)
        
# 要是直接print(class_info.splitlines())
# 则出来的是以换行为间隔的列表(list)
        
Prepare To Be Smart, 我们希望同学们学习这个教程后能学习到聪明的办法,从容的迈入人工智能的后续学习。

例子:回文判断

如果一个句子正着读、反着读都是一样的,那它就叫做“回文”

# 四个判断回文数的函数
def isPalindrome1(s):
    return (s == reverseString(s))
	# 翻转字符串
   
   
def isPalindrome2(s):
    for i in range(len(s)):
        if (s[i] != s[len(s)-1-i]):
            return False
    return True
   
   
def isPalindrome3(s):
    for i in range(len(s)):
        if (s[i] != s[-1-i]):
            return False
    return True
  
  
def isPalindrome4(s):
    while (len(s) > 1):
        if (s[0] != s[-1]):
            return False
        s = s[1:-1]
    return True
    
    
print(isPalindrome1("abcba"), isPalindrome1("abca"))
print(isPalindrome2("abcba"), isPalindrome2("abca"))
print(isPalindrome3("abcba"), isPalindrome3("abca"))
print(isPalindrome4("abcba"), isPalindrome4("abca"))

True False
True False
True False
True False

一些跟字符串相关的内置函数

str()len()

str()将另外一个数据类型转换为字符串类型

len()输出一段字符串的长度

name = input("输入你的名字: ")
print("Hi, " + name + ", 你的名字有 " + str(len(name)) + " 个字!")
# 如果把str去掉就会报错 ## 因为字符串才能被打印


输入你的名字: Datawhale
Hi, Datawhale, 你的名字有 9 个字!

chr()ord()

chr():输出ASCII码对应的那个字符

ord():输出对应的ASCII码

俩者是相反的用途

print(ord("A")) # 打印出对应的ASCII码
65
print(chr(65))
A
print(
    chr(
        ord("A") + 1 # A的ASCII码+1然后转换为字符
    )
)
B
print(chr(ord("A") + ord(" ")))
# A的ASCII码是65,空格的ASCII码是32
a

eval()函数

会有被执行漏洞的风险

# 它可以正常运行,但是我们不推荐你使用这个方法
## 恶意代码片段执行会不安全(尽量使用)
s = "(3**2 + 4**2)**0.5"
print(eval(s)) # 执行字符串里的数学方法
5.0

推荐使用 ast.literal_eval()

注:如果被执行字符串里有类似赋值语句,那么执行后的值会进行覆盖

# 推荐使用 ast.literal_eval()

import ast
s_safe = "['p', 2, 's']"
s_safe_result = ast.literal_eval(s_safe) # 通过输入输出会判断是否是安全的(合法)避免执行到恶意代码
print(s_safe_result) # 会覆盖这个值(拿安全值去覆盖)
print(type(s_safe_result))


['p', 2, 's']
<class 'list'>

一些字符串方法

def p(test):
    print("True     " if test else "False    ", end="")
def printRow(s):
    print(" " + s + "  ", end="")
    p(s.isalnum())
    p(s.isalpha())
    p(s.isdigit())
    p(s.islower())
    p(s.isspace())
    p(s.isupper())
    print()
def printTable():
    print("  s   isalnum  isalpha  isdigit  islower  isspace  isupper")
    for s in "ABCD,ABcd,abcd,ab12,1234,    ,AB?!".split(","):
        printRow(s)
printTable()


  s   isalnum  isalpha  isdigit  islower  isspace  isupper
 ABCD  True     True     False    False    False    True     
 ABcd  True     True     False    False    False    False    
 abcd  True     True     False    True     False    False    
 ab12  True     False    False    True     False    False    
 1234  True     False    True     False    False    False    
       False    False    False    False    True     False    
 AB?!  False    False    False    False    False    True    

lower()upper():大小写转换

print("YYDS YYSY XSWL DDDD".lower())
print("fbi! open the door!!!".upper())

yyds yysy xswl dddd
FBI! OPEN THE DOOR!!!

strip() :可以将字符串首尾的空格删除

print("   strip() 可以将字符串首尾的空格删除    ".strip())

strip() 可以将字符串首尾的空格删除

replace()replace(A,B)将一个字符串中的子字符串A用B替换

print("聪明办法学 Python".replace("Python", "C"))
print("Hugging LLM, Hugging Future LLM".replace("LLM", "SD", 1)) # count = 1 (只换一次,后面如果还有则不会换了)
## 默认是全换(如果后面没有参数)

聪明办法学 C
Hugging SD, Hugging Future LLM

用这个方法还可以把某些字符串删除

(相当于替换为了None)

s = "聪明办法学Python, 就找 Datawhale"
t = s.replace("聪明办法", "")
print(t)
# 还能够通过这样的方法删除字符串中特定字符

学Python, 就找 Datawhale

count():输出一个字符串出现的次数

print("This is a history test".count("is"))
print("This IS a history test".count("is"))
# 大小写敏感
3
2

startwith()endwith():检测该字符串是否是以某个字符串开头(endwith是检测是否以这个字符串结尾)

print("Dogs and cats!".startswith("Do"))
print("Dogs and cats!".startswith("Don't"))
True
False

print("Dogs and cats!".endswith("!"))
print("Dogs and cats!".endswith("rats!"))
True
False

find():找到与子串在字符串内相对应的字符的起始位置

比如下面and起始位置是在序号(角标)为5的位置,返回5

如果找不到,则返回的值为-1

print("Dogs and cats!".find("and"))
print("Dogs and cats!".find("or"))
# 但是如果上面是s,s[-1]能找到,所以这里的-1仅仅表判断
5
-1

index():和上面find()用法一致

都是用于从列表中找出某个值第一个匹配项的索引位置

但是不同的是,index()如果找不到则会报错

print("Dogs and cats!".index("and"))
print("Dogs and cats!".index("or"))
5

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
c:\Coding\Datawhale\Python_Tutorial\learn-python-the-smart-way-v2\slides\chapter_6-Strings.ipynb Cell 112 line 2
      <a href='vscode-notebook-cell:/c%3A/Coding/Datawhale/Python_Tutorial/learn-python-the-smart-way-v2/slides/chapter_6-Strings.ipynb#Y221sZmlsZQ%3D%3D?line=0'>1</a> print("Dogs and cats!".index("and"))
----> <a href='vscode-notebook-cell:/c%3A/Coding/Datawhale/Python_Tutorial/learn-python-the-smart-way-v2/slides/chapter_6-Strings.ipynb#Y221sZmlsZQ%3D%3D?line=1'>2</a> print("Dogs and cats!".index("or"))

ValueError: substring not found

f-string 格式化字符串

x = 42
y = 99

# 里面要用引号的话得是不同的引号
print(f'你知道 {x} + {y} 是 {x+y} 吗?')
你知道 42 + 99 是 141 吗?

其他格式化字符串的方法

如果要格式化字符串的话,f-string 是个很棒的方法,Python 还有其他方法去格式化字符串:

  • % 操作
  • format() 方法

参考资料:

字符串是不可变的

是个常量

但是可以替换后赋值(用字符串方法)

s = "Datawhale"
s[3] = "e"  # Datewhale
# 常量不能直接赋值(list能,但字符串不行)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
c:\Coding\Datawhale\Python_Tutorial\learn-python-the-smart-way-v2\slides\chapter_6-Strings.ipynb Cell 118 line 2
      <a href='vscode-notebook-cell:/c%3A/Coding/Datawhale/Python_Tutorial/learn-python-the-smart-way-v2/slides/chapter_6-Strings.ipynb#Y230sZmlsZQ%3D%3D?line=0'>1</a> s = "Datawhale"
----> <a href='vscode-notebook-cell:/c%3A/Coding/Datawhale/Python_Tutorial/learn-python-the-smart-way-v2/slides/chapter_6-Strings.ipynb#Y230sZmlsZQ%3D%3D?line=1'>2</a> s[3] = "e"

TypeError: 'str' object does not support item assignme

你必须创建一个新的字符串

s = s[:3] + "e" + s[4:] # 把s拆分然后重新赋值给s
print(s)				# 过于繁琐

Datewhale

字符串和别名

字符串是不可变的,所以它的别名也是不可变的

相当于变量名是一个指针(标签)指向(存放)同一组数据

s = 'Data'  # s 引用了字符串 “Data”
t = s      # t 只是 “Data” 的一个只读别名
## 这个别名里面赋的量,只改变s,t不会变的哇
s += 'whale'
print(s)
print(t)
Datawhale
Data
t[3] = "e"
# t本身依然不能直接改变

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
c:\Coding\Datawhale\Python_Tutorial\learn-python-the-smart-way-v2\slides\chapter_6-Strings.ipynb Cell 124 line 1
----> <a href='vscode-notebook-cell:/c%3A/Coding/Datawhale/Python_Tutorial/learn-python-the-smart-way-v2/slides/chapter_6-Strings.ipynb#Y236sZmlsZQ%3D%3D?line=0'>1</a> t[3] = "e"

TypeError: 'str' object does not support item assignment

基础文件操作 Filing

Open() 函数

Open() 函数

Python open() 函数用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数。

文件不存在则会自动创建文件

open(file, mode) 函数主要有 filemode 两个参数,其中 file 为需要读写文件的路径。mode 为读取文件时的模式,常用的模式有以下几个:

  • r:以字符串的形式读取文件。
  • rb:以二进制的形式读取文件。『readbit』
  • w:写入文件。『清空所有内容重新写入』
  • a:追加写入文件。『在指定行数插入内容(看光标指向)一般为末尾』

不同模式下返回的文件对象功能也会不同。

file = open("chap6_demo.txt", "w") # 文件不存在就自动创建
dw_text = "Datawhale"
file.write(dw_text)
file.close()

file = open('chap6_demo.txt', 'r')
print(type(file))
<class '_io.TextIOWrapper'>

文件对象

open 函数会返回一个 文件对象。在进行文件操作前,我们首先需要了解文件对象提供了哪些常用的方法:

  • close(): 关闭文件
  • 在r 与rb模式下:
    • read(): 读取整个文件
    • readline(): 读取文件的一行
    • readlines(): 读取文件的所有行
  • 在 w与a模式下:
    • write():
    • writelines():

下面我们通过实例学习这几种方法:

read()readline()

## 通过 read 方法读取整个文件
# 上文刚写入数据
content = file.read()
print(content)
Datawhale
## 通过 readline() 读取文件的一行
content = file.readline()
print(content)

代码竟然什么也没输出,这是为什么?

因为上述read()了整个文件,此时光标(指针)拉到最后一行末尾,而readline()会读取下一行,而下一行无内容

所以什么也没输出

## 关闭之前打开的 chap6_demo.txt 文件
file.close()
## 重新打开
file = open('chap6_demo.txt', 'r')
content = file.readline()
print(content)

Datawhale

注意每次操作结束后,及时通过 close( ) 方法关闭文件

## 以 w 模式打开文件chap6_demo.txt
file = open('chap6_demo.txt', 'w')
## 创建需要写入的字符串变量 在字符串中 \n 代表换行(也就是回车)
content = 'Data\nwhale\n'
## 写入到 chap6_demo.txt 文件中
file.write(content)
## 关闭文件对象
file.close()

w 模式会覆盖之前的文件。如果你想在文件后面追加内容可以使用 a 模式操作。

with 语句

我不想写 close() 啦!

用this模块演示『python之禅』

import this

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Caesar_cipher = """s = \"\"\"Gur Mra bs Clguba, ol Gvz Crgref

Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
Pbzcyrk vf orggre guna pbzcyvpngrq.
Syng vf orggre guna arfgrq.
Fcnefr vf orggre guna qrafr.
Ernqnovyvgl pbhagf.
Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
Nygubhtu cenpgvpnyvgl orngf chevgl.
Reebef fubhyq arire cnff fvyragyl.
Hayrff rkcyvpvgyl fvyraprq.
Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.
Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.
Abj vf orggre guna arire.
Nygubhtu arire vf bsgra orggre guna *evtug* abj.
Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!\"\"\"

d = {}
for c in (65, 97):
    for i in range(26):
        d[chr(i+c)] = chr((i+13) % 26 + c)

print("".join([d.get(c, c) for c in s]))
"""

用with方法(会自动close掉)

with open("ZenOfPy.py", "w", encoding="utf-8") as file:
    file.write(Caesar_cipher)
    print(len(Caesar_cipher))

    
    
1003

import ZenOfPy也会执行python之禅

import ZenOfPy
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

task06总结

  • 单引号与双引号要适时出现,多行文本用三引号
  • 字符串中可以包含转义序列
  • repr() 能够显示出更多的信息
  • 字符串本身包含许多内置方法in 是一个特别好用的玩意。
  • 字符串是不可变的常量。
  • 文件操作推荐使用 with open("xxx") as yyy,这样就不用写 f.close() 啦。****