Crossin编程学习+高淇老师

参考资料:Crossin编程教室  百战程序员高淇  python标准库文档    python在线工具

小甲鱼视频       小甲鱼作业及答案        Python黑魔法手册     python基础

Python 3 教程    Python 教程      廖雪峰-Python

最好的CS入门课:CS61a学后感

Tips

快捷键:注先前的Fn键,笔记本锁定了,可以用Fn+ESC恢复原有的功能。
(1)  Pycharm下,运行:Shift + F10
(2)  选中某一行(左侧出现红点) 然后右键debug,接着可以使用step over/step into 来陆续执行每一行代码,另外还有step out(三者区别见这里)。如果我们选中两行,也就是左侧设定两个红点thread,debug的时候先执行到第一个红点处,然后我们点“run to cursor”就会直接从第一个红点处执行到第二个红点处。参见视频
(3) 自动补全前面曾经出现过的单词: Alt+/
(4)  缩进决定逻辑层次
(5)  注释某一行 Ctrl+/三个键一起,再作用一次就接触注释
(6)   注释某一段:使用三个单/双引号。选中内容,然后按住Shift不放,然后连续敲击三次引号键
(7)   避免 tab 与空格混合的缩进风格,虽然我们知道大多数编辑器默认 tab 制表符就是 4 个空格
(8)  一句内容过长,使用行连接符\
(9)  python是面向对象(每个对象包含标识、类型、值的信息)的,对象的本质就是:一个内存块,拥有特定的值,支持特定类型的相关操作 。变量:对象的引用。
(10)  程序员修炼手册
(11)  列表的删除和插入都涉及拷贝(更换原有元素的物理地址),存疑?。
(12)  列表和字符串很多函数用法是相通的。
(13)  不要一边遍历,一遍修改/删除。先挑出有用的元素。
(14)  print(“赋值符不能出现在条件表达式中”) ,比如 if 3<c and (c=20):
(15)  尽量写推导式
(16)  字典:空间换时间
(17)  调出帮助文档:选中然后shift  F1
(18)  Python 中“一切皆对象”, 所有的赋值操作都是“引用的赋值”

小技巧:
1. 一般不要在代码里面写中文,如果非要写,请在第一行输入# coding: gbk

2.  支持布尔代数,比如value = 2 < 5那么print(value)得到True。

3. a=int(input())输入的必须是整数,否则报错

4. pycharm 代码,选定任何一行,代码栏下面(灰色的一小栏)会显示控制流结构,很重要

5.  引入模块  from 模块名 import 方法名 比如 from random import randint(引入随机数模块),接下来你就可以用randint来产生随机数,比如num = randint(1, 100)

6.  变量命名:首位必须是字母或者下划线,区分大小写

7. 累加的简化写法 a += 3

8.  布尔代数容易混淆的地方:a = False 然后print(a) 和print(a==False)的结果

9. for 循环和matlab的区别:for i in range(a, b)就是从 a 循环至 b-1

10.  被称作转义字符,除了用来表示引号,还有比如用

  • \n 表示字符串中的换行(相当于按一下回车键的效果)
  • \t 表示字符串中的制表符(相当于按一下tab键的效果)
  • \\ 表示字符串中的 \ (因为单个斜杠被用来做转义了,所以真的要表示 \ 字符,就要两个斜杠)
  • \用于代码换行  比如  tiantian \ xiangshang    等于  tiantian xiangshang(输出的时候还是显示在同一行),注意这个\是通过回车打出来的。
  • 字符串里面有引号,那么在每个引号之前加上\,程序就可以区分不同引号(a = (‘ He said, \”I\’m yours!\” ‘ ))

11. 三单引号和三双引号((”’)或者(“””)),输入什么,就输出什么,可以实现字符串中换行。参见这里

12.  数字字符串化 print(‘My age is’ + str(18))

13. % 对字符串进行格式化,其中%d 替换整数,%f 替换小数,%.2f替换保留两位小数。例子:print(‘Price is %f’ % 4.99) print(‘My age is %d’ % 18)  (注:数字可以替换为已经被定义数字的变量名)name = ‘Crossin’
print(‘%s is a good teacher.’ % name)    (注释:%s替换一段字符串)
注:d-decimal   ;    f-float  ;    s-string

14.   延续上面的,print(“%s’s score is %d” % (‘Mike’, 87)),一个字符串里面替换两个,这里的(‘Mike’, 87)叫作元组(tuple)。

注:顺便提一下divmod函数,divmod(13, 3)返回的也是一个元组(4, 1),前面一个元素是商,后面一个是余数。

15. 不换行打印

end=‘ ‘   输出一个之后,空格,输出第二个。end 参数的作用是指定 print 结束之后的字符,默认是回车。你可以试试设置成不同字符的效果。

16. 输出一个变量的数据类型,比如a = 1,然后print(a, type(a))得到的是1 <class ‘int’>,这里的int可以变为字符串str、bool类型等。

17.  错误代码print(‘Hello’+1) 或者print(‘hello%d’ % ‘123’)
前者的错误原因:加号只能用于数字之间或者字符串之间;%d对应的是数字,而不是字符串,加上引号的数字就变成了字符串。

18. 数据类型转换

  • int(x)     #把x转换成整数
  • float(x)  #把x转换成浮点数
  • str(x)     #把x转换成字符串
  • bool(x)   #把x转换成bool值
    例子:
    int(‘123’) == 123
    float(‘3.3’) == 3.3

    str(111) == ‘111’
    bool(0) == False

19. bool类型转换,转成bool类型,下列情况被认为是False:

  • 为0的数字,包括0,0.0
  • 空字符串,包括”,””
  • 表示空值的 None
  • 空集合,包括(),[],{}
    在 if、while 等条件判断语句里,判断条件会自动进行一次bool的转换。比如下面的等价表达

    if a:= if bool(a) == True: = if a != ”:

20. 构建函数,输入参数(可以不输入),经过函数作用,得到输出结果
def sayHello():
print (‘hello world!’)

sayHello()
sayHello()
sayHello()
注:先前的input()和range()函数都是内建函数,直接调用就行

21.  【Python 第20课】
(1)  在terminal输入python 并敲下回车,就可以进入python环境了;
(2)  C:\Users\hujie>dir   输入dir得到当前文件夹下所有子文件的信息
(3)  输入cd 得到目录名;
(4)  输入cd.. 返回到上一级目录;
(5)  输入cd  目录名, 进入当前目录的子目录。
注:dir-directory(目录);cd-change directory(改变目录)

22.  if, elif, else 连用  (最后一个else是可选的)

23.  列表list的使用
print(list(range(1,10)))输入结果为[1, 2, 3, 4, 5, 6, 7, 8, 9]
l = [365, ‘everyday’, 0.618, True]可以是不同类型数据的混合
(1)  for i in l:然后  print(i)即可遍历l中所有的元素;
(2)  print (l[1])输出’everyday’
(3)  修改元素l[0] = 123,原list变为[123, ‘everyday’, 0.618, True];
(4)  添加元素 l.append(1024),原list变为 [123, ‘everyday’, 0.618, True, 1024];
如果在中间插入或者前面添加元素,那么要变动新增元素后面所有元素的物理地址(存疑),这样程序不友好,因此append方法 原地修改列表对象,是真正的列表尾部添加新的元素,速度最快,推荐使用。
对列表a=a+[50],这样生成的a不是原地扩展,得到的是一个新的物理地址的列表a。
(5)  删除元素del l[0],原list变为 [‘everyday’, 0.618, True, 1024];
(6)  负索引(index),l[-3]表示倒数第3个元素;
(7)  切片(slice),l[1:3]得到的结果是[‘everyday’, 0.618],如果不指定第一个数,切片就从列表第一个元素开始。 如果不指定第二个数,就一直到最后一个元素结束。 都不指定,则返回整个列表;
(8)  extend()操作,这个和append很类似,也是原地尾部操作,不同之处append是添加单个元素,extend是添加多个元素组成的list。
a=[20, 30] b=[10, 40] a.extend(b)
print(a)
得到的结果是:[20, 30, 10, 40] (9) insert的用法(不推荐)
>>> a = [10,20,30] >>> a.insert(2,100)    #2对应位置编号
>>> a
[10, 20, 100, 30] (10)  列表元素的删除,前面只讲了del操作,其实还有pop(),remove()
上图是del操作示意图,会出现元素的拷贝,所以效率不高。
pop()删除并返回指定位置元素(比如 a.pop(1) ),如果未指定位置则默认操作列表最后一个元素。
a.remove(20) 表示删除list   a中首次出现的20这个元素,若想要删除的元素不存在,则抛出异常。

汇总一下:
del a[0]   #删除列表a的第一个元素
a.remove(“tt”)   #删除列表a中的第一个”tt”元素,没有这个元素就报错
a.pop(0)  #删除列表a中的第一个元素,并将这个元素作为返回值。
a.clear()   #清空列表中的元素,得到一个空列表

(11)  列表的遍历
for obj in listObj:
print(obj)
(12)  列表的复制
a=[20, 30] b=a
print(id(a))
print(id(b))
输出两个相同的物理地址,说明b只是复制了a中的地址来引用[20, 30]所在的物理位置。也就是栈中的两个元素a和b都对应堆中的同一个对象。
a=[20, 30] b=[]+a
print(id(a))
print(id(b))
修改之后就是两个变量分别对应两个对象,只是这两个对象数值和类型上相同,但是ID(物理地址)不同。
(13)  a.sort()原地排序, a.sort(reverse=True) 也是原地排序(降序),random.shuffle(a)原地打乱顺序。注意这些都是有返回值的,所以不能写类似b=a.sort()。
a = sorted(a)或者c = sorted(a,reverse=True) 则是新建了一个列表,开拓了一个新的内存空间。

对于列表a=[10, 20, 30, 40]来说,list里面的物理地址是连续的。

例子:
a=[1,2,3] print(id(a[0]))
print(id(a[1]))

输出结果:
1688590512
1688590528   #12+16   每个unicode是16位。

list(字符串)得到将字符串转变为list。
list(range(10))将range的type变为list。

24.  字符串的分割split()
(1)  sentence = ‘I am an English sentence’
a=sentence.split()   (默认按照空格/换行/制表符分割)
(2)  指定分隔符’.’,
section = ‘Hi. I am the one. Bye.’
a=section.split(‘.’)
得到[‘Hi’, ‘ I am the one’, ‘ Bye’, ”]

25. 用join函数连接list中的元素
(1) a=’;’.join([‘apple’, ‘pear’, ‘orange’])
print(a)得到apple;pear;orange
(2)  s = ‘;’
li = [‘apple’, ‘pear’, ‘orange’]
fruit = s.join(li)
print (fruit)同样得到apple;pear;orange
(3) a=”.join([‘hello’, ‘world’])
print (a)得到helloworld

26. 字符串的遍历/索引/切片/连接
这个个list里面的用法很类似
(1)  遍历
word = ‘helloworld’
for c in word:
print(c)
(2)  索引(与list不同的是,字符串不能通过索引访问去更改其中的字符)
print (word[0])
print (word[-2])
(3)  切片
print (word[5:7])
print (word[:-5])
print (word[:])
(4)  连接
a = ‘,’.join(‘word’)
print(a)得到w,o,r,d

27. 文件操作

同子目录下
# read
f = open(‘任缥缈.txt’, encoding= ‘utf-8’)   #中文的编码 ,打开文件
s = f.read()    #读取文件
print(s)        # 输出内容
f.close()      # 关闭文件

# write
f = open(‘write_test.txt’, mode = ‘w’, encoding = ‘utf-8’)  # w表示写入, 生成新文件
f.write(‘我很好\n’)
f.write(‘你好吗\n’)
f.close()

readline() #读取一行内容
readlines() #把内容按行读取至一个list中

注:上面的mode=’w’可以删除mode =,效果一样;如果选择’w’模式就不能read了,写入模式下会删除先前的内容;如果write的文件不存在,那么会自动创建一个文件;默认是阅读模式,即’r’,如果文件不存在,则会出现异常;如果想不删除以前的内容而进行写入,那么选择’a’ 模式(appending);如果是记事本输入的,那么‘utf-8’就该变成‘gbk’,如果是浏览器内复制的,那么就是‘utf-8’(浏览器的中文编码多使用 utf-8)。

28. 制表符
表符‘\t’:作用是在不使用表格的情况下在垂直方向按列对齐文本。类似word TAB
例子: result = ‘%s \t: %d\n’ % (data[0], sum)

29. break 语句
在while 循环或者for…. in 循环,想提前跳出循环,可以用if….break语句,其中if给出跳出的限定条件。特别注意对齐方式

30. continue语句
break是彻底地跳出循环,而continue只是略过本次循环的余下内容,直接进入下一次循环。(下图中低于60分的不计入总成绩)注意:无论是continue还是break,其改变的仅仅是当前所处的最内层循环的运行,如果外层还有循环,并不会因此略过或跳出。

31. 异常处理(try…except语句)
除去开发者可以避免的错误,使用者可能输入一些非法值,这个时候就必须给出响应的“反馈”,常用的是try….except语句,比如打开一个本身就不存在的文件:文件存在,被打开,给出“回应”;文件不存在,同样要给出“回应”。总之,程序员的程序给用户用,必须考虑到所有情况。

32. 字典
字典格式 d = {key1 : value1, key2 : value2}
注意:
(1)  花括号 {},不是list的[];
(2)  键必须是唯一的;
(3)  键只能是简单对象,比如字符串、整数、浮点数、bool值。

创建字典的另一种方法:
r1= dict(name=”高小一”,age=18,salary=30000,city=”北京”)  #也常用
print(r1,type(r1))

结果为:
{‘name’: ‘高小一’, ‘age’: 18, ‘salary’: 30000, ‘city’: ‘北京’} <class ‘dict’>

还可以用zip()来创建字典对象
>>> k = [‘name’,’age’,’job’] >>> v = [‘gaoqi’,18,’techer’] >>> d = dict(zip(k,v))
>>> d
{‘name’: ‘gaoqi’, ‘age’: 18, ‘job’: ‘techer’}

通过 fromkeys 创建值为空的字典
>>> a = dict.fromkeys([‘name’,’age’,’job’])
>>> a
{‘name’: None, ‘age’: None, ‘job’: None}

例子:score = { ‘萧峰’: 95, ‘段誉’: 97, ‘虚竹’: 89 }
访问:print (score[‘段誉’])或者score.get(‘慕容复’)
注:使用get更好,因为如果你输入的key在字典里找不到,会输出None,而前者的方法会报错
遍历:for name in score:   然后print (score[name]),这里的name就是key;
重新赋值:score[‘虚竹’] = 91;
增加元素:score[‘慕容复’] = 88;
删除元素:del score[‘萧峰’];
建立一个空字典:d = {}。
列出所有键值对
>>> print(a.items())得到的结果如下
dict_items([(‘name’, ‘gaoqi’), (‘age’, 18), (‘job’, ‘programmer’)])

dict = {'Name': 'Runoob', 'Age': 7}
for i,j in dict.items():    #分别对应字典中的键和值
    print(i, ":\t", j)


#输出结果
Name :   Runoob
Age :    7

列出所有键/值:
>>> print(a.keys(), type(a.keys()))    # a是字典变量
dict_keys([‘name’, ‘age’, ‘job’])  <class ‘dict_keys’>
>>> print(a.values(), type(a.values()))
dict_values([‘gaoqi’, 18, ‘programmer’])  <class ‘dict_values’>

字典的遍历

d = {'Name': 'gaoqi', 'Age': 18,"address":"西三旗001号楼" }
for  x in d:  #  遍历字典所有的key
    print(x)

for  x in d.keys():  # 遍历字典所有的key
    print(x)

for  x in d.values():  #  遍历字典所有的value
    print(x)

for  x in d.items():  #   遍历字典所有的"键值对"
    print(x)

#  第一个结果
Name
Age
address

#  第二个结果
Name
Age
address

#  第三个结果
gaoqi
18
西三旗001号楼

#  第四个结果
('Name', 'gaoqi')
('Age', 18)
('address', '西三旗001号楼')

注意,遍历字典的时候默认是遍历value。

例子:用列表和字典存储下表信息,并打印出表中工资高于 15000 的数据(重点)

33. 模块
模块可以理解为是一个包含了函数和变量的py文件。在你的程序中引入了某个模块,就可以使用其中的函数和变量。
我们先前的import random就是导入random模块,但是这个模块里面有很多种类的函数,我们必须选择需要的进行调用,比如random.randint(1, 10) 和random.choice([1, 3, 5])。

查找random模块的所有函数:在terminal窗口输入python回车,然后输入 import random回车然后输入dir(random)即可显示出该模块(库)包含的所有函数。

math模块:要想输出pi, 就要import math,然后调用math.pi,即输出print(math.pi)。有的时候有简写,比如通过from…import…指明from math import pi 然后print (pi)注意math中的pi(math.pi)已经被重命名为pi,为了避免歧义,可以写成from math import pi as math_pi然后print (math_pi)

34. 猜数字游戏改进

35.  函数的默认参数

对于函数来说,一般要输入参数,然后得到对应的结果,但是我们也可以指定在没有参数下的结果,类似f()也对应一个确切的结果。我们先前写的def hello(name): 和print (‘hello ‘ + name)函数,然后调用hello(‘world’),即给name赋值’world’,最终的输出结果就是hello world。

指定默认参数:def hello(name = ‘world’): 和print (‘hello ‘ + name),那么调用hello()得到的就是hello world,即默认参数;当然你指定内容的话,仍然有效,比如调用hello(‘python’)得到的依然是hello python。

注:注意,当函数有多个参数时,如果你想给部分参数提供默认参数,那么这些参数必须在末尾。比如:def func(a, b=5):而不是def func(a=5, b): 。

35. 查天气

requests库的作用:包括gzip压缩、字符编码、json的自动处理。如果用Python自带的urllib.request库,工作量就会增加很多。

首先安装第三方库 pip3 install requests(terminal下)

import requests
req = requests.get("http://hao123.com")
print(req)
req.encoding = "utf8"
content = req.text
print(content)

get是requests库中的一个函数,将打开网址得到的变量存入到req,而print(req)返回的是一个数组,如果是200则说明网站访问请求成功。red.encoding=’utf-8’表示的是编码方式,因为里面有中文,所以指定这种编码方式。req.txt是req内容变量的text属性,按照文本的内容赋值给content,然后输出content即得到网站的代码,其中包含html+css+javascrpit等语言。我们把content的内容复制到记事本,然后把后缀改成html,那么同样可以用浏览器打开。

例子:查天气

第一步:查出信息

while True:
    city = input('请输入城市,回车退出:\n')
    if not city:  # 如果输入回车,那么意味着city是空,not空的布尔就是真,于是执行break
        break
    req = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=%s' % city)
    print(req.text)

这里的while True可以保证我们能够多次查询,如果不输入任何内容,那么程序自动结束。

注:如果提示编码错误,那么在开头添加# -*- coding: utf-8 -*-
我们获取的天气的信息内容是“json格式”。

第二步:整理信息

目前得到的是 利用req.text 拿到的json格式的天气数据,数据格类型还是字符串(只不过满足json格式),利用req.json()将json格式的字符串改成真正的字典,然后找到对应的信息,一次输出。

36. 面向对象

类(class)和对象(object),比如’hello’就是一个字符串类(型)的对象,类描述的是抽象的共同特点,对象是具体的某个东西。
print(dir(s))      得到字符串这种类的所有属性
print(dir(l))   得到list这种类的所有属性

37. and-or技巧   和逻辑运算符
bool and a or b语句中,当bool条件为真时,结果是a;当bool条件为假时,结果是b。
例如:

结果为heaven
hell等价于print ((a > 0) and “big” or “small”)
特别注意:当a本身是个假值(如0,””)时,会出现误判,即使前面的bool是真,程序仍然选择输出b。确保a的值不会为假。最常用的方式是使 a 成为 [a] 、 b 成为 [b],然后使用返回值列表的第一个元素:注:and-or似乎只是替代if-else而已,其实不然,在特殊场合,不能用if语句,这时就只能选择and-or技巧了,比如lambda函数中(后面会详述)。

逻辑运算符(特别注意返回值比如
a=True
a or 20/0
不会报错,而得到True

a=False
b=30
a or b
得到30  (注意不是true)

38. 元组

又叫作“多元组”,多个元素(数字、字符串随意)按一定顺序排列得到的组合。
() 元组
[] List
(key1:value1,  key2:value2,  ….)     字典

Python的元组与列表类似,不同之处在于元组的元素不能修改
注:当元组中只有一个元素时,比如tuple_a=(1, )必须要在元素后面加上逗号,不然会有歧义,比如如果不这样规定, 你无法区分(1)到底是元组还是一个数加上括号。

元组没有增加元素、修改元素、删除元素相关的方法。 能进行的操作如下:
1. 索引访问
2. 切片操作
3. 连接操作
4. 成员关系操作
5. 比较运算操作
6. 计数:元组长度 len()、最大值 max()、最小值 min()、求和 sum()等。

元组的创建方法:
a = (10,20,30)
a = 10,20,30
b = tuple()
b = tuple(“abc”)
b = tuple(range(3))
b = tuple([2,3,4])

排序:    返回的是一个list
>>> a = (20,10,30,9,8)
>>> print(sorted(a))
[8, 9, 10, 20, 30]

zip函数
zip(列表 1,列表 2,…)将多个列表对应位置的元素组合成为元组,并返回这个 zip 对象。
>>> a = [10,20,30] >>> b = [40,50,60] >>> c = [70,80,90] >>> d = zip(a,b,c)
>>> print(list(d),type(d))
[(10, 40, 70), (20, 50, 80), (30, 60, 90)]  <class ‘zip’>

元组总结:
1. 元组的核心特点是:不可变序列。
2. 元组的访问和处理速度比列表快。
3. 与整数和字符串一样,元组可以作为字典的键,列表则永远不能作为字典的键使用。

39. 数学运算(math模块)
使用之前import math,然后按需求选择math里面特定的函数,下面列举几个常用的:
(1)  math.pi # 圆周率π
(2)  math.e # 自然常数
(3)  math.ceil(x) # 对x向上取整
(4)  math.floor(x) # 对x向下取整
(5)  math.pow(x,y) # 指数运算
(6)  math.log(x) # 对数,默认基底为e
(7)  math.sqrt(x) # 平方根
(8)  math.fabs(x) # 绝对值
(9)  math.sin(x)
(10)math.degrees(x) # 弧度转角度
(11) math.radians(x) # 角度转弧度

所有的math库模块,可以在参考官方文档

40. 正则表达式 (参考1    参考2     参考3)

正则表达式的作用就是定下一定的规则,然后按照这个规则去寻找符合条件的字符串。正则表达式就是记录文本规则的代码。
(1)  最简单的正则表达式,只有基本的字母或数字,它满足的匹配规则就是完全匹配
得到的结果是[‘hi’, ‘hi’],如果用“\bhi\b”匹配不到任何结果。但“\bhi”的话就可以匹配到1个“hi”,出自“his”。“[Hh]i”的意思是既匹配“Hi”,又匹配“hi”。

\b表示字母数字与非字母数字的边界, 非字母数字与字母数字的边界。
比如”site sea sue sweet see case sse ssee loses”中site 以前一后两个\b   所以如果用‘\b \b’索引,会找出任意单词前后部分的边界。\w匹配字母或数字或下划线或汉字等。“隐式位置” \b,匹配这样的位置:它的前一个“显式位置”字符和后一个“显式位置”字符不全是 \w。

“*”表示任意数量连续字符

r”\bhi”表示不对””内的字符串进行转义。\有转义的功能,比如\n表示换行。r是raw的意思,表示按照原始的模样。

import re的re就是python的正则表达式模块(库),findall是其中一个方法,用来按照提供的正则表达式,去匹配文本中的所有符合条件的字符串。返回结果是一个包含所有匹配的list。

“\S”,它表示的是不是空白符的任意字符(一个)。匹配结果为[‘H’, ‘i’, ‘,’, ‘I’, ‘a’, ‘m’, ‘S’, ‘h’, ‘i’, ‘r’, ‘l’, ‘e’, ‘y’, ‘H’, ‘i’, ‘l’, ‘t’, ‘o’, ‘n’, ‘.’, ‘I’, ‘a’, ‘m’, ‘h’, ‘i’, ‘s’, ‘w’, ‘i’, ‘f’, ‘e’, ‘.’]。

“.”在正则表达式中表示除换行符以外的任意字符(一个)。“i.”去匹配,就会得到 [‘i,’, ‘ir’, ‘il’, ‘is’, ‘if’]。

懒惰匹配:“I.*?e”   结果为[‘I am Shirle’, ‘I am his wife’]   (先匹配头,碰到符合条件的尾巴就整体匹配一下,继续寻找下一个头)

贪婪匹配:“I.*e”  结果为 [‘I am Shirley Hilton. I am his wife’]    (先匹第一个头,然后匹配最后一个尾巴)

例子:最后留一道习题: 从下面一段文本中,匹配出所有s开头,e结尾的单词。 site sea sue sweet see case sse ssee loses
解答为:r’\bs\S*e\b’
运行结果为[‘site’, ‘sue’, ‘see’, ‘sse’, ‘ssee’]

说明:前后\b把单词隔开,中间s表示开头,e表示结尾,*表示任意字符(sXXXe),而\S表示没有空格(排除sXX  XXe)。

41. 随机数(random模块)
(1)  random.randint(a, b)可以生成一个a到b间的随机整数,包括a和b。注:a、b必须都是整数。
(2)  random.randint(3, 3) 结果只有3。
(3)  random.random() 生成一个随机浮点数[0.0, 1.0)左边闭合,右边开。
(4)  random.uniform(a, b)生成a、b之间的随机浮点数。不过与randint不同的是,a、b无需是整数,也不用考虑大小。
(5)  random.choice(seq)

(6)  random.randrange(start, stop, step)
(7)  random.sample(population, k) 从population序列(list、元组、字符串)中,随机获取k个元素,生成一个新序列。sample不改变原来序列。
(8)  random.shuffle(x)  把序列x中的元素顺序打乱。shuffle直接改变原有的序列。

注:在电脑模拟中伪随机数用来模拟产生随机的过程,因而得到的随机数不是真正的随机数。伪随机数的一个特别大的优点是它们的计算不需要外部的特殊硬件的支持,因此在计算机科学中伪随机数依然被使用(可以选取不同的)。真正的随机数必须使用专门的设备,比如热噪信号、量子力学的效应、放射性元素的衰退辐射,这些是完全不可预测的,而伪随机数实际上是可以预测的。

42. time模块

epoch [ˈiːpɒk]时代; 纪元; 时期;
计算机领域的特殊事件epoch,它表示的时间是1970-01-01 00:00:00 UTC
time.time()返回的就是从epoch到当前的秒数(不考虑闰秒)。这个值被称为unix时间戳

一段程序,首位都用time.time()获取一下时间,然后两个时间相减,就得到了程序运行消耗的时间。

time.sleep(secs)  让程序暂停secs秒注:在抓取网页的时候,适当让程序sleep一下,可以减少短时间内的请求,提高请求的成功率。

43. 程序排错技巧
每生成一次变量,让这个变量输出一次,看程序循环到哪里就循环不动了。
原程序改造之后的程序(输出调试信息)

44. python 2和python 3的差异
(1)  print(‘this is version 3’) , 而2中不需要括号(3中print是一个函数,所以有括号);
(2)  python 2和3的不换行输出
2:print ‘*’,
3:print(‘*’, end=’ ‘)    # python每次print默认以换行结束,这里使用end,将换行结束变成了空格结束。

后续碰到了再补上,学习别人的程序,要搞清楚是2还是3。

45.   python shell
三个右括号 >>> 是 python 输入的提示符,它表示 python 解释器已经准备好了,等待你的命令。
python shell 可以非常方便的运行 python 语句,这一点对调试、快速组建和测试相当有用。当你在编写代码的过程中,对一些方法不确定的时候,可以通过 python shell 来进行试验。

46. 列表解析(List Comprehension)

通过一个已有的列表生成一个新的列表
例子:找出一个list中的偶数,然后组合成新的list
(1)  遍历法(2)  列表解析注:如果想将原来list中的偶数取出来,然后将这些偶数都除以2,然后输出得到的新的list,那么可以写成[i / 2 for i in list_1 if i % 2 == 0]

在实际开发中,适当地使用列表解析可以让代码更加简洁、易读,降低出错的可能。

习题:把1到100的整数里,能被2、3、5整除的数取出,以分号(;)分隔的形式输出。
答案:print (‘;’.join([str(i) for i in range(1,101) if i % 2 == 0 and i % 3 == 0 and i % 5 == 0]))

改写成容易看懂的是

a=list(range(1,101))
list_2 = [str(i) for i in a if i % 2 == 0 and i % 5 == 0 and i % 3 == 0 ]
print(";".join((list_2)))

#结果
30;60;90

注:得到的数,我们必须str化。list=[1,’2′,’3′] 中第一个元素是数字,后面的两个是字符串。数字字符串化参见知识点18。print(‘My age is’, str(18))  注意逗号。

47. 函数的参数传递

(1)  普通形参
def func(arg1=1, arg2=2, arg3=3):

print (arg1, arg2, arg3)

调用
func(2, 3, 4)
func(5, 6)
func(7)

结果为
2 3 4
5 6 3
7 2 3
注:输入参数不足的时候,匹配能匹配的部分,其他的输出默认值

指定参数值
func(arg2=8)
func(arg3=9, arg1=10)

结果为
1 8 3
10 2 9

这样的调用是错误的
func(arg1=13, 14)   #  指定的放后面
func(15, arg1=16)   #不能指定同一个

注:定义参数默认值的函数可以在调用时更加简洁。大量 Python 模块中的方法都运用了这一方式,让使用者在调用时可以提供尽可能少的参数。

(2) 一种更加灵活的参数传递方式(func(*args)—元组)
注:可以接受任意数量的参数。在变量前加上星号前缀(*),调用时的参数会存储在一个 tuple(元组)对象中,赋值给形参。上面没有星号就会报错。不过有一点需要注意,tuple 是有序的,所以 args 中元素的顺序受到赋值时的影响。

注:这里的星号应该的作用和正则表达式中的作用应该是一样的,就是匹配任意次(0次或者多次),那么输入的参数就可以是任意个。

(3) 一种更灵活的参数传递方式(func(**kargs)—字典)

func(*args) 方式是把参数作为 tuple 传入函数内部;而 func(**kargs) 则是把参数以键值对字典的形式传入。

一个星号*    对应元组
两个星号**  对应字典。

字典是无序的,所以在输出的时候,并不一定按照提供参数的顺序。同样在调用时,参数的顺序无所谓,只要对应合适的形参名就可以了。于是,采用这种参数传递的方法,可以不受参数数量、位置的限制

例子:print语句中的k表示的是字典中的key,kargs[k]表示key对应的value。字典的形参为kargs。
输出结果为

三种调用方式混合在一起的例子:结果 特别注意:有默认值的形参放在无默认值形参的后面。

48. lambda 表达式(体现了python的简洁)输出
6
15

lambda 表达式的语法格式:
lambda 参数列表: 表达式
注:它的写法比 def 更加简洁。但是,它的主体只能是一个表达式,不可以是代码块,甚至不能是命令(print 不能用在 lambda 表达式中)。所以 lambda 表达式能表达的逻辑很有限。能用lambda的地方其实都可以用def替代,只是前者更简洁,但是能用def的地方,不一定能用lambda。

上面程序等价于

更复杂的例子:

输出  5   (首先a = fn(2)得到的是2+y,而a(3)让y = 3)

更复杂的例子
g = [lambda a:a*2,lambda b:b*3,lambda c:c*4] print(g[0](6),g[1](7),g[2](8))

输出结果为:
12 21 32

49. 变量的作用域

代码1:x的值在函数内部发生改变,但是并不传递到函数外,所以最后一行中的x依旧是50。输出:
X in the beginning of func(x): 50

X in the end of func(x): 2
X after calling func(x): 50

代码2:报错,没定义就用

代码3:函数内部定义了全局变量,于是将赋值后的x传递到函数之外。输出:
X in the beginning of func(x): 50

X in the end of func(x): 2
X after calling func(x): 2
注:调用函数,最好写成显式,上面的func()这种写法就不太好。

50. map 函数   (参考知乎)
map()函数是python内置的高阶函数,它接收一个函数f以及一个list,并通过把函数f依次作用在list的每个元素上,得到一个新的list并返回。map()函数不改变原有的 list,而是返回一个新的 list。标准格式为:

map(function_to_apply, list_of_inputs)

  • function_to_apply:代表函数
  • list_of_inputs:代表输入序列

# 例子1 将list中的字符型的数字,转换成int
a = list("1213456789")
print(a)   #得到的是一个个单独的数字字符
b = map(int, a)
print(b, type(b), list(b) )   # b的类型还是map, 只有list之后才能准确输出数字组成的list

# 输出结果:
['1', '2', '1', '3', '4', '5', '6', '7', '8', '9']
<map object at 0x02F90A30> <class 'map'> [1, 2, 1, 3, 4, 5, 6, 7, 8, 9]


# 例子2  将数字的list中的每个数字都平方一下
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def f(x):
    return x*x
b = map(f, a)
print(list(b))

# 输出结果:
[1, 4, 9, 16, 25, 36, 49, 64, 81]



# 例子3  两个或者多个list的情况
a = map(lambda x,y:x**y,[1,2,3],[1,2,3])
print(a,list(a))

# 输出结果:
<map object at 0x0304AF90> [1, 4, 27]

51. reduce 函数(参考知乎)
reduce相比map稍复杂点

reduce的工作过程是 :在迭代序列的过程中,首先把 前两个元素(只能两个)传给 函数,函数加工后,然后把 得到的结果和第三个元素 作为两个参数传给函数参数, 函数加工后得到的结果又和第四个元素 作为两个参数传给函数参数,依次类推。

# 求解 n的阶乘----方法1
from functools import reduce    # reduce函数不能直接使用,必须先import
n = 5
print(reduce(lambda x, y: x*y,range(1, n+1)))


# 求解 n的阶乘----方法2
from functools import reduce
def f(x, y):
    return x*y
n = 5
items = range (1, n+1)
factorial =  reduce(f, items)
print(factorial)

52. 多线程

53. format 函数

format函数是用来替代前面的%的,它可以接受不限个数的参数,而且位置可以不按顺序。

比如:
a = “我叫{0},我今年{1}岁了,我的专业是{2}。”
print(a.format(“胡杰奇”,”25″,”材料科学与工程”))
输出结果为:我叫胡杰奇,我今年25岁了,我的专业是材料科学与工程。
注意:如果是编号的话,从0开始。

换一种:
a = “我叫{name},我今年{age}岁了,我的专业是{major}。老师说{name}成绩一般。”
print(a.format(major= “材料科学与工程”, name=”胡杰奇”, age=18))
输出结果为:我叫胡杰奇,我今年18岁了,我的专业是材料科学与工程。老师说胡杰奇成绩一般。
注:这个例子看出,只要指定好了,顺序不重要。一一映射,很方便。{1}或者{name}这些相当于占位符,想一下自习室占座,我先仍一本数把座位占着,然后我或者我的小伙伴谁要去上自习都可以用那个位置。

54. 填充与对齐(排版)

^、<、>分别是居中、左对齐、右对齐,后面带宽度
:号后面带填充的字符,只能是一个字符,不指定的话默认是用空格填充

例子1:
“{:*>8}”.format(“245”)
得到 ‘*****245’
{:*>8}表示右对齐,8表示占据8个位置,由于我们只有一个三位数,所以左侧的5个位置由我们制定的*来占据。

例子2:
“我是{0},我喜欢数字{1:*^8}”.format(“高淇”,”666″)
得到’我是高淇,我喜欢数字**666***’

另外的方法是center()、ljust()、rjust()这三个函数用于对字符串实现排版。

55. 数字格式化

先前我们要保留几位小数的做法是print(“temperature is %.2f” % 35.5486)
这里用format更方便, 浮点数通过 f,整数通过 d 进行需要的格式化

例子1:
a = “我是{0},我的存款有{1:.2f}”
a.format(“高淇”,3888.234342)
得到:
‘我是高淇,我的存款有 3888.23’

56. index/count/len函数用法

index()获得指定元素在列表中首次出现的索引,注意是首次出现的地方,而不是所有的index,matlab中是显示所有的index。

例子:
a = [10,20,30,40,50,20,30,20,30]
a.index(20)
得到1

如果:
a = [10,20,30,40,50,20,30,20,30]
a.index(20, 5, 7) #从索引位置 5 到 7 这个区间,第一次出现 30 元素的位置
得到 6
注:如果没有7,只有5,那么表示从位置5索引到最后面。

count()可以返回指定元素在列表中出现的次数
例子:
>>> a = [10,20,30,40,50,20,30,20,30] >>> a.count(20)
3

len()返回列表长度
例子:
>>> a = [10,20,30] >>> len(a)
3

注:可以用于求列表的平均值。count也可用于字符串处理,而不只是list。

57. enumerate函数

enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
注:enumerate [ɪˈnjuːməreɪt] v.列举; 枚举

aa=[“a”,”b”,”c”,”f”,”a”] print(enumerate(aa))
print(list(enumerate(aa)))
输出结果为:
<enumerate object at 0x013EE238>
[(0, ‘a’), (1, ‘b’), (2, ‘c’), (3, ‘f’), (4, ‘a’)]

和for连用的例子:

aa = ['a', 'b', 'c', 'f', 'a']
for index,s in enumerate(aa):
    if s== "a":
        print(index)

# 如果用老方法
aa = ['a', 'b', 'c', 'f', 'a']
bb = 0
for x in aa:
    if x == "a":
        print(bb)
    bb += 1

58. reverse函数

作用是将一个列表颠倒过来。比如:
a=[1,2,3,4] b=a.reverse()
print(b)   # 返回None
print(a)   #返回[4, 3, 2, 1]

所以正确的写法就是:
a=[1,2,3,4] a.reverse()
print(a)

reversed()返回迭代器注:list第二次返回空,因为第一次已经遍历完了。

我们将列表升序排列是a.sort()   注意这个没有返回值,只是对a进行操作(和a.reverse()类似,即b=a.sort() 或者b=a.reverse()得到的是None),如果想逆序就用a.sort(reverse.True)。

59. 大小写转换

s = What Is Your Name?
print(s.swapcase()) #大小写互换

s.lower()-变成小写
s.upper()-变成大写
s.swapcase()-大小写互换
a.capitalize()-产生新的字符串,首字母 大写
a.title()-产生新的字符串,每个单 词都首字母大写

60. 删除元素的多种方法 (可以参考这里)

自己想的方法:
a=[10,10,30,50,40,10] b=[i for i in a if i!=10]   #循环遍历出想要的元素到新的list(等价于删除不要的10)
print(b)

令外就是23中的提到的三种方法:
del a[0]   #删除列表a的第一个元素
a.remove(“tt”)   #删除列表a中的第一个”tt”元素,没有这个元素就报错
a.pop(0)  #删除列表a中的第一个元素,并将这个元素作为返回值。

61. 集合操作

其实我们可以发现前面的元组、列表、字典还是存在一些缺陷的,比如删除特定元素,每次只能删除一个。下面介绍的集合在这方面更具有灵活性。

正如我们数学上集合的概念,集合就是里面一堆东西放在一起,并不区分每个元素的先后顺序,重要的只是某个元素是在集合里面还是在集合外面。对集合来说,你输入时候的元素在集合中的顺序,并不代表输出时候的顺序,顺序只取决于物理地址。特别注意:集合会删除重复的元素

(1)  创建集合  a = {3,5,7}
(2)  将列表/元组转为集合  a = [‘a’,’b’,’c’,’b’]    b = set(a)
(3)  添加元素  a.add(9)
(4)  删除元素/清空集合   a.remove(20) 或者a.discard(20) (如果不存在20这个元素,用remove方法会抛出错误,discard不会);  a.clear()清空
(5)  集合操作:
并集  a|b   交集 a&b  差集 a.difference(b)     # a中删除和b中重复的元素

62. 标识符命名习惯

开发中约定俗成的命名习惯
63. 除法和幂次

注:我之前用pow(2, 3)表示幂运算; divmod(13, 3)得到的是一个元组(4, 1)前者是商,后者是余数。

64. 进制转化

int(a  b)得到的就是十进制结果,其中a为任意进制的数,b为对应的进制数。

附:

例如: 0xff 得到255。

65. 增强型赋值运算

我们常用 a+=2表示a=a+2,需要特别注意的是+=中间没有空格。
运算符+、-、*,/、//、**和%和赋值符=结合可以构成“增强型赋值运算符”。

66. 查询某个对象的物理地址:id(变量名/obj),查询对象的类: type(obj),输出obj中储存的数据:print(obj)。

67. 拼接合并复制

我们知道字符串的拼接  “3”+“2”==> “32” ,但是其实元组和列表也可以拼接。[10,20,30]+[5,10,100] ==>[10,20,30,5,10,100]

乘法运算步进可以用于数字,同样可以用于字符串和列表,

68. 字符串的编码

python3直接支持Unicode(16位,二进制),可以表示世界上任何书面语言的字符。Python3的字符默认就是16位Unicode编码,ASCII码(8位,只够英文)是Unicode编码的子集。

使用内置函数ord()可以把字符转换成对应的Unicode码;
使用内置的chr()可以把十进制数字转换成对应的字符。

比如:ord(“A”)得到65。ord(“高”)得到39640。而chr(66)得到’B’。

69. 直接提取字符串的某个字符

先前我的做法是先将字符串转为list,然后对list的每个元素进行操作。其实可以直接用a[n]的方法提取某个字符。a[-1]就是最后一个字符。

70. 字符串的修改替换

正如我们上面说的,我先将一个字符串变成list,然后进行操作,因为list比较灵活,修改(增加元素、删除元素、替换元素)比较方便。而字符串本身要修改的话,不能修改自身,只能重新建立一个内从地址,存储修改后的字符串,这个过程用replace函数。

比如对字符串 ‘abcdefghijklmnopqrstuvwxyz’a[3]=”高”这个操作是没用的,必须用 a = a.replace(‘c’,’高’) ,等式左侧的a其实是一个新的变量,对应的是一个新的物理地址。
71. 字符串的切片slice

前面我们提到了list可以切片,其实可以直接对字符串进行slice。

slice的标准格式为:
[起始偏移量 start:终止偏移量 end:步长 step] 注:这个[:: -1]类似reverse(用于list),只是这里直接对字符串操作。

72. join()和split()互逆操作

注意:字符串拼接,不推荐使用+,推荐使用join函数,效率更高;每+用一次,得到一个新的对象,浪费内存。
比如循环执行a+=”my name”,那么每循环一次,生成一个新的变量。但是如果用list就比较好,因为list大小可变,每循环一次,在list末尾加上一个”my name”,最后将list中的内容都join一下。

73. 成员资格操作符

in /not in 关键字,判断某个字符(子字符串)是否存在于字符串中

a=[“a”,”b”,”c”]   #这是对list
>>>”a” in a
True
>>>”d” not in a
True
>>>”a” in “abc”   #这是对单个字符串
True

74. 文本查找

a=”’我是高淇,今年 18 岁了,我在北京尚学堂科技上班。我的儿子叫高洛希,他 6 岁了。我 是一个编程教育的普及者,希望影响 6000 万学习编程的中国人。我儿子现在也开始学习编 程,希望他 18 岁的时候可以超过我”’
注:find()和index()的区别在于如果找不到特定对象,那么前者返回的是-1,后者抛出异常

75. 字符串去除首尾信息

strip()函数,比如可以用于移除空格,比如
>>>t=”     madfaf   “
>>>t.strip( )    #去掉左右空格,其实可以写 strip() ,一样功能
‘madfaf’

注: .lstrip()和.rstrip()去除字符串左边/右边的特定字符。remove函数是用于列表的,不能直接用于字符串。

76.  多分支选择结构

特别注意if…..elif…..elif……..else 和if……if…….if…….所执行的效果是不同的,因为前者一旦满足某个条件,就跳出整个大if,而后者需要把每一个if都执行一遍。

77. 三元条件运算符(使代码简单、易读)

 

num = input(“请输入一个数字”)
print( num if int(num)<10 else “数字太大”)

如果传统的写法如下

注:下面的写法直接写在后面,感觉更简洁
if num%2==0:sum_even += num
else:sum_odd += num

78.  range的使用

前面我们只是大概用了一下range函数,但是没有详细介绍,现在详细说明一下。
range 对象是一个迭代器对象,用来产生指定范围的数字序列。格式为:
range(start, end, [step])

for i in range(10) 产生序列:0 1 2 3 4 5 6 7 8 9
for i in range(3,10) 产生序列:3 4 5 6 7 8 9
for i in range(3,10,2) 产生序列:3 5 7 9
   #最后一个2表示步长

79. python各种IDE其实都是解释器(python.exe)的外挂,只为让程序员更容易编程。

80.  将3赋值给a的过程:a=3

变量是对象的引用,因为变量存储的是对象的地址,变量通过这个地址来引用对象。变量位于栈内存,对象位于堆内存。

81. 调出帮助文档

直接在pycharm界面按F1的话,出现的是pycharm网页的帮助文档。选中自己编写的某个代码使用的函数,选鼠标选中后,左手按住Ctrl,右手单击一下;或者先选中后,然后按shift+F1。

82. 变量删除和垃圾回收机制,变量赋值技巧

a=3
del a
删除a其实是删除栈,而3这个对象没有变量取引用,就会被垃圾回收器回收,清空内存空间。

赋值:
(1)  a=b=3  等价于a=3; b=3  (注意这种写法简洁),二者的物理地址一样。
(2)  a,b,c=4,5,6 分别赋值。 a, b = b, a表示a和b的值互换。

83. float(3) 是生成一个新的对象,而不是修改原来的对象,int(), round()也是一样。

a=3
a= a+1也是生成一个新的对象

84. int(3.94)和round(3.94)结果的区别

85.  同一运算符

is 是判断两个标识符是不是引用同一个对象
is not 是判断两个标识符是不是引用不同对象

is 与 == 区别
is 用于判断两个变量引用对象是否为同一个,既比较对象的地址。
== 用于判断引用变量引用对象的值是否相等,默认调用对象的 __eq__()方法。

86. 字符串驻留机制和字符串比较

字符串驻留:仅保存一份相同且不可变字符串的方法,不同的值被存放在字符串驻留池中。 Python 支持字符串驻留机制,对于符合标识符规则的字符串(仅包含下划线(_)、字母 和数字)会启用字符串驻留机制驻留机制。

注:pycharm对此进行了优化,所以结果与老师以及上面的描述不同。
我在pycharm中结果为True

比较:
(1)  ==,!=对字符串进行比较,是否含有相同的字符。

(2)  is / not is,判断两个对象是否同一个对象。比较的是对象的地址,即 id(obj1)是
否和 id(obj2)相等。
即变量引用的地址是不是一样的。

87.  可变字符串

一般来说,字符串创建之后是不可变的,但是如果真的要频繁修改某个字符串(在原地址上修改),那么可以使用 io.StringIO对象或 array 模块 。具体看高老师的资料,这里不赘述。(感觉用到的概率不大)

88. 推导式生成列表

>> a = [x*2 for x in range(5)] #循环创建多个元素
>>> a = [x*2 for x in range(100) if x%9==0] #通过 if 过滤元素

89. 补充前面的多维列表

多维列表,顾名思义,就是列表中的元素是列表,那么索引的时候,必须有多个参数确定核心元素的位置,最常见的就是二维列表。
a = [
[“高小一”,18,30000,”北京”],
[“高小二”,19,20000,”上海”],
[“高小一”,20,10000,”深圳”],
]

内存结构:遍历一下所有元素:每输出一个元素,用制表符\t结束,这样输出结果能对齐。打印完一个人的信息之后,用print()实现换行。

90. else 语句

while、for 循环可以附带一个 else 语句(可选)。如果 for、while 语句没有被 break 语句结束,则会执行 else 子句,否则不执行。语法格式如下:

91. 循环代码优化(三个原则)

1. 尽量减少循环内部不必要的计算
2. 嵌套循环中,尽量减少内层循环的计算,尽可能向外提。
3. 局部变量查询较快,尽量使用局部变量

注:其实第一条和第二条是一回事其他优化手段:
1.
连接多个字符串, 使用 join()而不使用+
2.
列表进行元素插入和删除, 尽量在列表尾部操作

92. 使用 zip()并行迭代

a = [10,20,30] b = [40,50,60] c = [70,80,90] d = zip(a,b,c)
print(d,type(d))
得到的是<zip object at 0x02D5D4B8> <class ‘zip’>

要使用zip,两种方法:p=list(d)或者p=dict(d),注意第二种字典的方法,zip里面只能包含两个(abc必须去掉一个)
例子:
a = [10,20,30] b = [40,50,60] print(dict(zip(a,b)))
得到:{10: 40, 20: 50, 30: 60}

例子:
names = (“高淇”,”高老二”,”高老三”,”高老四”)
ages = (18,16,20,25)
jobs = (“老师”,”程序员”,”公务员”)
for name,age,job in zip(names,ages,jobs):
print(“{0}–{1}–{2}”.format(name,age,job))

其实我们其他方法也可以
names = (“高淇”,”高老二”,”高老三”,”高老四”)
ages = (18,16,20,25)
jobs = (“老师”,”程序员”,”公务员”)
for i in range(3):
print(“{0}–{1}–{2}”.format(names[i],ages[i],jobs[i]))

93. 推导式创建序列

前面88讲了推导式创建列表,这里推广到所有的序列(列表、字典、集合、元组)

(1)  列表
[x*2 for x in range(1,20) if x%5==0 ]

(2)  字典
{key_expression : value_expression for 表达式 in 可迭代对象}
统计文本中字符出现的次数:
>>> my_text = ‘ i love you, i love sxt, i love gaoqi’
>>> char_count = {c:my_text.count(c) for c in my_text}
>>> char_count
{‘ ‘: 9, ‘i’: 4, ‘l’: 3, ‘o’: 5, ‘v’: 3, ‘e’: 3, ‘y’: 1, ‘u’: 1, ‘,’: 2, ‘s’: 1, ‘x’: 1, ‘t’: 1, ‘g’: 1, ‘a’: 1, ‘q’: 1}

(3)集合( 和列表推导式的语法格式类似 )
>>> {x for x in range(1,100) if x%9==0}
{99, 36, 72, 9, 45, 81, 18, 54, 90, 27, 63}

(4) 元组( 元组是没有推导式 )
>>> (x for x in range(1,100) if x%9==0)
<generator object <genexpr> at 0x0000000002BD3048>

我们发现提示的是“一个生成器对象”。显然,元组是没有推导式的。 一个生成器只能运行一次。第一次迭代可以得到数据,第二次迭代发现数据已经没有了。

94. 函数简介

前面我们学习了Crossin编程中函数的内容,但看了高老师的视频,发现他讲得并不很好,或者不全,不透。下面几个知识点再次就函数这个重要知识点展开。

python的函数分为四类:内置函数(str()、int()、len()等)、标准库函数(海龟模块、math模块等,需要import.math导入)、第三方库函数、用户自定义函数。

定义函数的语法:
def 函数名 ([参数列表]) :
       ”’文档字符串”’     #解释说明这个函数的作用,大概说一下功能的实现方式
        函数体/若干语句

函数里面的a、b是形参,而10、20是实参
help(printMax.__doc__)可以得到printMax函数注释说明的文字内容

返回值

return 返回值要点:
1. 如果函数体中包含 return 语句,则
结束函数执行并返回值;
2. 如果函数体中不包含 return 语句,则返回 None 值。
3. 要返回多个返回值,使用列表、元组、字典、集合将多个值“存起来”即可。

95. 函数也是对象,内存底层分析

Python 中,“一切都是对象”。实际上,执行 def 定义函数后,系统就创建了相应的函数对象。我们执行如下程序,然后进行解释:执行 def 时,系统中会创建函数对象,并通过 print_star 这个变量进行引用:

 

执行“c=print_star”后,显然将 print_star 变量的值赋给了变量 c,内存图变成了:显然,我们可以看出变量 c 和 print_star 都是指向了同一个函数对象。因此,执行 c(3)和执行 print_star(3)的效果是完全一致的。 Python 中,圆括号意味着调用函数

96. 局部变量和全局变量

其实关于这一块,前面已经讲了一部分,大体就是def里面的参数都是局部变量,如果不用global声明的话。

效率: 局部变量的查询和访问速度比全局变量快,优先考虑使用,尤其是在循环的时候。在特别强调效率的地方或者循环次数较多的地方,可以通过将全局变量转为局部变量提高运行速度。

比如重复执行开方运算, 或者说重复调用math.sqrt() 函数,我们可以将这个函数存在b里面 b = math.sqrt,然后每次调用b(30)这样。

97. 传递可变对象的引用

可变对象包括:列表、字符串、字典、集合和自定义的对象等。

传递参数是可变对象(例如:列表、字典、自定义的其他可变对象等),实际传递的还是对象的引用。在函数体中不创建新的对象拷贝,而是可以直接修改所传递的对象。 注:函数调用之后,栈m就没了。
输出结果为:
m: 45765960
b: 45765960
[10, 20, 30]

98. 传递不可变对象的引用

不可变对象有: 数字、字符串、元组、function 等。

实际传递的还是对 象的引用。在”赋值操作”时,由于不可变对象无法修改,系统会新创建一个对象。

输出结果为:
n: 1663816464
n: 46608592
300
a: 1663816464

99. 浅拷贝和深拷贝

我们可以使用内置函数:copy(浅拷贝)、deepcopy(深拷贝)。

浅拷贝:不拷贝子对象的内容,只是拷贝子对象的引用。
深拷贝:会连子对象的内存也全部拷贝一份,对子对象的修改不会影响源对象。

形象地说,浅拷贝就只是复制爷爷这一个对象,深拷贝,就是额外复制一组,既有爷爷也有爸爸,还有儿子。理解就行。

100. 传递不可变对象包含的子对象是可变的情况

我们先前说了元组是不可变对象,但是元组中可能有一个元素是列表,那么我们可以通过二维定位对这个列表中的特定元素进行修改。
运行结果:
a: 41611632
m: 41611632
(10, 20, [888, 6])
m: 41611632
(10, 20, [888, 6])

101. 函数中的参数

参数可以通过两种方式对应,一个是按位置,另一个是按命名。前置比如def f(a, b, c)然后调用的时候f(1, 2, 3);后者比如def f(a, b, c),然后调用f(c=3, b= 2, a =1)。另外要注意#默认值参数必须位于普通位置参数后面。

可变参数(前面讲了,现在按高老师的方法说一下)
可变参数指的是“可变数量的参数”。分两种情况:
1. *param(一个星号),将多个参数收集到一个“元组”对象中。
2. **param(两个星号),将多个参数收集到一个“字典”对象中。

例子:
def f3(a,b,*c,**d):
print(a,b,c,d)

f3(8,9,20,30,name=’gaoqi’,age=18)
输出结果为:
8 9 (20, 30) {‘name’: ‘gaoqi’, ‘age’: 18}

102. eval()函数

eval 函数会将字符串当做语句来执行(存在一定的安全隐患)。

例子1:
s = “print(‘abcde’)”
eval(s)

例子2:
a = 10
b = 20
c = eval(“a+b”)
print(c)

例子3:
dict1 = dict(a=100,b=200)
d =
eval(“a+b”,dict1)
print(d)

102. 递归函数

分形几何就是递归。 自己调用自己的函数,在函数体内部直接或间接的自己调用自己。 递归函数包含:终止条件和递归步骤(把第 n 步的值和第 n-1 步相关联)。

注: 递归函数由于会创建大量的函数对象、过量的消耗内存和运算能力。在处理大量数据时,谨慎使用。

例子1:

def test01():
    print("test01")
    test01()

test01()

函数自己调用自己。每次输出一个test01,然后调用自身,于是再次输出test01,然后调用自身,最后栈空间被占满了,程序就报错。

例子2:

def test01():
    print("test01")
    test02()
    
def test02():
    print("test02")

test01()

执行最后一句test01(),先开辟一个栈(对应于test01函数),在执行过程中,需要调用test02函数,于是又开辟了一个栈(对应于test02函数)。test02被执行完毕之后,这个栈就没了,然后test01也被执行完毕,所以test01的栈也没了。

例子3:

def test01():
    print("test01")
    test01()
    print("####")

# def test02():
#     print("test02")
test01()

同样是先调用test01函数,创建一个test01的栈,然后输出test01,然后再次调用test01函数,创建一个test01的栈,然后输出test01,然后再次调用……..由于没有设置终止条件,于是无穷无尽地调用,知道所有的test01栈将内存空间沾占满,程序报错。

例子4:

def test01(n):
    print("test01",n)
    if n ==0:
        print("over")
    else:
        test01(n-1)
        
test01(4)

用if设置调用的终止条件,如果if的条件不满足,就执行else语句,继续调用;这里每调用一次,参数减1。
输出结果为:
test01 4
test01 3
test01 2
test01 1
test01 0
over
注:从下到上创建,从上到下关闭(依次)。

例子5:

def test01(n):
    print("test01",n)
    if n ==0:
        print("over")
    else:
        test01(n-1)

    print("test01***",n)

test01(4)

输出结果为:
test01 4
test01 3
test01 2
test01 1
test01 0
over
test01*** 0
test01*** 1
test01*** 2
test01*** 3
test01*** 4从下到上创建栈,创建一个新的,都要执行print(“test01”,n)这一句;调用完了,然后从上到下关闭栈,每个栈关闭的时候执行对应的print(“test01***”,n)。

104. 递归方法计算阶乘

105. 嵌套函数(内部函数)

嵌套函数: 在函数内部定义的函数!
f2()出了f1()用不了。

一般在什么情况下使用嵌套函数? 1. 封装 – 数据隐藏 外部无法访问“嵌套函数”。 2. 贯彻 DRY(Don’t Repeat Yourself) 原则 嵌套函数,可以让我们在函数内部避免重复代码。 3. 闭包 后面会详细讲解。
106.  nonlocal关键字

nonlocal 用来声明外层的局部变量。
global 用来声明全局变量。

def
b=10
def
nonlocal  b     #可以在内层函数对b进行修改
b=20

107. LEGB 规则

108. 面向对象初识

面向过程:一堆动词的排序,按一定动词顺序执行某个任务。

面向对象:一堆名词,将任务拆解成几个模块,各个模块要么继续拆解成子模块,要么直接对应过程(一定动词顺序执行)。

面向过程解决的是简单的问题,是微观的任务实现;面向对象是解决复杂问题,是宏观把握问题。当然宏观最终还是要落脚到微观,也就是说面向对象的过程最终拆解之后还是要面向过程的。

109. 数据的进化

1.   最简单数据,就是我们按计算器的那种数据,30,40,50.4 等这些数字。

2.    数组,将同类型的数据放在一起,比如 [20,30,40][“aa”,”bb”,”cc”]

3.  结构体将不同类型的数据放到一起,是 C 语言中的数据结构 。比如每个人的户口,包含各种信息:出生年月、户籍地址、身高、血型等等。

4.  对象
将不同类型的数据、方法(即函数)放到一起,就是对象。其实就是在结构体的基础上加上了方法。比如:

110. 类  (类名首字母大写,驼峰原则)

python中一切皆对象,类(饼干磨具)也是对象,只不过是产生对象的“对象”。

我们通过类定义数据类型的属性(数据)和方法(行为),也就是说,“类将行为和状态打包在一起”。
类产生对象,但是这个对象只从类中继承了方法,不继承属性(值不同)

一个典型类的定义:第一个def是构造方法,而第二个是实例方法。构造方法有特定的格式,先构造了,然后才能实现实例方法。s1=Student(“张三”,80)对应构造函数。
123是地址,传给了self。self.name就是刚才那个对象的name属性=外部传进来的数据(张三)。init是initial的缩写。

111. __init__构造方法和__new__方法

s1 = Student(‘张三’, 80) 的执行顺序
(1)  __new__()方法: 用于创建对象,但我们一般无需重定义该方法
(2) __init__()方法:初始化创建好的对象,初始化指的是:“给实例属性赋值

一个 Python 对象包含如下部分:
1. id(identity 识别码)
2. type(对象类型)
3. value(对象的值)
(1) 属性(attribute)
(2) 方法(method)

_init__()的要点如下:
1. 名称固定,必须为:__init__()
2. 第一个参数固定,必须为:self。 self 指的就是刚刚创建好的实例对象。
3. 构造函数通常用来初始化实例对象的实例属性,如下代码就是初始化实例属性:name和 score。

112. 实例属性


self对应于123这个物理地址,s1这个变量也引用123这个物理地址。123对应的对象是从磨具Student来的,我们可以对123这个地址的对象增加新的属性;但是如果再次调用Student的的话(s2=Student(“高淇”, 18)),会从磨具中套出一个新的对象,物理地址不再是123。

113. 实例方法

函数和方法的区别

1. 都是用来完成一个功能的语句块,本质一样。
2. 方法调用时,通过对象来调用。方法从属于特定实例对象,普通函数没有这个特点。
3. 直观上看,方法定义时需要传递 self,函数不需要。

实例对象的方法调用本质:
其他操作:
1. dir(obj)可以获得对象的所有属性、方法
2. obj.__dict__ 对象的属性字典
3. pass 空语句
4. isinstance(对象,类型) 判断“对象”是不是“指定类型”

Leave a Reply