本文共 11568 字,大约阅读时间需要 38 分钟。
谨以此blog记录我的python学习之路和给其他初学者参考。
我看的书是像计算机科学家一样思考Python,看起来B格很高,但其实非常好入门,并没有很理论(大概名字高级好卖一点 )。
安装好python3,设好环境变量后,在命令行敲个python就可以进入码代码的模式了。新的语言自然是从Hello World开始
>>> print('Hello,World!') #输出Hello,World!
这个程序体现了三个信息。
Then Py还可以做一些类似计算器的工作(从此不用电脑的计算器
>>> 2 * 3 ** 354>>> qwq = 9>>> qwq / 33.0>>> qwq // 24
我们可以发现我们输入一个表达式,会求出最终值给我们。这里的**是指数运算的意思,//是向下整除法。其他运算基本就是c语言了。(我学过c,c++。所以跟c,c++相似的就不赘余了
赋值,变量名称要求和c语言一样。表达式和语句的区分:
>>> n = 10 #语句>>> n + 4 #表达式14
语句通常没有值,表达式有最终值。
前面这些都是interactive mode下运行python,也就是一行一行地在命令行写并执行。还可以在文件里写,也就是script mode。两者区别就是表达式在script mode下不会输出他的值,想输出要print()。
字符串操作,有两个,+ 和 *。+ 就是拼接。*就是重复字符串几次(必须 * 整数。>>> 'Mr'+'chen116''Mrchen116'>>> 'BBZ' * 4'BBZBBZBBZBBZ'
代码说话
>>> type('454')>>> type(5.5) >>> int('49')49>>> float('23.8')23.8>>> int(-16.7)-16
type()输出参数的类型,类型转换则c++类似,int(),str(),float(),三者可以相互转。
要用数学函数就要有数学的模块(module)>>> import math>>> math>>> math.sqrt(49)7.0>>> math.sin(math.pi/6) #弧度制,瞧他还有浮点误差0.49999999999999994
可以看到math是一个module object。用’.'可以使用module object里面的变量和函数。值得注意的是,三角函数用的是弧度制,而不是角度。
写函数~
>>> def print3(mySTR):... print(mySTR*3)...>>> print3 #可见定义其实就是创建函数对象,但是不直接执行函数体的语句。>>> print3('您好~')您好~您好~您好~
Py中函数def定义函数,括号内是参数,然后:后面就是函数体,函数体用缩进来表示,相当于c的{ }。后面就可以调用这个函数了。
然后形参跟实参的关系跟c类似啦,但由于形参的类型并没有固定,所以会跟随实参的类型。然后函数里面的变量包括形参都是局部变量啦~ 这里的函数是无返回值的,如果强行用它的值,会发现他是None。不是字符串,而是None type的。>>> res = print3('~')~~~>>> print(res)None>>> type(res)
这一章比较好玩,用来熟悉语法。这一章就开始用script mode了,也就是搞个IDE玩。
介绍第二个module:turtle,用来画图。就是一只乌龟,走到哪,哪就留下一条边。
import turtlebob = turtle.Turtle()
运行这个代码就会弹出白窗口,箭头就是小乌龟了!这里bob就是一个Turtle对象了,也可以做很多个Turtle对象,也就是会出现很多个箭头。
下面是对?的一些操作:
bob.fd(10) #向前走10pxbob.lt(90) #左转90度bob.rt(60) #右转60度
然后我就用这个做了方形,圆形,菊花。。。
import turtleimport mathbob = turtle.Turtle()qq= turtle.Turtle()def polygon(t,r): '''plot半径为r圆形''' n=r len = 2*r*math.pi/n for i in range(n): t.fd(len) t.lt(360/n)def arc(t,r,angle): '''plot半径为r角度为angle的圆弧''' n=r len = 2*r*math.pi/n for i in range(int(angle/360*n)): t.fd(len) t.lt(360/n)def petal(t,len,angle): '''plot长度为len展角为angle的花瓣''' r=int(len/math.sin(angle/180*math.pi/2)) arc(t,r,angle) t.lt(180-angle) arc(t,r,angle)def flower(t,num_petal,len): '''plot num_petal个长度为len花瓣的花朵''' angle=int(360/num_petal) for i in range(num_petal): petal(t,len,angle) t.lt(180)def square(t,len): '''plot方形''' for i in range(4): t.fd(len) t.lt(90)square(qq,30)flower(bob,12,150)#while 1:# i = input()# if i == 'a':# bob.lt(90)# elif i=='d':# bob.rt(90)# elif i=='w':# bob.fd(10)# elif i=='s':# bob.rt(180)# bob.fd(10)
上面的三点,是多行字符串的意思,也就是可以保存换行
mySTR = '''Hello World''' print(mySTR)
逻辑操作符: and or not 即与或非啦~
条件i = 24if i > 0: print('qwq')elif i < 0: print('QAQ')else: print('GB')
递归
def print_num(n): print(n) if n > 0: print_num(n-1)print_num(8)
输入 input() 函数,参数可有可无,为输入提示信息。
ans_me = input("What's your problem?\n") #字符串有'用双引号,\n是换行print("This's your problem. " + ans_me)
就是加个return 啦~
由于函数参数并没有限定,而很多时候需要指定类型的参数,就可以用到一个判断类型是否为某类型的函数isinstance(),返回类型是bool。>>> b = 6>>> c = 'v'>>> isinstance(c,str)True>>> isinstance(b,str)False>>> isinstance(b,int)True
用一个平方根,介绍一下while,break的用法。这里用牛顿迭代法做一个开平方跟熟悉这两个语句。
a = float(input())x = aepsilon = 1e-6while True: print(x) y = (x + a/x) / 2 if abs(y-x) < epsilon: break x = yprint(x)
我学到这就开始有点无聊了
字符串就非常好玩了~~~
>>> fruit = 'apple'>>> type(fruit[0])>>> fruit[-1]'e'>>> len(fruit)5
字符串就是字符序列,于是我就好奇那里面的单个字符是什么类型呢?结果是仍然是str。同时Py中下标也是从0开始。因缺思汀的是负整数同为合法的下标,从右往左编号,第一个是-1。len函数就是字符的个数。
切片:
>>> fruit[0:3] #冒号前后表示一个区间,包含左边的,但不包含右边的,因此没有'l''app'>>> fruit[:3] #省略第一个,就是从头开始'app'>>> fruit[2:] #省略第二个,就是到结尾'ple'>>> fruit[4:0] #第二个≥第一个,就会是空串''
for循环遍历
>>> for cha in fruit:... print(cha)...apple
特殊:字符串不能改变里面某一个字符
>>> fruit[1] = 4Traceback (most recent call last): File "", line 1, in TypeError: 'str' object does not support item assignment
表明str作为一个object,是一个整体,而里面字符只是一个item。
字符串方法
>>> fruit.lower() #返回字母都变为小写'apple'>>> fruit.upper() #变成大写'APPLE'>>> fruit.find('pl') #查找字符串在原串中的首位置2>>> fruit.find('p',2) #接受第二个参数,为开始查找的位置2>>> fruit.islower() #返回是否全为小写字母,同样还有isupper()True>>> fruit.capitalize() #若第一个字符是字母,则将其变成大写;其他字母变小写'Apple'
布尔操作符in
返回第一个str是不是第二个的子串。
>>> 'pl' in fruitTrue>>> 'awp' in fruitFalse
于是就可以写出这种类似英文的代码,找出两个串中相同的字符。
def in_both(word1,word2): for letter in word1: if letter in word2: print(letter)in_both('What','the')
代码说话
fin = open('Py1.py') #读入文件的方法,返回一个file for line in fin: #逐行读入 print(line.strip()) #strip()方法是去除行首末的指定字符,未指定则默认空格和换行
逐行读取还有一个函数
fin.readline()
列表一般用方括号括起来
>>> li = ['xixi', 2.5, 6, [4, 7]] #列表可以存各种类型>>>> li[0] = 'haha' #这是合法的>>>> 6 in liTrue>>> li + li[-1]['haha', 2.5, 6, [4, 7], 4, 7]>>> li[2:4][6, [4, 7]]>>> li[2:4][6, [4, 7]]
可以看到列表还可以嵌套,而且列表元素是可变的。而且可以用in操作符。遍历方法同str差不多,都可以用遍历元素或遍历下标。同样的,列表有加法和乘法,与str一样的用法。切片的用法也一样。
列表方法: 见注释>>> li.append('DIAO') # 添加一个元素>>> li['haha', 2.5, 6, [4, 7], 4, 7, 'DIAO']>>> li.extend(['Q','E']) # 添加列表所有元素到里面>>> li['haha', 2.5, 6, [4, 7], 4, 7, 'DIAO', 'Q', 'E']>>> bb = ['a','E','c','1','A']>>> bb.sort() # 对列表内元素排序,无返回值>>> bb['1', 'A', 'E', 'a', 'c']>>> bb.pop() # 删除最后一个元素,同时返回它!'c'>>> bb.pop(0) # 删除下标是0的元素,并将其返回'1'>>> del bb[0] # 若不需要其值,可以直接del>>> bb['E', 'a']
列表和字符串
>>> STR = 'split me'>>> li = list(STR) # 把字符串分成单个字符的列表>>> li['s', 'p', 'l', 'i', 't', ' ', 'm', 'e']>>> t = STR.split() # 此方法可按空格分开>>> t['split', 'me']>>> STR = 'Go!Euler!Oh!'>>> STR.split('!') # 同样可按你要求的分隔符['Go', 'Euler', 'Oh', '']
对象和值
来一段诡异的代码:
>>> s = 'are'>>> b = 'are'>>> s is bTrue>>> l1 = [1,2,3]>>> l2 = [1,2,3]>>> l1 is l2False
这里显示出s和b是同一个字符串的引用,而l1,l2不是同一个对象,只是值相同。有没有想起str不能改变,而list可以改变这个特性!?相信你知道了!
别名 理解了上面那个,看这个就更加诡异了~>>> a = [1,2,3]>>> b = a>>> a is bTrue>>> b[0] = 6>>> a[6, 2, 3]
刚说完不同,这又来了个True,这证明b只是a的别名。当我改变b的时候,a也改变了。
列表参数def del_head(li): del li[0]t = [1,2,3]del_head(t)print(t) # [2, 3]
当以列表为函数参数时,传的是引用,即改变形参,会影响实参的值
然鹅。。。def del_head(li): li = li[1:]t = [1,2,3]del_head(t)print(t) # [1, 2, 3]
这又是为什么呢?因为切片时其实新建了一个新的列表,所以最后li已经不是实参的引用了。同样,下面的加法也创造了一个新list。
def add_end(li): li = li + [7]t = [1,2,3]add_end(t)print(t) # [1, 2, 3]
字典就是映射。犹如c++ STL中的map一样,下标可以是任意类型。(回顾一下,下标->键,另外一个是值
>>> di = dict() # 创建空字典>>> di['one'] = 1 # 添加key-value pair>>> di['two'] = 2>>> di{ 'one': 1, 'two': 2}>>> di['one'] # 查找某个值1>>> di['four'] # 若没有就ErrorTraceback (most recent call last): File "", line 1, in KeyError: 'four'
与STL map不同,Py的dict是用hashtable的方式存的。具体后面再谈。下面用统计单词的各个字符出现的次数的函数来进一步熟悉dict。
def func(s): d = dict() for c in s: if c in d: # 判断一个键是否在字典中 d[c] += 1 else: d[c] = 1 return dmyS = 'Tencent'di =func(myS)for x in sorted(di): # sorted函数会把di的键进行排序,返回值是一个键的list print(x,di[x])
dict还有一个方法get(),接受一个键和一个默认值,若找不到对应键就返回默认值,所以上面的func() 也可以这么写
def func(s): d = dict() for c in s: d[c] = d.get(c,0)+1 return d
反向遍历,实际上并没有太好的方法。
def reverse_lookup(d, v): for k in d: if d[k] == v: return k raise LookupError('value does not appear in the dictionary!')di = { 'a':1,'b':2,'c':3}print(reverse_lookup(di,2))
这里有个新语句raise,它会产生一个异常,这要生成的异常是LookupError 这是一个内置异常。那个描述错误细节的参数是可选的。当找不到对应value是程序就会输出
Traceback (most recent call last): File "", line 1, in File " ", line 5, in reverse_lookupLookupError: value does not appear in the dictionary!
字典与列表
列表可以是字典的一个值,下面举一个反转字典的例子。def invert_dict(d): inverse =dict() for key in d: val = d[key] if val not in inverse: inverse[val] = [key] else: inverse[val].append(key) return inversedi = { 'a':1,'b':2,'c':1}print(invert_dict(di))
输出为{1: ['a', 'c'], 2: ['b']}
。但是列表并不能作为字典的键,毕竟列表无法hash,而且它是可变的。从而你也可以猜到字典也是无法作为键的,因为它也是可变的。
并不懂作者为什么放全局变量在字典这一章,可能没地方放吧
在函数内若未声明全局变量,仍然可以使用它的值:
c = '乌里妈查'def p(): print(c) # 正确p()
然而,你想改变它的值,那就不行了:
c = '乌里妈查'def p(): c = 'M . M'p()
因为Py会默认c是新建的一个局部变量,并不会改变全局变量的值。基于此,下面这段代码就会报错了,因为局部变量c压根还没定义。
c = '乌里妈查'def p(): c = c + '!' # 错误p()
所以当我们要在函数内修改全局变量的值时,就要声明,告诉编译器这是全局变量,不要给我新建一个局部变量!
c = '乌里妈查'def p(): global c c = c + '!'p()
但是,若全局变量是可变的值,你也可以不用声明就修改它。所以可以添加、删除和替换一个全局的列表或字典的元素。
d = { 0:'a',8:'w'}def p(): d[2] = 'Q'p()print(d)
但是,要想给全局变量重新赋值,则需要声明啦~
d = { 0:'a',8:'w'}def p(): global d # 必须声明 d = dict()p()print(d)
这样听起来会特别乱。概括起来就是全局变量不声明时,可以作为右值访问,不能整个对象作为左值,而要是全局变量是可变的,就可以改变其值,但仍然不能作为左值进行重新赋值。
元组各方面跟列表差不多,但是元组是不可变的!创建元组的几种方式如下:
t = 'a','b','c't = ('a','b','c')t = tuple('abc')
上面三种都是等价的。tuple()不带参数是新建空元组,参数是序列(str,list,tuple)就会生成包含序列的元素的元组。
Py序列比较大小,从第一个元素开始,逐个比较到不同元素为止。
>>> (0,1,123)<(0,3,-9)True
优雅地交换两个变量的值
b,a = a,b
魔性吧!左边是变量的元组,右边是表达式的元组。每个值会一一对应。但是左右必须变量个数相同,不然就Value Error了。更一般的,右边可以是任何序列。
address = 'Mr.chen@qq.com'name,domain = address.split('@') # 返回list
上面的代码就可以把用户名和域名分开了。
遍历元组列表
t = [(1,11),(2,22),(3,33)]for index,value in t: print(index,value)
严格说,函数只能返回一个值。但这个返回值可以是元组,那就跟返回多个值差不多了。内置函数divmod()就是返回了(商,余数)这个元组。
divmod(11,3)(3, 2)
你也可以用return a,b,c
来写自己的函数。
函数可以接受不定个参数。只要形参前面加个*,所有参数都会 收集(gather)到这个元组上,反操作是分散(scatter),在调用形参不是接受元组,而是接受多个参数时,在实参元组前面加*。
def print_all(*arg): print(arg)tu = 11,3print_all(tu)print(divmod(*tu))
结果是:
((11, 3),)(3, 2)
下面介绍一下,内置函数中哪些是接受可变长元组,哪些是不接受
max(1,2,4,6) #正确min(1,2,4,6) #正确sum(1,2,4,6) #错误
zip() 接受两个或多个序列,并返回一个元组列表。每个元组包含一个元素,就像拉链一样把各个序列里的元素对应起来。例如:
s = { 2:4,3:9,4:64}t = [5,6,7,8]q = "What???"tmp = zip(s,t,q)print('tmp:',tmp)for e3 in tmp: print(e3)print('list(tmp): ',list(tmp))print('zip(s,t,q): ',list(zip(s,t,q)))
输出
tmp:(2, 5, 'W')(3, 6, 'h')(4, 7, 'a')list(tmp): []zip(s,t,q): [(2, 5, 'W'), (3, 6, 'h'), (4, 7, 'a')]
这反映的几个特性
zip和for组合起来就可以同时遍历多个序列。例如寻找是否有s1[i] == s2[i] 的程序
def has_match(s1,s2): for a,b in zip(s1,s2): if a == b: return True return False
这章主要在于如何灵活地应用各种Py核心数据结构。
这里用到了string module的whitespace(空白字符串),punctuation(所有标点符号)。
import stringfin = open("text.txt")out = ""for line in fin: for char in line: if char in string.punctuation+string.whitespace: out+=' '; else: out+=char.lower(); out+='\n'outlist=out.split()print(outlist)
用这个去扒书统计还是很有意思的。
import stringfin = open("text.txt")out = ""for line in fin: for char in line: if char.isalpha(): out+=char.lower(); else: out+=' '; out+='\n'outlist=out.split()dic = dict()for word in outlist: dic[word] = dic.get(word,0)+1moreThan20Word = dict()for word in dic: if dic[word] >= 20: moreThan20Word[word] = dic[word]print(moreThan20Word)
然而看了标程后,羞愧不已。
import stringdef process_file(filename): hist = dict() fp = open(filename) for line in fp: process_line(line,hist) return histdef process_line(line,hist): line = line.replace('-',' ') for word in line.split(): word = word.strip(string.whitespace+string.punctuation) word = word.lower() hist[word] = hist.get(word,0)+1hist = process_file("text.txt")
转载地址:http://mwuzi.baihongyu.com/