Python-2020-fall

来自SUDA-HLT
跳到导航 跳到搜索

Python程序设计课程主页(2020年秋季学期)

Teacher: 李正华

Teaching Assistant: 周厚全、刘泽洋、周仕林

上课时间和地点、QQ群

   周一13:30-15:20卫校301;
   周五13:30-15:20理工楼153
   周二13:30-15:20理工楼238、247(上机);
   python-2020学习交流QQ群:893402501

教材的名字:零基础学习并理解Python 特点:1)把重点放到理解上,建立基本概念;2)重视英语学习,尽可能多的给出英语术语翻译;3)多画流程图、多给出图例,考虑latex画图。

考试安排

三次正式考试

  • 第一次考试:11.11(周三),考试内容:基础、分支、列表、循环 (考试成绩)
  • 第二次考试:12月9日(周三)晚上:元组 字符串 字典 集合
  • 第三次考试(期末):1月
  • 考试形式:上机考试
    • 选择题
    • 编程题:每一道题对应一个函数(给定了函数名,不能随便修改),所有函数放到一个.py文件中

2020.11.3 模拟考试

  • 考试时间:2020.11.3 13:45-15:00
  • 考试题型:5道选择题(不会没关系,快速做完)、3道编程题
  • 模拟考试总结
常见问题:
    a. 语法错误:程序中出现语法问题将会导致判为0分:
        1. if中出现逗号,例如:
            if a0, a1, a2, a3, a4, a5==0:
        2. else后面带表达式:此处应该用elif
        3. 程序不完整(unexpected EOF):例如用if...else...时,else直接一个冒号就结束了,如果想空掉某些位置请使用pass
        4. if后没有冒号
        5. 小于等于运算符写错:应该是<=而不是=<
        6. 重复def
        7. 使用了中文的括号
        8. 缩进问题
        9. 使用未赋值的变量,尤其是在if判断的时候会出现这样的问题,例如:
            if x>0: 
                a = 1
            print(a)
    b. 变量使用问题:在使用一个变量时,应该首先确保这个变量已经被赋值,同上。
    c. 在代码中使用input导致超时:我们调用你的程序会遇到input()导致无限等待。
    d. 误用中括号,例如:
        return x, [.....]/5
    e. 其他审题要清楚,注意特殊情况下的结果是否与题目给出的样例一致。
    
    注意:考试时,提交的.py中不能有input() print()。
 

2020.11.10模拟考试

  • 考试时间:2020.11.10 13:40-15:00
  • 考试题型:1道选择题、3道编程题

Mooc混合式教学

中国大学慕课 Python程序设计 苏州大学 朱晓旭等

请同学们同步学习这个网课。

理论课上,我会留一些时间,来针对网课的内容进行讲解、答疑。

参考资料

实验课安排(有问题多主动问,Python不是教会的,而是不断动手、思考学会的)

实验报告说明

实验报告由两部分组成:

  • 实验报告:学号-exp-x.pdf (x表示第几次实验)
    • 注意文件命名格式,必须用pdf文件
    • 包含题目、流程图、解题思路、运行结果截图、遇到什么问题及如何解决的、总结有哪些收获、对老师的建议
    • 每次会提供一个基本的实验模板,学生按照自己的方式去安排报告的内容
    • 选择三道较难的题目,先画流程图,然后写代码。可以手画流程图然后拍照,也可以用画图软件去画。其他题目不用画流程图。
  • 代码:学号-exp-x.py
    • 把所有题目的代码放到一个py文件中,不要压缩,在提交的时候点击附件,上传相应实验的.py文件。
    • 注意可读性,方便老师批改,可以写一些必须的注释

注意事项:

  • 抄袭会严惩!当次实验成绩清0!
  • 实验报告、代码,要保留好,不要删除,期末的时候可能要统一放到一个文件夹中,交给老师。
  • 除了基本的题目,还可以额外做老师在课堂上提出的思考题、扩展题。
  • 根据认真程度、完成的质量、可读性等,来综合评分
  • 每次作业批改后,会在理论课或上机课上进行讲解,重点是讲大家常见的错误。
  • 如果系统中没有给出分数,则可以撤销提交并重新提交。

往年的习题集:

扩展题目(选做,可以放到实验报告中)


顺序结构题目:
1)输入三个变量的值,然后按小到大顺序输出。
2)BMI指数(身体质量指数,Body Mass Index)是目前国际上常用的衡量人体胖瘦程度及是否健康的一个标准。
体质指数(BMI)=体重(kg)÷身高^2(m)
3)编写程序实现华氏温度到摄氏转换
    转换公式:
摄氏度C=(华氏度-32)乘以(5/9)
华氏度F=32+(9/5) 乘以 摄氏度C
4)从键盘输入一个三位整数n,输出其逆序数m。例如,输入n=127,则m=721。

-----
分支结构题目:
(1)判断年份year是否为闰年。
(2)判断ch是否为小写字母。
(3)判断m能否被n整除。
(4)判断ch既不是字母也不是数字字符。
(5)输入年月,求该月的天数。
(6)输入一个时间(小时:分钟:秒),输出该时间经过5分30秒后的时间
(7)根据bmi情况,输出不同的信息:
if bmi<18.5:
    print("过轻")
elif bmi<25:
    print("正常")
elif bmi<28:
    print("过重")
elif bmi<32:
    print("肥胖")
else:
    print("非常肥胖")

-----
循环结构题目:
  从m到n数字求和
  判断一个数字是否为素数(质数)
  判断一个字符串是否为回文('abccba', 'aba')
  求一个浮点数(>0)的根号,可以有多种方法。例如:平方根迭代公式x1=1/2*(x0+a/x0)
  求两个整数a与b的最大公约数、最小公倍数
  输出[100,1000)以内的全部完数(因子之的和等于自己,如6=1+2+3)
  用字符'*'输出不同的形状,如等边三角形,等腰三角形,直角三角形
  打印9*9乘法表
  
角谷猜想:
是指对于任意一个正整数
如果是奇数,则乘3加1
如果是偶数,则除以2
得到的结果再按照上述规则重复处理
最终总能够得到1

欧几里得算法(辗转相除法)求最大公约数
num1,num2=eval(input("请输入两个正整数"))
if num1<num2:
    num1,num2=num2,num1 #保证num1大
while num1%num2!=0:
    temp=num1%num2
    num1=num2
    num2=temp
print("最大公约数是:",num2)

哥德巴赫猜想
哥德巴赫->欧拉
任一大于2的偶数都可表示为两个素数之和
1+1
陈景润
任何一个充分大的偶数都可以表示成一个素数和一个不超过两个素数的乘积之和
1+2

猜数字
计算机产生一个1-10000之间的随机数
人去猜
计算机提示
偏大
偏小
猜对
显示猜的人所猜的次数

-----
列表扩展题目:
例:给定一个数字列表,将每个元素求修改为其绝对值,然后返回该列表
l9 = [1,-3.39,7,-999]

例:从键盘输入数字到列表(输入非数字则停止),并对列表进行排序(从小到大),然后返回列表

例:给定一个列表,返回某元素在列表中的所有下标,作为一个列表返回
l1 = [1,'a',2,3]
value = 1

例:实现reverse功能

例:二分查找(一定要亲手实现一下)

例:排序算法

例:矩阵乘法实现:随机产生矩阵中的数字,用嵌套列表来存储

  • 2020.10.26:输出当前时间,新输出的时间刷新旧时间。(提示,利用退格符,PyCharm可以,用cmd也可以,IDLE不行)
  • 2020.10.23:求平方根,是否还有其他更快的解法(之前讲的是二分查找)
  • 2020.10.15:把求平方根的代码,扩展为x为任何大于0的浮点数。注意一定要先画流程图。

思考题目

  • 有100只一模一样的苹果,编号1-100。其中99个是正常的,一个被注射了毒药。只要老鼠咬一口毒苹果,一天后则死亡。现在,你有7只老鼠和一天的时间,如何检验出哪个号码的苹果被注射了毒药?
  • 蒙特卡洛法求圆周率 pi。正方形面积、圆的面积。当然,圆的面积公式又是怎么来的呢?

实验课常见问题

2020.10.20:

  • input()函数从用户得到的输入类型是字符串,不能直接进行数值的运算,需要类型转换。
  • 希望一次性input多个数字,可以用字符串split方法:
    • lst = list(map(int, input('please input:').split())) #一次性输入多个数字,按空格隔开;并存储到一个列表中
    • x, y, z = eval(input('please input two int, using comma as the delimiter: ')) # 输入 3, 5, -4
    • lst = eval(input('please input a python list: ')) # 输入 [3, 5, -4],中括号必须有,作为列表对象存储
    • a_tuple = eval(input('please input several int, using comma as the delimiter: ')) # 输入 3, 5, -4,作为元组对象存储
  • 注意变量 x 与字符串 "x" 之间的区别。

第一次实验报告 2020.10.20 python语言基础

  • 截止时间:11月4日20:00前
  • 报告模板(含基本题目),见csteaching

第二次实验报告 2020.11.3 顺序结构程序设计

第三次实验报告 2020.11.10 选择结构程序设计

  • 截止时间:11月28日20:00前
  • 报告模板
  • 学生建议:
 建议拓展题目不要有包含关系或同类题目,最好少而难。
 希望老师能在实验报告后对较难的题目给出较为简便高效的代码,以便于学习。
 希望老师上课多讲点知识,有条理一些。
 每节理论课可以在群里提前说一下下节课内容,有所准备的话,在课上可以更好的理解。
 希望老师能够对稍微大型些的程序做些分析和讲解。

第四次实验报告 2020.11.17 列表

  • 截止时间:12月01日20:00前
  • 报告模板
  • 学生建议:
 希望课程主页上能多更新一点课外拓展的题目。另外,希望老师能提供一点选择题的资料或者练习之类,或者以往几届考试的选择题和题库都可以。
 希望老师可以讲讲多个循环嵌套的例子。
 建议老师在每次实验报告截止日期后发一份标准答案,并在上机课上讲解较难的题目。
 对老师的建议是希望可以把魔方阵简单说一下。
 建议老师上课把重点函数点出来,过一遍基本没人能记住,有些不常用的看一眼就行了
 希望老师讲快一点

第五次实验报告 2020.11.24 循环结构程序设计

第六次实验报告 2020.12.01 字符串与正则表达式

第七次实验报告 2020.12.08 元组、字典、集合

 9. 使用random模块生成一个整数类型的随机数集合:从0到9(包括9)中随机选择一个数n作为集合大小,生成n个[0,1000]范围内的随机数,这些数字组成集合A。同理,按此方法生成集合B。在此基础上实现以下功能:
   a) 显示A和B的结果。要求每行最多显示10个数,每个数占5列,右对齐;
   b) 要求用户输入 A | B 和 A & B 的结果,并告诉用户他(或她)的答案是否正确。如果用户回答错误,允许他(或她)修改解决方案,然后重新验证用户输入的答案。如果用户三次提交的答案均不正确,程序将显示正确结果。

讲给同学们的话

大学生活、学习的一些建议

  • 计算机英语很重要(1000左右单词),有助于理解和记忆;
  • 逻辑思维能力很重要,从流程图(或伪代码)锻炼起;
  • 多动手、多练习、多思考、多尝试,才能学好编程;
  • 编程只是计算机科学与技术这门学科的最基本能力。要想成为顶尖的编程高手,必须对计算机的硬件、操作系统、数据结构、算法等基础理论理解透彻,所以要长期坚持,不断提高自己的计算机素养和基础。
2021.1.1 元旦,少一次课
2020.10.23 少一次课。希望大家利用各种资源,抓紧学习。我的课主要以理解为主,把知识串起来。要学好python,要不断写代码、调试。要靠自己
第5周周五少了一次课

讲义记录

TODO

 

正则表达式 函数 模块 文件 异常 

6次课:11 14 18 21 25 28

函数:
递归函数
函数作为参数 sort(key = )
lambda
函数参数:位置型、关键字类型
默认参数


标量Scalar(integer, floating-point number, boolean)
矢量Non-Scalar(字符串string等)


python的特点
high-level(python > c++ > c > 汇编)
   C语言能做的,Python都能做?感觉不一定
解释性(interpretative)
面向对象(object)
跨平台、移植性高
2.0和3.0不兼容,语法有一些小的变化

学习朱晓旭老师的PPT

 
in和not in 测试(成员测试,列表、字符串等)

isinstance(3, int)
用单引号或双引号括起来的字符串不可跨行
用三引号括起来的字符串可以是多行的

格式字符串:% format() str.format()

原始字符串:如果不希望字符串转义,前面加r
r”\n”

如果转义后没有意义,那么就是两个字符,如'\A'

转义字符:以反斜杠“\”开头,后跟一个或多个字符(反斜杠称为转义字符,表示的字符称为特殊字符?怎么说比较清晰呢,得看看英文文献,确认一下?)

转义字符具有特定的含义
  不同于字符原有的意义,故称转义字符,
  主要用来表示那些用一般字符不便于表示的控制代码

eval()函数
其调用格式为:  
eval(字符串)
作用是把字符串的内容作为对应的Python语句(表达式?)来执行


逗号:分隔符(元组)

表达式:
单个任何类型的对象或常数
使用运算符连接的变量和常量
函数调用的任意组合

什么是表达式?eval('x=3') vs. x=eval('3')

dir(__builtins__)

可以使用sys.modules.items()显示所有预加载模块的相关信息。


Python代码规范(摘自朱晓旭老师PPT)

缩进:
    类定义、函数定义、选择结构、循环结构,行尾的冒号表示缩进的开始
    python程序是依靠代码块的缩进来体现代码之间的逻辑关系的,缩进结束就表示一个代码块结束了。
    同一个级别的代码块的缩进量必须相同。
    一般而言,以4个空格为基本缩进单位,可以通过下面的方法进行代码块的缩进和反缩进:

注释:
    一个好的、可读性强的程序一般包含30%以上的注释。常用的注释方式主要有两种:
        以#开始,表示本行#之后的内容为注释
        包含在一对三引号'''...'''或"""..."""之间且不属于任何语句的内容将被解释器认为是注释

每个import只导入一个模块

如果一行语句太长,可以在行尾加上\来换行分成多行,但是更建议使用括号来包含多行内容。

必要的空格与空行:
    运算符两侧、函数参数之间、逗号两侧建议使用空格分开。
    不同功能的代码块之间、不同的函数定义之间建议增加一个空行以增加可读性。

适当使用异常处理结构进行容错,后面将详细讲解。

软件应具有较强的可测试性,测试与开发齐头并进。

函数

模块

模块基础:package(包)等以后再学习

random模块的学习和使用

什么是模块?py文件,文件夹组织时,如何import?【后期还会专门学习一下】

help(dir)

dir(math)

help(random)

dir(random)

help(time)

dir(time)

help(time.ctime)


Python默认安装仅包含部分基本或核心模块,但用户可以安装大量的扩展模块,pip是管理模块的重要工具。
在Python启动时,仅加载了很少的一部分模块,在需要时由程序员显式地加载(可能需要先安装)其他模块。
减小运行的压力,仅加载真正需要的模块和功能,且具有很强的可扩展性。
可以使用sys.modules.items()显示所有预加载模块的相关信息。

import 模块名
>>>import math
>>>math.sin(0.5)               #求0.5的正弦
>>>import random
>>>x=random.random( )    #获得[0,1) 内的随机小数
>>>y=random.random( )
>>>n=random.randint(1,100) #获得[1,100]上的随机整数
可以使用dir函数查看任意模块中所有的对象列表,如果调用不带参数的dir()函数,则返回当前脚本的所有名字列表。
可以使用help函数查看任意模块或函数的使用帮助。


from 模块名 import 对象名[ as 别名] #可以减少查询次数,提高执行速度
from math import *    #谨慎使用
>>> from math import sin
>>> sin(3)
0.1411200080598672
>>> from math import sin as f #别名
>>> f(3)
0.141120008059867

如何自己写一个模块。模块和引用py文件的路径问题?

time模块


字符串、进制、raw字符串?正则表达式

正则表达式

Linux课讲义:文件:Linux-RE.pdf


RE是满足正则语言语法的一个字符串,作为一个抽象的模式,用以匹配一个、多个甚至无穷多个实际的字符串。
主要用途:匹配 抽取 替换
支持RE的东西
  C++ Java Python
  Linux:egrep sed vi编辑器
  ...

re模块
match search两个函数


re.MatchObject
group() 返回被 RE 匹配的字符串。
start() 返回匹配开始的位置
end() 返回匹配结束的位置
span() 返回一个元组包含匹配 (开始,结束) 的位置

group groups(后面专门讲分组的概念,然后再讲groups)

match和search早点讲:re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 re.search 匹配整个字符串,直到找到一个匹配。
后面举例的时候,就可以两个切换着用

re.M多行模式啥意思?
re.I|re.M这个flag是啥意思?肯定是按位操作。这个好玩:)
re.I 忽略大小写
re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
re.M 多行模式
re.S 即为' . '并且包括换行符在内的任意字符(' . '不包括换行符)
re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
re.X 为了增加可读性,忽略空格和' # '后面的注释

自定义字符集
[ ] 字符集, [^ ]补集

预定义字符集
 \w [ [:alphanum:]]
 \d [ [:digit:]]
 \s

. 任意一个字符,不能匹配\n\r

重复修饰符(默认为贪心greedy匹配最长的字符串)
  * 表示前面的字符匹配0次到n次
  ? 表示可取0个/1个
  + 重复一次到无穷多次
  {3} 重复3次
  {3,5} 3次到5次
  {3,} 3次到无穷
  *? ?? +? {3,}? 不贪心匹配

分组group () 

| 或Alternation 

定位符anchoring
  ^表示行首
  $表示行尾
  \< \>表示单词的首/尾
  \b表示单词边界
  \B表示非单词边界

compile可以晚一点讲

正则表达式字符串的解析步骤:
1)先解析为一个普通字符串,按照字符串语法(主要是转义字符/问题),所以推荐用raw
2)进而解析为正则表达式,按照正则语法

扩展正则表达式 vs. 基本正则表达式语法 涉及这个问题吗?

re.sub(pattern, repl, string, count=0, flags=0)

repl 参数是一个函数

pattern = re.compile(pattern[, flags])

re.findall(pattern, string, flags=0)
或
pattern.findall(string[, pos[, endpos]])

re.finditer(pattern, string, flags=0) (返回迭代器)

re.split(pattern, string[, maxsplit=0, flags=0])

re.RegexObject
re.compile() 返回 RegexObject 对象。





??法则??


字符串 进制 海象运算符 位运算


-----

字符和数字的转化(不同进制)【不同进制的格式化输出】

print(0xff, 0o377, 0b11111111, 255)

默认的字符串表示,其实内存中都是一样的哈

进制转化函数:返回字符串
hex(255) # 十六进制,hexadecimal
bin(255) # 二进制: binary
oct(255) # octal

-----
整数格式化时的进制转化:
x和X:十六进制
o:八进制
b:二进制(%不支持)

'%#x' % 255

'{0:b} {0:d} {0:o} {0:x} {0:#X}'.format(255)  # '11111111 255 377 ff 0XFF'

-----
汉字的表示(UTF-8/16/32编码的细节不讲),python对字符串默认是采用UTF-8编码。python文件必须是utf-8编码,才可以正常运行?UTF-16编码到底是什么样子的?
如何避免编码问题?不要用中文字符

http://www.asciitable.com/ ascii码表

每个字符都有多种表示:八进制、十六进制
print('\61', '\061', '\x31')  # '\X31' '\o31'都不对

ord('a')  # 字符对应的ASCII码(American standard code for information interchange)
chr(97) # 返回与ASCII码对应的字符

-----
raw字符串


-----
海象运算符,可在表达式内部做变量赋值(walrus operator)
The purpose of the walrus operator is to consolidate an assignment statement and a boolean expression when both assignment and expression would utilize a similar statement.

:=	
在这个示例中,赋值表达式可以避免调用 len() 两次:

if (n := len(a)) > 10:
    print(f"List is too long ({n} elements, expected <= 10)")
if结束后,n还活着

函数的地方会讲:变量名字的生命域

C++支持吗?
if (int i = len(a) < 10) {
}

C++支持:
for(int i=0; i < 10; i++) {
}

python:
for i in range(10):
  ...
for循环结束后,i还活着

-----
位运算

& | ^异或 ~ << >>

a = 60            # 60 = 0011 1100 
b = 13            # 13 = 0000 1101 
 
c = a & b         

负数的补码表示(按位取反+1,注意python的int没有上界,补码理解起来就有点微妙)


python字符集

Python-2020-fall-python_character_set

2020.12.11 进制,字符8/16进制表示,raw字符串,海象运算符,位运算

进制:指一个数字按照多少进一个位。
    十进制:0    1    2    3    4    5    6    7    8    9    10,按照10次进一个位。
    二进制:0    1   10   11  100  101  110  111,按照2次进一次位。
    八进制:0    1    2    3    4    5    6    7   10   11    12,按照8次进一个位。
    十六进制:0  1    2    3 .. 8    9    A    B    C    D    E    F    10,按照16次进一个位,阿拉伯数字不够用字母来补。
    相应英文:十进制 decimal;二进制 binary;八进制 octal;十六进制 hexadecimal (hex)
    注:我们之前字符串的格式化%d就是来格式化成十进制,%o是八进制,%x是十六进制。
进制的转换:
    所有的进制转换为十进制可采用如下方法:
        例如:(10011)2 = 1*2^4 + 1*2^1 + 1*2^0 = 16+2+1 = 19
              (362)8 = 3*8^2 + 6*8^1 + 2*8^0 = 192+48+2 = 242
              (AF)16 = 10*16^1 + 15*16^0 = 160 + 15 = 175
    16进制,8进制和2进制相互转化时,因为16和8分别是2的4次幂、3次幂,转化十分有技巧。自己查资料。
python的进制:
    hex(); bin(); oct(),分别是可以把一个int转化为16进制,2进制,8进制的字符串。
    字符串format()方法:'{0:b} {0:d} {0:o} {0:x} {0:#X}'.format(255),这个语句输出 '11111111 255 377 ff 0XFF'
    int数字型:print(0xff, 0o377, 0b11111111, 255),分别是16进制、8进制、2进制、10进制的int数字对象。
    用%来格式化:'%d%o%x' , 分别对应着十进制八进制十六进制,没有%b。
    进制的转义字符:print('\101', '\x31'),第一个是八进制,第二个是十六进制,分别输出'A'和'1'(相应值的ASCII码对应的字符),
        注意:十六进制必须传入两位,八进制最多传入3个位,不够可以补0 (ASCII码0-255)
              '\9'会输出'\\9',事实上,python会自动把\当做转义字符,但是找到\后面的9,又没有这样的转义,就默认把\当成一个字符了,而不是转义。
              '\b'不是二进制,是退格符;八进制就直接在'\'后跟小于8的数字。
ord()和chr():前面讲过,ord()用来找到某个字符的ascii码值,chr()把相应ascii码值转化为字符。

海象运算符(walrus operator,python3.8开始支持):
    海象运算符':=',可在表达式内部为变量赋值。
    在以下示例中,赋值表达式可以避免调用 len() 两次:
    if (n := len(a)) > 10:
        print(f"List is too long ({n} elements, expected <= 10)")

位运算:以二进制的位为单位来操作。(计算机数字用补码存储,补码是什么,以后有空讲)
    & | ^ ~ >> <<
    例:A = 60,B = 13,以二进制表示,A = 0011 1100,B = 0000 1101
    & 且操作符:A & B = 12,即0000 1100,A和B相应位必须都为1才是1。
    | 或操作符: A | B = 61,即0011 1101,A和B相应位有一个为1就是1。
    ^ 异或操作符:A ^ B = 49,即11 0001,相同取0,相反取1。
    ~ 非操作符:~A = -61,涉及到补码的运算。
    << 左移:A>>1 = 30,所有位向右移一位,和整除2效果一样。
    >> 右移:A<<1 = 120,所有位向左移一位,和乘2效果一样。
    注:注意优先级。

raw (未处理的,即网络常用用语:生肉)字符串:主要用于正则表达式 (Regular Expression),通常RE不用处理特殊字符。
    简单来说就是去除转义。去除字符串中的转义。
    例:r'\b'就是'\\b'

正则表达式 (Regular Expression):一个RE是一个字符串,满足正则语言的语法,用以匹配一个或多个甚至无穷个具体的字符串。
    用途:匹配,抽取,替换。
    支持RE:C++;Java;Python;Linux;egrep;sed;vi编辑器。
在python中使用RE:
    re模块,import re

win10使用linux:Ubuntu
https://blog.csdn.net/daybreak222/article/details/87968078
 

2020.12.7 字典,集合

第二次考试:12月9日 周三 晚上,元组/字符串/字典/集合。
实验报告和代码:抄袭,肯定零分,几个人互相抄就几个人零分,有问题找老师商量。认真写实验报告,锻炼并提高自己的表达能力。
   实验报告中同学们提了很多建议:非常感谢!

字典dict

定义:
1) {} # 空字典
   {1:'a', 2:'b'} # 包含两个元素(键值对)的字典
2) 工厂函数dict (zip生成函数可以每次返回一个对)
    例:l1 = [1, 2, 3]
       l2 = [4, 5, 6]
       d1 = dict(zip(l1, l2))
    结果:d1的值为{1:4, 2:5, 3:6}
    d2 = dict([[1,'a'],[2,'b'],[3,'c']])

字典的特点:
    可变:元素可以增加、可以删除、可以修改value
    key值唯一,不同key对应的value值可以是相同的(甚至可以绑定到同一个对象上) (可以用字典来实现存储一个班的成绩,key是学号,value是成绩) ;
    无序(字典中的元素没有固定的顺序)
    可迭代但不是序列 (不可用下标索引随机访问)。
    key必须是完全不可变对象(即可哈希对象),value可以是元组、列表、集合等任意一个数据类型。
    字典不是用平衡二叉树存的,现在是用哈希表(hash table)来实现的
        https://www.laurentluce.com/posts/python-dictionary-implementation/
遍历:
    in;not in:判断一个key是否存在于字典中(==)
    1 in d1 -> True

    for i in d1:
        print(i, d1[i])   
    for i in d1.keys():
        print(i, d1[i])
    for i in d1.items():
        print(i[0], i[1])
    for (i,j) in d1.items():
        print(i,j)

[]操作符:在字典中,[]内部应该放key值,通过key来访问字典的value。
    例:d = {'li':4, 'zheng':5, 'hua':6}
        print(d['zheng'])
    输出:5
    如果key不存在,会抛出KeyError异常

del d1[1]:删除key为1的元素

字典在内存中的存储方式?自己画一下。非常重要!

思考:什么样的操作会修改字典?
    如果字典中,某一个key对应的value是列表,你修改了那个列表,其实并没有修改字典。

不是序列的可迭代对象:
range
reversed
dict
set
file
dict_keys # 思考,如何判断dict_keys对象不属于序列?
dict_items


内置函数:以前讲过的函数都是面向全部可迭代对象的,字典当然也是。
    例如:len; str; type


字典的方法(增删改查)
    'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'

    d1.fromkeys(),传入一个可迭代对象进去,根据可迭代对象的每个值作为key,来返回一个新的字典。
        例如:dict.fromkeys('abcde'),返回{'a':None, 'b':None, 'c':None, 'd':None, 'e':None }。
        可以看出.fromkeys()是一个静态(static)方法,即属于类的方法(类级别的方法),不会修改具体对象。调用静态方法时,既可以通过对象调用,也可以通过类名调用。
    d1.get(),可以返回字典的某个key的value,如果key不存在返回默认值。
    d1.items(),返回一个字典的键值对可迭代对象。


字典嵌套,例如:
    d = {'lizhenghua':{'name': 'lizhenghua', 'number': 001, 'grade': 100}, 'zhenghuali':{'name': 'zhenghuali', 'number': 002, 'grade': 100.0}}
    这样就可以很方便的去访问某一个人的信息。例如d['lizhenghua']['grade']就会返回100这个分数了。

字典的拷贝:
    拷贝:创建一个新的dict对象,包含原字典的key,value不拷贝(对可变对象有影响)。
    深拷贝:key不需要拷贝,因为key本身就是完全不可变对象。
        value遇到非完全不可变对象就会进行深拷贝,即创建一个新的和value相同的对象,并且对于value中包含的非完全不可变对象,也会递归地进行类似的深拷贝。
        例如,对于([1,2,(3, [4])], 5),深拷贝时会新创建
            元组,值为([1,2,(3, [4])], 5)
            列表:值为[1,2,(3, [4])]
            元组:值为(3, [4])
            列表:值为[4]
        这块不容易理解。深拷贝的基本原则就是:如果一个对象不是完全不可变对象,那么深拷贝时就会创建一个与其值相同的新对象,并进一步递归处理其包含的对象
        讲课的视频中,也给了几个例子。

什么样的对象可作为key?(在上方已经提到过)
    做个实验:可否自己写个类,属于可变对象(例如包含若干int数据变量名字,但是可以改变名字绑定),但是同时又定义了__hash__(),这时候这个类对象是否可以作为key?

----- 
其他资料:

d1 = {1:'Jan',2:'Feb','Mar':3,'Tuesday':2}

[]操作符
    d1[1] = 'Monday'
    d1['a']=3
    d1['b']=[1,2,3]
    d1['b'].append(4)

del d1['a']

拷贝
d6={0:[1,2,3],1:[4,5,6]}
d7={}
d7[0] = d6[0]
d7[1] = d6[1] # 浅拷贝
d7 = dict(d6) # 前面三行等价于这一行


-----
字典嵌套:用字典设计比较复杂的数据结构

方法一,比较死板,可读性比较差
d2={}
d2['001']=['name','M',99,97,30]
d2['002']=['name2','f',99,99,80]
d2['001'][2]

方法二,可读性更好,字典嵌套字典
d3={}
d3['001']={'name':'zhenghua','gender':'M','grade':{'python':99,'C':90}}
d3['001']['grade']['python']

for i in d3:
    if d3[k]['name']=='zhenghua':
          print(d3[k]['grade']['python'])  

集合:set, frozenset

集合:只有key没有value的字典。可以用于去重。集合内不允许有重复元素(即元素的值不能相同)。

定义方法:
1){}:{1, 2, 3},定义一个含有三个元素的集合。
  s1 = {3,5,3,7,'a','a'}  # {'a',3,5,7},去重作用
2)工厂函数:
  set('abcd') # 参数要求是可迭代对象
  s5 = set([23,3,7,3])  # s5={3,7,23} 去重
  空集合定义:set()  # {}定义空字典

特点:可变、元素值唯一、无序、可迭代容器

什么样的对象可以作为集合元素?
   必须是完全不可变对象。

那么有深拷贝的说法吗?
   当然没有了,集合里的元素已经是完全不可变对象了。

遍历:in; not in
s1 = {3,5,'a','cxb'}  # 无序
3 in s1  # True
'cxb' in s1  # True
for i in s1:
    print i   # 集合是可迭代对象,不支持索引。

[]操作符:集合不支持!

del:因此也不能用del来删除某一个元素

集合的方法:'clear', 'copy', 'discard', 'pop', 'remove', 'update'
    s1 = {'a','cxb',5,3} 
    s1.add('abc') # 集合中增加一个元素(集合中不可增加可变对象)。
    s1.add((1,2,3))  # 嵌套一个元组对象
    s1.remove(3) # 移除
    s1.discard(3) 
    s6.update([1,3,5]) # s6 = {'o','h','l','1','3','5'} # update的参数必须为可迭代对象,这个方法很重要!
    
集合的运算:
    'difference', 'intersection', 'symmetric_difference', 'union', 
    'isdisjoint', 'issubset', 'issuperset',
    'difference_update', 'intersection_update', 'symmetric_difference_update', 
    
    s6 = set('holiday')
    s7 = set('hello')
    s8 = set('ho')
    s9 = set('hello')  # s7和s9不是同一个对象
    s10 = set(s6)

    s8 < s9 # True  s8是s9的真子集
    s8 <= s9 # 判断s8是否是s9的子集
    s6 | s7 # 求s6和s7的并集
    s6-s7 # 求s6和s7的差集
    s6^s7 # s6和s7异或

    s6.difference(s7) #差集
    s6.intersection(s7) #交集
    s6.union(s7) #并集
    s6.symmetric_difference(s7) # 异或
    s6.intersection_update(s7) # s6中的元素是s6和s7的交集:s6 = {'o','h','l'}

frozenset和set的区别:frozenset是不可变的set,因为set的全部元素必须是完全不可变对象,所以frozenset是完全不可变的。
fs1 = frozenset(s1)
fs2 = frozenset([1,2,3,2,1]) 

2020.12.4 字符串格式化、字典

默认的格式化:每个对象都有字符串表示,以便print,以便调试debug(这是python设计理念的一个非常大的优点)
    obj.__str__(),对象格式化为字符串的默认方法,print时会隐式调用这个方法
    obj.__repr__(),提供给python解释器的

建议大家做一个实验,自己定义一个类。看看定义__str__()和__repr__()的效果是什么。
    如果不定义,由于每一个类都应该继承object,因此会默认继承object的__str__和__repr__方法,即格式化为'类名+对象内存地址'


f = 2/3
f.__str__()    # 对于小数点位数比较多的浮点数,__str__有一个默认的输出精度。
print(f)
f.__repr__()
'%10.2f' % f

'%20s' % [1,2,3]  # 列表对象当成字符串来做格式化,隐式调用了__str__()
print([1,2,3] # 隐式调用了__str__()

格式化的定义:以某种格式将n个相同类型或不同类型的对象转化为一个字符串。四种方法:

1. %
2. str.format()
3. f'' 不常用
4. format() 不常用


-----
%操作符方法,%为一个二元操作符:
    形式:'formatting-str' % (a, b, c) (注意后面元组的元素数量要和前方数量对的上)
    例: 
    
    '%d' % 3.1  # '%d'的意思是将对象按照整数来对待,进行格式化。bool、int、float都可以,其他类型的对象(str等)都不可以的,会报错。
    '%10d' % 3 -> '         3' # 为这个整数设置尺寸为10,不够默认用空格填充。
    '%010d' % 3 -> '0000000003' # 也是设置整数尺寸为10,不够指定0来填充。
    '%10d %5s %7.2f' -> '         7   abc    3.74',# '%5s'是指定宽度为5的字符串,'%7.2f'是指定总宽度为7的浮点数,精度为2。不够的都默认用空格填充。

除了runoob,这个网页介绍得也比较系统:https://www.cnblogs.com/songdanlee/p/11105807.html

类型(typecode):
    形式:%[(name)][flags][width][.precision]typecode,
      中括号[]表示参数是可选的(optional)
      name为字典参数,具体怎么用,可以自己研究下
      flags对齐和填充标志
      width字符串整体宽度,如果设置过小则无效
      precision浮点数精度(小数点后的位数)
          精度和有效数字不同,0.001的有效数字是3,0.100的有效数字是3
          注:按精度截取时,不一定会按照十进制去四舍五入,而是和计算机存储浮点数(二进制)的原理有关。
              '%.2f %.2f' % (3.155, 3.165) -> 3.15 3.17
      typecode类型编码,即d、f、s等
        %d 整数(十进制);%f 浮点数;%s 字符串;
        %c 字符(char),对应参数必须为长度为1的字符串,一个ascii码转化为相应字符'A'是65,'a'是97。
            ord(),返回一个字符的ascii码(十进制数字),chr()可以把一个ascii码转化成相应字符。
        %e =E,转化为科学计数法数字。
            %e和%f如果不指定精度,默认会保留到小数点后6位。
            科学计数法:45e-5 9.34e2

        %g =G,根据值的大小,选择正常输出,或科学计数法。【没搞明白,我从没用过】
        %o、%x分别表示八进制和十六进制,等后面会系统讲解,oct hex bin
        %%:输出literal的%


一些其他例子:
    '%d %d --- %d' % (3, 4, -7)  # '3 4 --- -7'
    '%10f\n%10f\n%10f' % (9.9, 12.754, 3.34)
    '%6.3f\n%6.3f\n%6.3f' % (9.9, 12.754, 3.34)   # 占6个字节,小数点后保留3位
    '%10s' % 'hi'   

思考一个编程题目:输出n以内的乘法表,并且用今天的知识对齐,格式化输出。

字符串format()方法:用{}和:来代替%。可以接受很多参数,顺序也可以指定。
    通过runoob系统学习:https://www.runoob.com/python/att-string-format.html
str.format的优势:1)可以不指定对象类型,使用对象的默认字符串表示;2)可以重用(多次使用)一个参数;3)可以用dict等复杂类型等(很方便)
    例如:'{:.2f} {:3d} {:5s}'.format(34.2313, 1, 'sca'),返回'34.23   1 sca  '
    还可以在{}内:的前面指定位置,选择format里面的哪个参数。
        例如:'{1:.2f} {0:3d}'.format(1, 34.2313),返回'34.23   1'
    还可以使用关键字参数:'{name} -> {score}'.format(name='zhenghua', score=98)  # 这么写有啥意义呢?感觉在绕弯路。也许有些情况下是有意义的。
    字典参数:'{name} -> {score}'.format(**d1) # 其中,d1={'name':'zhenghua', 'score':98, ...} # 这样用对吗?看看runoob的例子,自学一下。
    列表参数: '{0[0]}.format([1,2,3])

-----
字典

先思考一件事情,如何去把一本书里,全部的字都统计出它们的出现次数。(统计词频)
考虑列表存储[['li', 1], ['zhenghua', 1], ...]
     如果列表不排序:从左向右按顺序查询是否存在,如果存在则更新(频率+1),否则在最后位置appen。查询的时间复杂度都是O(n),插入的时间复杂度是O(1)。
     如果列表排序,那么可以用二分查找,查询是否存在的时间复杂度为O(logn),但是插入时,要保证排序,因此需要把插入位置后面的元素统一后移,因此插入的时间复杂度为O(n)。
字典为此而生,查询和插入的复杂度都为O(logn)【如果想琢磨怎么做到的,可以给一个提示:内部用平衡二叉树来实现】。

字典(dictionary, dict):容器,可迭代,但是不是序列。每一个元素有key和value一个键值对,key需要是完全不可变对象且不能重复,value可以是任意对象。
    在字典中,我们可以通过key,来得到value。

定义方法:
    d1 = {a:b, c:d},直接定义。
    d1 = dict([(1, 2), ('abc', 3)]),用工厂函数,传入一个可迭代对象,每次返还两项,这个例子会返还{1:2, 'abc':3}
       zip函数在这个地方很常用

字典的特点:
   可变;
   key唯一;
   无序,即不能假设key的顺序(用平衡二叉树存储的);
   可迭代,但不是序列。

 

2020.11.30 字符串,字符串的方法,字符串的格式化

字符串的拼接:s1 += s2,和s1 = s1 + s2是一样的,创建新的对象。
字符串的乘法:s1 *= 3,和s1 = s1 * 3一样,也会创建新的对象。

python的优化:对于完全不可变对象,无论是浅拷贝,还是深拷贝,都只是做名字绑定,不会新创建对象。
    s2 = str(s1),虽然str()是一个工厂函数,但是s2仍然和s1是同一个对象,对于"完全"不可变对象s1没有被复制。再例如:
    t1 = ((1, 2), 3, 'abc')
    t2 = tuple(t1)
    此程序,t1和t2的id完全相同,即使是deepcopy也会是完全一样的id。

序列浅拷贝的几种方法:工厂函数;全切片;x1 = x2 * 1;copy.copy
序列深拷贝的方法:copy.deepcopy

如何更深入的学习Python?
    学习C/C++,这样才可以了解底层:C++ Primer; STL源码剖析(侯捷);Effective C++;More Effective C++
    深入学习和理解python的底层,例如Python源码剖析

in和not in:在一个序列里找到某个元素是否存在。对于字符串,是看一个“子串”,是否存在。而不仅限于一个字符!
    例如:'ab' in 'abcd'会返回True。

    for i in 'abcd':
        ...
    遍历(迭代iterate)时,会把每一个字符作为单位。为什么是这样呢?为什么不是每两个字符作为一个单元?这是由__iter__()这个特殊方法来决定的。
    同学们可以自己写一个类,然后实现__iter__(),来决定如何遍历。如果没有实现__iter__()方法,那么这个类型的对象就不可迭代。

str可以转化为list/tuple对象,例如:list('string')会返回 ['s', 't', 'r', 'i', 'n', 'g']。

list也能转换为str。事实上,所有类型的对象都可以转换为字符串对象。
    __str__()和__repr__()这两个特殊方法在起作用
    如果你自己写了一个类,没有定义__str__()和__repr__(),那么默认是类型名和内存地址。大家可以做实验试试。

下标索引、切片:
s = 'abcdef' # 下标s[1]='b',s[-1]='e'
s[3:5] # 'de'
s[3:] # 'def'
s[:3] # 'abc'
s[1:5:2] # 'bd',步长为2
s[-5:-2] # 'bcd'
s[::2] # 'ace'
s[::-1] # 'fedcba'
s[-2,-5,-2] # 'ec'

字符串方法:
    请大家结合runoob和help英文文档,系统自学一遍。有些方法很少能用上,了解一下即可。用到了再仔细看文档。

    s1.capitalize(),把首个字母变成大写。
    s1.center()/s1.rjust()/s1.ljust(),用于格式化输出字符串,s1.center()是把字符串居中输出,参数传入可以指定字符串总长度,可以指定用什么字符来补齐空缺,默认为空格。ljust和rjust就是左对齐和右对齐(justify)。
    s1.count(),可以看到子串 (sub-string) 出现了几次。
    s1.endswith(suffix),字符串以什么结束。
    s1.find(),找一个子串第一次出现的位置下标。
    s1.index(),和find一样,只不过找不到会报错。
    s1.isalnum(),如果字符串至少长度为1,并且全是字母或数字就返回True。
    s1.isspace(),判断是否为空白符,有:'\t'制表符;'\n'换行符;'\r'换行符;'\v'垂直制表;'\f'翻页符(flip over);
    s1.join(),可以以s1来链接一个可迭代对象,返回一个字符串。
        例如:'.'join(['ab', 'cd', 'ef']),会返回'ab.cd.ef'。列表里面的元素需要是str类型。
              '.'join('abcd'),返回'a.b.c.d'。
    s1.lstrip(),截掉左边的指定字符,默认是空白符,有多少删多少。s1.strip()和s1.rstrip()对应。
    s1.maketrans(),字符串映射,可以用于加密。
    s1.replace(),把某个子串全部替换为指定字符串。
    s1.split(),和s1.join()是相反的,按照分割符(delimiter)切分字符串为列表,例如:'a b c d'.split(),返回['a', 'b', 'c', 'd']。(这个函数会切出来空字符串的)
    s1.splitlines(),按'\r'或'\r\n'(作为字符串)或'\n'来切分,分割后,如果最后一个是空字符串,会删掉。其他空字符串不会删掉。

    'abc'.center(10)  # 占10个字节,居中
    'abc'.isalpha()   # 字符串中所有字符是否都是字母,返回布尔值
    '   abc  \t\n'.strip()  # 去除空白符
    '##abc'.strip('#')  # 去除指定符号
    'abc'.replace('ab','AB')  # 替换
    'a b c'.split()  # 切分字符串

    空格符的英文:blank/space characters;
    空白符号的英文:whitespace,表示一个集合,\t\n\v\f\r

    \r\n都表示换行,为什么需要两个字符?return newline。键盘是由打字机而来的。

    学习字符串相关的方法和函数,一定要搞清楚,一个参数是一个字符串,还是一个字符集合?很重要!

出几道题目:
    打印各种三角形,直角三角形,等边三角形,如下
*
**
***

  *
 **
***

  *
 ***
*****

     *
   * * *
 * * * * *
* * * * * * (这个不对,不是等边)


-----
字符串相关的内置函数,建议大家自己系统学习一下所有的内置函数:

https://www.runoob.com/python3/python3-built-in-functions.html

-----
字符串格式化(formatting):将对象以一定的形式转化为字符串。
    默认的格式化方法:__str__()和__repr__()
    四种方法,后两种不常用
    'formatting-str' % (a, b, c)
    'formatting-str'.format(a, b, c)
    f'formatting-str'
    format()

 

2020.11.27 元组的可变性与不可变性,元组的拷贝,字符串

元组的可变性和不可变性:不可变,指的是元组中每个元素指向的对象是不可变的;可变,指的是元组中如果含有可变对象,那么元组中的可变对象元素它自身是可以变化的。
    例如:t1 = (1, 2, 3),就是一个完全不可以变化的元组;t2 = (1, [3, 4, 5], 2),这个元组中包含一个列表可变对象,那个列表自己是可以更改的,并且元组也会发生相应的“变化”,但是本质上,元组的几个元素事实上仍指向原来的那几个对象。

完全不可变对象:指一个不可变对象,其包含的所有子孙(容器嵌套)也都是不可变对象。如果一个元祖中包含了列表,那么这个元组就不是完全不可变对象。


元组的浅拷贝和深拷贝:既然有嵌套,元组也有浅拷贝和深拷贝。
    元组对象绑定:t3 = t2
    元组拷贝 (元组切片) :t3 = tuple(t2);t3 = t2[:]; t3 = copy.copy(t2);t3 = t2 * 1(此处t2和上面的例子是一样的)
    元组深拷贝:t3 = copy.deepcopy(t2)。递归(recursive)拷贝,直到“完全”不可变对象。


字符串 (string character):最常用的数据类型,是人机交互的基础。
    字(character)级别有英文,中文(C),韩文(K),日文(J),中文韩文日文有很多字符,要比英文大的多,所以需要更多字节存储一个字符。汉字一般是2-6个字节存,英文和数字是1个字节存。
    有一些字符是控制字符,比如回车符、空格符、响铃符、制表符等。(ASCII码)

字符串的定义:s1 = 'abc',双单引号; s1 = "abc",双双引号;s1 = '''abc'''三单引号;s1 = """abc"""三双引号。
    其中,在python中,单引号和双引号没区别,三单引号和三双引号也是没有区别的,三引号可以换行表示同一个字符串,双引号做不到。
    单引号和双引号混用:例如, "john' s" 和 'john\' s' 是一样的。如果都使用单引号,因为计算机区分不出来哪个是终止的单引号,所以需要用转义字符 \' 来表示一个单引号,如果是用双引号,计算机就可以很好的区分出来。
    
三引号用法:定义字符串时多行输入,或者是作为注释 (comment)


注释 (comment) :只要我们按照规范来写好注释,python可以自动生成文档 (document),可以利用help()来查看文档,或者生成网页文档。有两种方法去进行注释。
    利用 # 可以直接注释单行。
    利用三引号来写注释。
    注释规范:对于函数,在def func()的下面一行来写;对于模块,在最顶端来写。
    https://www.runoob.com/python3/python3-comment.html

字符串有不可变性 (immutable),并且在内存中连续存储是一个整体,不可拆分。

特殊字符:
    续行符 \,在未结束的语句的行末,就是一个续行符,后面不要再跟东西了。这个续航符不仅仅是在字符串里适用,在普通的语句中一样可以续行。例如:
         print(a\
         , b)
         print('ab\
         cd')
    退格符 \b
    响铃符 \a
    空字符 \0
    换行符 \n
    制表符 \t (horizontal)
    纵向制表符(vertical):\v
 

2020.11.23 元组,__str__,__repr__,拆分赋值

如何去测试一个算法的性能:以顺序和二分查找为例,同一个列表,找很多测试点元素,循环多次测试,分别取其平均值。

iterable和sequence:sequence是一个更严格的概念,zip和enumerate、reversed、文件、range这种类型的对象是可迭代的,但是不是序列。
    (区别一个对象是否是可迭代对象可以用for来测试;序列有元组、列表、str)

元组 (tuple):也是一种sequence (内存中连续存储、下标随机访问)。
    和列表的主要区别是:immutable 不可变。

元组的定义:t1 = tuple(); t1 = (); t1 = (2, ),必须要有括号内的逗号,否则会优先被python判定为是一个式子,而不是一个只含一个元素的元组。
元组的拼接(concatenation):t1 += (4, 5)和t1 = t1 + (4, 5)是等价的,t1的id已经发生了变化,并不是原来的对象了,新创建了个元组对象。
元组的乘法:t1 = t1 * 3和t1 *= 3,和拼接是一样的,返回新元组对象。
元组的删除:del t1[0]报错,元组不能操作。
元组的切片:返回新元组,切片方式和列表一样。
    例:t1[-1:-len(t1)-1:-1],返回一个元组的反转元组。
元组的比较:和列表的比较是一样的,(1, 2, 3, 4, 5) < (1, 2, 3, 4, 5, 1, 2, 3, 4, 5)返回True。
in, not in:查询一个元素在不在元组内,返回bool。
元组和列表的拼接:t1 + l1会报错,列表和元组是不可以拼接的。
元组和列表的相互转换:工厂函数,例:l1 = list(t1),创建一个值和t1元组相等的列表;t1 = tuple(l1),创建一个值和l1列表相等的元组。
元组的方法:只有t1.index()和t1.count(),列表中那些不会对列表操作的方法保留下来了。

序列有关的内嵌函数仍然适用,因为内嵌函数的本质通常是针对一个序列或者一个可迭代对象的,这和是元组或者是列表是没有关系的,然后返回一个新的可迭代对象。例如zip; enumerate; len; max; sum; sorted; reversed; all; any等。
    例:len()这个内嵌函数,传入的只需要是一个obj对象即可,只要传入的类有__len__()这个特殊方法,就可以找到它的长度。(什么是类,自己可以提前了解,提前做个实验)
        sorted()返回新列表。

类特殊方法的__str__和__repr__:
    __str__:当print()时,会输出其返回值。将当前对象转为str对象时,会使用其返回值。
    __repr__:一个对象的自我介绍 (给程序员),默认提供对象的类型,内存地址等。可以自己重写,按照自己想要的格式来print。
    可以做个实验。

序列拆分赋值:和之前讲的是一样的,例如:a, *b = (1, 2, 3, 4)。

元组的使用场合:
    同步赋值,例如,x, y = 5, 7
    函数返回多个对象:return a, b, c
    字符串格式化‘%d %f’ % (10 ,5)

元组的可变性和不可变性;元组的浅拷贝和深拷贝(下节课)
 

2020.11.20 查找,二分查找,unpack,列表生成表达式,模块基础

操作符优先级:一元操作符的优先级普遍高于二元操作符。not的优先级要比and高。


-----
二分查找:
查找:对于列表,有个方法li.index()可以快速地查找到相应value的下标。

顺序查找:如果是查找一个无序的列表,顺序查找的时间复杂度为O(n)

对于一个已经排序好的列表,可以用二分查找,时间复杂度为O(logn)

二分查找 (Binary Search):查找一个已经排序好的列表,例如,对于一个序列[-4, -1, 0, 1, 3, 5, 6, 8, 10]找到元素8的下标,首先确定一个上界和下界,第一轮把上界和下界限定为整个序列,找中位点,第一次会找到3,发现8比3还大,所以把下界重新设置为5,再找中位点,会找到6,发现比8还是小,在把下界设为8,然后再找一次,就会找到8的位置。二分查找中,每一次查找,都会把列表中一半的元素筛除,所以试的次数最大为log2n,其时间复杂度为O(logn)。

编程题目:随机产生一个数字n,然后随机产生n个数字放到列表中,然后.sort(),然后用自己写的二分查找函数来做查询。可以比较一下二分查找和顺序查找的效率。

-----
zip:
苏州大学运动会100米决赛8名队员,按照成绩从小到大排序
nums=[1001,1002,1003,1004,1005,1006,1007,1008]
marks=[10.01,10.89,11.02,11.02,10.02,10.38,10.95,11.45]
这个题目需要把编号和成绩绑在一起作为一个元素,然后排序。C++的做法是用一个结构体,把两种元素绑定在一起。
python的做法:
   1)用zip(marks, nums),把两个列表打包,然后指定key为分值来sort()
   2)用zip(nums, marks),把两个列表打包,然后指定key为分值来sort(key = lambda x: x[1])

zip后的遍历:
for i, j in zip(nums, marks): 
    print(i, j)

-----
拆包,解包(unpack):又称为”序列”拆分赋值 (同步赋值),使用赋值语句,将序列拆分,绑定到多个名字上。例如:
    x = 5
    x, y = y, x
    x, y, z = z, x, y
    x, y = 5, ‘abc’
    赋值语句右侧的对象,被隐式转化为元组(tuple)对象。
    
    e, *f, g = [1, 2, 3, 4],在这个语句中,*f会对应多个元素。最后f的值为[2, 3],是一个列表。
    *最多出现一次。左边的变量名数量,可以<=右边序列的len+1。如果左边的变量名的数量为len+1,那么*对应的变量名为空列表
    e, *f, g = 'zhenghua',f也是一个列表,每一个元素为长度为1的字符串

-----
列表生成表达式:
    [表达式 for 目标1 in 可迭代对象1 [if 条件1] …… for 目标n in 可迭代对象n [if 条件n]]
    例:l1 = [i for i in range(1, 100)]
    问题1:如何产生10个随机的偶数?
    例:l1 = [(x, y) for x in range(5) if x%2==0 for y in range(5) if y%2==1]
       最后l1的值为[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
       顺序是:给定一个x,遍历所有的y;然给给定下一个x,再遍历所有的y
    例:l2 = [abs(i) for i in l1]
    例:l3 = [i**2 for i in range(10) if i % 2 == 0]

---- 
模块(module):
    模块化:在程序中,比较重要的思想就是模块化思维,把大问题分解为一个个的小问题。模块化后的一个很大的优势就是小问题的解可以重复使用(重用)。
    模块 (module):在python中,一个模块就是一个.py文件。目前常用的模块有:math, random, time。
    如何创建并使用自己的模块(DIY)
        1)我们以前写过的一个程序prime100.py,其中包含一个is_prime()函数。下面我们演示如何把这个.py作为一个模块使用。
        2)在同一个目录下,创建一个新的.py文件,命名为use_DIY_module.py(不在同一个目录下时,如何使用模块,以后会讲)
        3)use_DIY_module.py中写
              import prime100 (注意不需要.py)
              print(prime100.is_prime(7))
        4) 运行use_DIY_module.py,就会发现可以了
    包 (package):当模块很多时,需要用目录树来组织,整个目录树就叫包。以后会讲。
    后面,我们会专门讲解import prime100,具体发生了什么?以及其他使用模块的其他方法。
 

2020.11.16 列表的方法,关于序列的内嵌函数

时间复杂度(time complexity)和空间复杂度下去自己了解一下。

列表的方法:
    形式:列表名.属性,例如li.append()。其中点符号(.)是属性访问符(attribute access symbol)。
        注:属性有数据和方法(method, function)。比如math模块,math.pi就是引用了他的数据,math.sin()就是引用了他的方法。
    li.append(self, object, /),self是类的内部属性合集,调用方法的时候就会隐式处理,不用传参。
    li.reverse(self, /),就地(In Place)反转,返回值是None。
        自己写个myreverse,不允许用切片,也不允许用li.reverse(),两个数交换用x, y = y, x
    li.clear(self, /),就地修改,清空列表。
    li.remove(self, value, /),就地修改,删除第一个在li中与value相等的元素,否则抛出异常(Exception) ValueError。
        如果不想报错,就在删之前确保value在li中存在,可以用in,也可以用try语句。
    li.pop(self, index=-1, /),弹出指定下标的元素,默认最后一个,返回被删除的值。
    li.copy(self, /),浅拷贝(shallow copy)。
    li.count(self, value, /),返回value在li中 出现的次数。
        回去写个函数,删除列表中全部的值为value的元素,count和remove配合即可。
    li.index(self, value, start=0, stop=9223372036854775807, /),返回第一个值为value的元素的下标。找不到就抛出异常ValueError,一般不会有内存能存下这么大的列表,所以一般不用担心stop。
        回去写一个函数get_all_indices(),找到一个列表中全部的值为value的下标,返回列表。li.count()和li.index()配合使用。
    li.insert(self, index, object, /),把object插入到index位置,之前的index所指的元素,及其之后的元素,都被往后推一个。插到最后一个位置等于append()。
    总结:学一个对象的方法,首先要知道是否会对对象进行修改;其次要知道是否返回一个新创建对象。
          上面有三个题目。

    li.sort(self, /, *, key=None, reverse=False),就地排序,是稳定的排序,稳定排序指的就是列表中两个相同的值,相对位置不会发生变化。
        参数:reverse是排序完之后是否反转,默认是从小到大;key是要传入一个函数,默认为None就是按照简单的比较 (等讲到函数再详细地展开)。
    注:"/"和"*"都是用来在函数限定位置的分隔符,"/"前面的都必须用位置传参,如果用关键字指定就会报错,"/"之后就可以用位置指定和关键字指定了,"*"之后必须用关键字指定。如果"/"和"*"要一起用,“/”必须要在“*”前面,顺序不能反,要不然就矛盾了

与序列相关的内置函数:(和列表的方法是不太一样的)
    len(); max(); min(); sum(); sorted(); enumerate(); reversed(); all(); any; zip()
    sorted(iterable, /, *, key=None, reverse=False),和列表的sort()方法差不多。
    enumerate(iterable, start=0),返回一个枚举对象,是一个工厂函数。简单来说,在用for遍历列表的时候,用enumerate()包装一下,就会同时返回循环次数。
    reversed(sequence, /),返回一个reversed可迭代对象(iterable),就是把原来的列表做成一个迭代器,在迭代器循环就会得到一个反转的列表。
    zip(l1, l2, l3. ...),把几个容器打包,变成一个zip可迭代对象,每次返回的是一个元组,打包了那些容器的相应位置的元素。长度不一取短桶。

视频1:26:10位置,提到了一个加分题目。谁如果做完了,把代码和运行结果截图 发给 刘泽洋助教,前3名同学给加分。不要发到群里。

 

2020.11.13 列表的拼接,列表的乘法,列表拷贝,列表排序

第九次理论课:

第一次考试,第一次考试占总成绩比重不是特别大。
一对一辅导,家教。自己要站起来,主要还是靠自己。
可以查成绩,没有错误减三分。

全切片:l2=l1[:] 。此时发生了什么?对比l2=l1,在内存中怎么画?

列表的拼接:
    l1 = l1 + l2,新创建一个列表对象,长度为l1和l2的长度之和,并且把l1绑定到新列表对象上。
    l1.extend(l2),对l1就地修改,扩大长度,新增元素绑定到l2元素所绑定的对象上。
    l1 += l2,和extend()是一样的,在l1原有的基础上增加长度。    
    增加长度时,后面的内存可能不够,这时候要整体移走。所以id()返回的是逻辑内存地址,而不是物理内存地址。
    可以自己做做实验,一直extend列表,看看id是否会发生变化。体会一下内存的逻辑地址和物理地址。

列表的乘法:
    l2 = l1 * 3,创建个新列表,放了3次l1的元素,最后l1指向的每个对象在l2中有3个名字指向它们。
    l1 *= 3,其他的和上一个一样,只不过是就地,不创建新列表。

总结:+=和*=都是就地修改,不创建新的列表
      多去理解列表在内存的存储方式,再试试列表里面嵌套列表应该怎么画内存,列表拼接、乘法、拷贝应该怎么画内存的变化。


拷贝(可以称为浅拷贝)的定义:创建一个新对象,和原来的对象“值”相同。
        拷贝方法:全切片;用工厂函数(工厂函数见前几次课);copy.copy();l2 = l1 * 1A;li.copy()方法。
        例如:l2 = l1[:];l2 = list(l1);l2 = copy.copy(l1);l2 = l1.copy()
        总结:浅拷贝只拷贝了列表的指向,但是没有一起拷贝列表指向的对象,此时对可变对象进行操作,拷贝的对象和原列表一起发生变化。

矩阵存储:l1 = [[1,2], [3, 4]](内存中怎么画?)
        numpy -> pytorch (GPU)

深拷贝:创建一个新对象,和原来的对象的“值”相同,并且与之前的对象毫无瓜葛 (彼此的改变,不会影响到对方)。
        深拷贝方法:l2 = copy.deepcopy(l1)
        注:深拷贝往往会创建多个对象,遇到容器对象(除str)会递归(recursive)拷贝。

思考:什么情况下,对一个对象做拷贝和做深拷贝存在差异?什么情况下没有区别?
        容器嵌套时(str除外,虽然str也是容器)。
        例如:列表中包含其他容器对象(除str)时才会存在深拷贝和浅拷贝的问题

列表排序:把一个列表按照一定的规则排序,一般情况是从小到大。
    选择排序:每轮从左向右扫描,找到最大的数放到-1位置(-1位置指没有排序的部分末尾),这样每轮都能找到一个最大数,一共n-1次就能把列表变得有序。
    冒泡排序:每轮从左向右扫描,每移动一步,就比较一下此时位置相邻两个的大小,如果前面的比后面大,就交换,这样每轮都会有个最大数冒泡到尾端。也是n-1次列表就变得有序了。
    (冒泡排序的命名应该来自于一种物理现象:因为水越深水压就越高,所以气泡从水底浮出的过程中,气泡会越来越大,和冒泡排序的原理很像)
    归并排序:基于分治法,每次把列表划分为两部分排序,递归到单个元素,时间复杂度很低。
    大家做实验对比一下,上面三种排序算法的速度如何?
    堆排序:
    快速排序:
    问题:什么是时间复杂度,这几个排序时间复杂度怎么样。

 

2020.11.9 循环嵌套(break continue)、列表基础

画流程图:输出前100个素数(质数)
我们需要用大循环,去寻找到100个素数,但是每找一个素数需要用一个小循环来判定当前数是否为素数。
这就是循环的嵌套。
这个程序有个问题:如果找10000个素数,找到后面会越来越慢,想想可以怎么优化。(通过列表保存前n-1个素数)

但是上述程序看起来非常复杂,如何在逻辑和流程上更加简洁呢?这里要可以用到一个模块化思维:用函数来实现内部循环。
判断一个数是否为素数,可以写一个函数,每个函数只完成一个功能。

基本数据类型、不可变对象:int, float, bool, NoneType, complex, str
    什么叫基本数据类型?python自带的。不能再细分为更小的类型。这两种说法都不严谨。还是不用这个说法了。叫标量(非容器)和矢量(容器)好了。
str是一种序列,当然也是容器。

序列:
    定义:(有序)、(连续存储)的容器。注意括号内的形容词。
    访问方式:可以根据下标访问,常数时间内就能找到,速度极快。

列表:也是一个容器、序列,但是列表是可变对象。
    创建列表对象:li = [1, 2, 3]
    如何删除列表对象?这个问题本身是有问题的,没有办法直接删除列表对象。del li只是删除了li这个名字,同时取消了名字绑定。如果一个对象没有被任何名字绑定,就会被删除回收(python的垃圾回收机制)。

Q1:列表对象和其包含的对象之间有什么关系?
    一个列表对象包含的其实是一堆名字,这些名字分别绑定到对应的对象上。(看一下板书)


Q2:列表中可以“包含”不同类型的对象吗? YES
    列表嵌套也是可以的

Python vs. C++
    在定义函数时,不需要明确声明参数的类型。执行过程中,python会动态判断参数的类型,进行相应的操作。

强类型程序语言 vs. 弱类型程序语言:这个概念比较模糊,以后不再提了。
    
列表对象名字绑定:l2 = l1
    
列表方法(method):(好多函数,自己查表)
        li.append(),可以在列表后追加一个元素。例如l1.append(l2),会把l2作为一个对象追加到l1后面。
        li.clear(),列表清空。
        li.count()
        li.index()
        li.insert()
        li.sort() vs. 内置函数sorted() # 仔细先学习一下,下节课会仔细讲一下
        l1.extend(l2): 没有创建新的对象;l1的长度增加;l1的地址不变;l2不受影响; 增加了一些名字绑定

列表拼接(concatenation):
    l3 = l1 + l2,如果l1有3个元素,l2有3个元素,l3此时只会创建一个新对象,进行了7次对象绑定。
    l1.extend(l2),在l1列表的尾巴上扩展l2列表,这个操作没有新对象创建,l1地址不变,但是有3个新的名字绑定。(注意这个操作和append()是不一样的)
    l1 += l2
    问题:是否有新的对象创建?内存中发生了什么?in-place(就地)修改,还是新创建了一个列表对象?

列表乘法:
    l2 = l1 * 3 # 发生了什么,是否有新的对象产生?


列表索引和遍历:
        for i in l1:       for i in range(len(l1)):
            print(i)           print(l1[i])
    
    找某个位置的元素:l1[1]或者l1[-1],1是列表第二个元素,-1是列表最后一个元素。(j=i-n,此时i和j指向相同位置)
    0,  1,    ..., n-1  (i)
    -n, -n-1, ...,  -1  (j)
    i = j + n
    j = -(n-i) = i - n 

列表的切片(slicing,把列表切成子列表):
        例如:l1[2:4],返回的是列表的2号元素到3号元素的子列表,和range()一样,是前闭后开。
              l1[2:9:2],返回2号元素,4号元素,6号元素,8号元素的子列表。
        注:序列中,第2个元素对应着1号元素,我们是从0开始计数的。

列表的比较:
    l1 is l2,两个名字是否指向一个对象。
    l1 == l2,判断两个列表的值是否相等。(值的比较
    l1 < l2,从左到右逐渐比较,注意数据类型,没法比较的数据类型就会报错。

成员判断:in关键字,2 in l1,即2这个值是否在l1中。(值的比较)

 

2020.11.6 2020.11.6 循环(for while else break continue),range函数,pass语句

下周二上机课再来一次模拟考试,4个编程题,包括循环和列表。
8道题目:顺序,分支,循环,列表,各2道。

自学内容:做习题集会用到两个内容,都先自学一下。大学要培养自学能力。我希望在上课的过程中,教会大家如何自学,如果检验知识。授之以渔。
  字符串格式化:第一次考试(编程题不会考)
  模块的使用:math time random,结合dir help 百度 runoob来学习

为什么需要循环呢?
    从两个例子入手,来解释。写程序之前请大家先画流程图,不断练习流程图。

    例子1:写一个函数,从5个数字中选择最大的数,并返回。
    def func(x1, x2, x3, x4, x5):
        y = x1
        if y < x2:
            y = x2
        if y < x3:
            y = x3
        ...
        return y
    如果是100个数呢?
    问题 1)100个数字如何作为参数传过去呢?100个参数?显然太多了。
    问题 2)即使真的传100个参数,那么这个函数能够做的事情也太局限了,只能处理100个数字;99个数字中选择最大数,还得写另外一个函数
    这两个问题,就引出了列表这种数据类型。即可以把很多数字(变长)放到列表中,传给参数。
    
    处理很多个数字、或者长度不确定的列表,就需要(最好)用循环。否则代码会很冗余。
    def func(x1, x2, x3, x4, x5):
        y = x1
        for x in x2, x3, x4, x5:  # x2, x3, x4, x5其实被隐式的转化为一个元祖tuple对象,for循环对其进行遍历
            if y < x:
                y = x
        return y


    例子2:从一个字符串中统计一个字符(如'a')的次数。字符串类似于列表,也属于长度不定的序列,必须使用循环来遍历。
    while和for都可以做。先画流程图。

循环的语法:
    循环利用for和while两个关键字来操作。流程图runoob有,或者看一下板书。
    https://www.runoob.com/python3/python3-loop.html

    while:
        形式:while condition:
                  code block
        意义:如果满足condition这个条件,while就会执行下去

    for:
        形式:for var in iter:
                  code block
        意义:var是一个变量,iter是可迭代对象,序列就属于可迭代对象(如列表,元组,字符串),var会在这个可迭代对象中循环,直到可迭代对象结束。

    for循环使用起来更方便,会有隐式的遍历语句,自动增加下标和判断是否结束。
    
    死循环:deadlock,是指循环永远不会退出来,也叫无限循环。有的时候是需要无限循环的。
    如果遇到死循环,用Ctrl+C来杀死正在shell运行的程序。
    
    遍历列表操作时,如果要删除列表元素,要非常谨慎。尤其适用for循环时,很容易出错。while循环会安全一些。

    a = 0
    while a < 10:
       print(a)
       a += 2

    表格法来学习和理解循环:
        step   a     动作
        0      1     打印’1’ a+=2 (3)
        1      3     打印’3’ a+=2 (5)
        2      5     打印’5’ a+=2 (7)
        3      7     打印’7’ a+=2 (9)
        4      9     打印’9’ a+=2 (11)
        5      11    退出循环

    while中的else语法:
        形式:while condition:
                  code block A
              else:
                  code block B
        意义:由于condition为False而退出循环时,才执行else。反之,如果循环由于break或return而结束,那么就不会执行else子语句。
    for中的else语法:类似于while。
    
    break:从当前循环语句中跳出(包括else一起跳了)。
    continue:退出本次循环,直接进入到下一轮循环。注意,continue会在for循环中取出可迭代对象下一个值。

    range函数:
        range()是一个生成函数(generator,生成器;上课时我称为生成器函数,需要确认一下名称),返回range对象(range是一个类型,即这个函数也是工厂函数)。
        注:生成数字序列是前闭后开的,即range(10),生成的是0, 1, 2, 3, 4, 5, 6, 7, 8, 9
        例:range(15, 3, -2),以15开头,小于等于3结束,步长为-2

    pass语句:
        pass是一个关键字,pass语句是用来空转的,也叫空语句,占位语句。

继续做题,多做题目。
 

2020.11.2 工厂函数,复合函数,条件控制(分支),选择表达式,做题目

print(),指定sep和end参数时只能通过关键字调用。

工厂函数:类型转换,根据一个给定对象,创建一个属于该类型的“新”对象。(同类型也是可以的)
  例如:bool(( )) → False	(空元组用括号囊括一个空格)
        float(‘3e-3’) → 0.003	(e是一种科学计数法,3e-3代表着3*10^-3)
  注:传入工厂函数的对象要符合转换规则,complex转化为int就会返回TypeError,错误的字符串传入float会返回ValueError。

复合函数:x = int(input(‘输入一个数:’)),即函数嵌套函数,一个函数的返回值是另一个函数的传入参数。

条件控制:
  形式:(请不要以过小的分辨率看以下格式,CB是code block的缩写)
if condition:  |  if condition1:    |  if condition1:
  CBA	       |    CBA		    |    CBA
else:	       |  elif condition2:  |    if condition2:
  CBB	       |    CBB		    |      CBB
	       |  else:		    |    CBC
	       |    CBC		    |  else:
	       |		    |    CBD

题目:自己画流程图,写函数。审题,注意边界条件,输入类型,返回结果要求。isinstance()可以判断类型。
  判断一个数字是奇数还是偶数:偶数返回’even’,奇数返回’odd’。
  判断一个年份是否为闰年(能被4整除但是不能被100整除或能被400整除):返回True或者False,传入的year为int型。
  判断三个数字中的最大值:返回最大值。
  传入一个三位自然数,计算并返回其百位十位个位上的数字元组,如果输入的不是三位自然数返回None。

选择表达式:x if x > y else y  (其中x>y是条件判断,x和y必须是两个表达式) (注:赋值语句不是表达式)
  例如:print(‘A’) if x > y else print(‘B’)
        z = x if x > y else y

表达式有哪些?创建对象(理解一下)、算术运算、条件运算、逻辑运算、函数调用(返回对象)
注意:赋值语句不是表达式!

 

2020.10.30 基本数据类型总结(标量 vs. 矢量)、bool、complex、关键字、name命名规则、工厂函数、对象可变与不可变性、内置函数(help, input, print)

基本数据类型(标量scalar):
	int(Python没有限制范围);float(Python不分单精度和双精度,C语言区分);str;bool(boolean);...
	complex(复数):
		形式:例如:1 + 2j
		定义方式:例如:z = 1+2j;z = complex(a, b);z = a + b*(1j)

关键字:程序预定义的有特殊含义的名字;关键字不允许另作它用,否则执行会出现语法错误
	is/ is not:用来判断两个对象是否是同一个对象。简单来说判定一下两个变量是否绑定(binding)在了同一片内存地址(当然这里涉及一些数据结构的问题,不能简单地把对象来等同于内存地址)。
	注:变量名字一旦绑定,以后用到这个名字,就等同于用绑定的对象;
	    x和y指向相同的对象,此时 id(y) == id(x);
	    在Python中,对于一些整数(小于256)或字符串(简单),会共用一块地址。
	del:可以销毁对象,Python中也拥有一种垃圾回收机制,定期将程序(进程)中没有任何名字指向的对象销毁。
	import;and;or;not;if;else;while;for;True;False... (已讲过)
        查看所有的关键字
            import keyword
            print(keyword.kwlist)

对象重用优化:对于一些简单的整数(<256)和字符串对象(注意整数和字符串均为不可变对象),在创建之前,会看内存中是否已有值相同的对象,如果有的话,就会用已有的,而不会重新创建新的对象。
   例如
   x = 123
   y = 123  # 会重用上一个,而不会创建一个新的整数对象
   id(x) == id(y)  # x和y指向同一个对象
   类似的,字符串也是一样的。bool只有两个不同的对象True和False,因此一定会重用。NoneType只有一个对象None,也一定会重用。
   但是,其他类型,如浮点数、复数、列表等,就一定不会重用。
   x = 0.5
   y = 0.5
   id(x) != id(y)
 注意!!上课时走了一个弯路,找到正确的实验方法后,我也没有给出一个合理的解释。现在解释一下:
   id(123456789), id(123456789)
   为什么id是一样的呢?更合理的解释是:这种对象没有name绑定,因此用完就会销毁;第二个整数对象创建时,会在同一个地址上创建


name的命名规则:
	1. 首位:_ a-z A-Z (注意,首位不能是数字)
	2. 后续:_ a-z A-Z 0-9

工厂函数(构造函数):int;float;str;bool;list;dict;tuple;set;complex;...
	既是class类型名,也是一个函数,可以制造相应对象。

标量(scalar):不可分解的,单一的。以int;float;complex; bool。
矢量(vector,也叫向量、容器container):以list;tuple;dict;set为代表
str也是容器,所以称为矢量也可以的,还可以继续分解为更小的字符串。但是str是基本数据类型,不存在更小的数据类型(如字符)。

可变对象和不可变对象:
不可变对象(Immutable Object):int;str;float;bool;complex;tuple(!);frozenset
可变对象:list;dict;set

help函数:
	help(input):这个语句可以调出来帮助文档,help里可以传入函数、模块、对象、名字...
	注:None代表着空数据。

input函数:(我们一般会把函数直接用input()这种方式来写,以后将直接用这种方法来代表函数)
	input()会读入一个字符串,并且会剥离最后一个回车符。
	例如:input: This is Python class.\n 。然后input()会返回'This is Python class.'这个字符串。
	注:不可以用x = input(prompt='pls enter a number') 这种格式。理由如下:
                python3.8加了新的特性,函数可以添加限定位置参数,所以使用prompt传参会报错,课上看help(input)的反斜杠就是限定符标识。详情见:https://zhuanlan.zhihu.com/p/90563819

print函数:
	用法:print(value, ..., sep=' ', end='\n')
	含义:一次可以print()多个数值,每个数值用'sep'分隔,print结束输出一个'end'符。
 

2020.10.26 考试形式、IDE、简单语句、字符串、特殊字符


2020.10.23运动会,缺一次课!

考试:
电脑阅卷,选择题30分钟20~25个题目,立刻进入编程题,3~5个题目,两个小时。
编程题要提交“.py”文件,不要用shell,文件要保存到一个可以找到的地方。
注:注意养成一个文件管理的好习惯:小心误删误覆盖;可以通过复制粘贴来版本控制;不要放桌面也不让保存的目录太深;...
    考试会让你写个函数,函数名题目会给定,函数要有传入参数,有返回值。对于想拿高分的同学,要注意边界条件,要缜密思考。
    写完函数,用测试语句测试,记得把测试语句注释(#)掉,要不然就用“if __name__ == 'main': ”把测试语句囊括。

PyCharm和IDLE是一个集成的开发环境(IDE:Integrated Development Environment),拥有的功能有:
编辑(edit);运行(run/execute);调试(debug)。PyCharm这学期可能不会讲。
调试方法:单步执行;print();...

简单语句:
	6. 逻辑运算(Logical Operation):
		Q1:operand must be True/False?NO!
		Q2:return value always be True/False?NO!
		例:x = 2 and 3
		    print(type(x))
	            Output:3
		注:非bool型会有一个隐式转换:
				对于int,0 → False
					 != 0 → True
				对于float 0.0 → False
					  != 0.0 → True
				对于str '' → False
	7. 位运算(bit)
	8. 优先级(priority)由高到低:
                各类括号,指数(**),位运算(~; +; -),算数运算(* / % > +  -),关系运算(<; >; ==; >=; <=; !=);逻辑运算(not > and > or),赋值语句(=; -=; +=; /=; *=)
                注:详情请见 https://www.runoob.com/python3/python3-basic-operators.html
复杂语句:函数定义;while;if-else;类定义;...

缩进(Indent):
	为了复合语句,可以嵌套,但是不要写的过于复杂了。
	4个空格或者一个TAB(制表符)为一层缩进。
	注:空格和制表符不能交替使用,不过一般的IDE会自动帮你对齐缩进,并且使用一种缩进方法。
	    制表符不一定是8个空格,可配置,也不一定必须使用4个空格,只要文件内部是一致(consistent)的即可。

字符串(String,简称str):一串连续字符(Character,简称char)。
	只考虑英文字符的话,一个字节内存存一个字符。ASCII表把字符映射成唯一数字。
	“str”是Python内置(预定义提供)的基本数据类型,在Python中,char和str都属于“str”类型。
	1. 定义方式:单引号('这是一个字符串');双引号("这是一个字符串");三单引号('''这是一个字符串)	(有区别吗?)
	2. 转义字符: 
		'\n'回车;'\\'反斜杠;'\t'制表符;'\b'退格符(backspace);'\a'响铃;...
	3. 操作函数:
		+ :一个操作符面对不同场景(操作数类型)有不同的含义,即重载(overloading)。
			例:'abc' + '123' 返回 'abc123'
		len():返回字符串长度。
			例:len('abc\n') 的返回值为4。'\n'是一个转义字符,反斜杠(backslash)打头,代表着换行符(回车)。
	
写一个程序:输出当前时间,新输出的时间刷新旧时间。(提示,利用退格符,PyCharm可以,用cmd也可以,IDLE不行)

2020.10.19 Python和英语的对比、简单语句

python(作为语言)和英语作对比, 
字符:大小写字母;数字;#’’...
单词:keywords:while; def;函数名;变量名;数字;字符串。和英语语言不一样,单词可以不符合英语字典里的单词,比如'_a123'对于python也是合法的变量名
句子:statement vs sentence
段落:复合语句,文件,包 vs 节,章,篇,书
语法:非常严格(格式和语法都很严格) vs 比较随意
程序语言和英语哪个难?当然是英语,程序语言有唯一语义。

语句 (statement):
简单语句:
	1. 赋值语句assignment:把一个对象(object)绑定(binding)到一个名字(name, 标识符, identifier)上。
		例如:	x = 7	→	把整数对象绑定在了x上。
		注:object是内存中实际存在的东西,有4个属性(attribute):
				id (identity,地址);
				类型 (数据类型,类名,type,class);
				数据值/内容;
				方法 (method / function) (主要是class类中,详情见后面章节)。
			程序执行过程中,不会有重名。
	2. 函数调用:
		内嵌函数 (build-in):print;abs;help;...	。无需引入“包”即可使用,python默认提供。
		import math:math.sqrt(); math.pow(); math.log(); ...
	3. import:把一个包引入到当前文件。
	4. 算数运算(Arithmetic):加 + ;减 - ;乘 * ;除 / ;整除 // ;余数 % 
	5. 关系运算(Relational):数字或字符串比大小,小于 < ;大于 > ;等于 == ;不等于 != 。返回bool型,即True & False。
	6. 逻辑运算(Logical Operation/Calculus):and ;or ;not。
		例如:3>2 and 2<1。
        注:逻辑运算符号的两边不一定要是bool型,返回的结果也不一定是bool型,请自行测试学习。
	注:运算注意object的type类型;注意算术符优先级;字符串比大小有个字母序(alphabetic)。
复杂语句:函数定义;while;if-else;类定义;...
 

2020.10.16 计算机组成、数据结构、算法、流程图

计算机组成
  冯诺依曼架构
A processing unit that contains an arithmetic logic unit and processor registers (ALU)
A control unit that contains an instruction register and program counter (CU)
Memory that stores data and instructions
External mass storage
Input and output mechanisms
   https://en.wikipedia.org/wiki/Von_Neumann_architecture
   https://zh.wikipedia.org/zh-hans/%E5%86%AF%C2%B7%E8%AF%BA%E4%BC%8A%E6%9B%BC%E7%BB%93%E6%9E%84
   https://www.baidu.com/link?url=WUyrwd9zkEs6eVKyVR9Emg4_pkDsGxJLyrcixtszhapi6XO92QXBlbW-B8f_6dooqxiExzUKir5bCoZhZNvNefxSPO5WSIsI_E-lM2XUgSp5i2i7WY0Ip7tTSwXuy4rEsgtrYO5HOAHElbzI0P1O2mdy-jz9K4-Dx_xvd01rImKxbfrOKyOE4O7cW5U-94xh3XOvQK-8qcWUmN_EnFy2NqauxvnNXHKwWbYN9ZW5JKl8MgTi_HkZ7c6LG75yQ58UZ49MAY98NtbDAVCUXAPruPeO81ozIt36bB1jZOZRQw2PpFK7VV5euTIWOs68_D-i&wd=&eqid=e2294df70000e186000000045f7fd18c

数据和算法
  计算 数据
  流程图、伪代码:平方根
  平方根的其他解法,更优的:https://note.youdao.com/ynoteshare1/index.html?id=828b637ef7ff73a51dd26c1bc59be3e9&type=note

2020.10.12 自我介绍、大学生活学习建议、课程介绍

自我介绍
  演示几个平台

对同学的摸底,能力强的同学,不妨做我的基础编程练习,由简入繁,不断积累

大学生活、学习的几点建议

课程介绍(过程化课程)
  课堂提问、上机实验(代码和报告)、期中、期末多次考试