Py日记(python零起步

谨以此blog记录我的python学习之路和给其他初学者参考。

我看的书是像计算机科学家一样思考Python,看起来B格很高,但其实非常好入门,并没有很理论(大概名字高级好卖一点 )

一、程序之路

安装好python3,设好环境变量后,在命令行敲个python就可以进入码代码的模式了。新的语言自然是从Hello World开始

>>> print('Hello,World!') #输出Hello,World!

这个程序体现了三个信息。

  • print()是输出啦~
  • #后面是注释啦~
  • 字符串可以用单引号括起来~(也可以用双引号)

Then Py还可以做一些类似计算器的工作(从此不用电脑的计算器

>>> 2 * 3 ** 3
54
>>> qwq = 9
>>> qwq / 3
3.0
>>> qwq // 2
4

我们可以发现我们输入一个表达式,会求出最终值给我们。这里的**是指数运算的意思,//是向下整除法。其他运算基本就是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')
<class 'str'>
>>> type(5.5)
<class 'float'>
>>> int('49')
49
>>> float('23.8')
23.8
>>> int(-16.7)
-16

type()输出参数的类型,类型转换则c++类似,int(),str(),float(),三者可以相互转。
要用数学函数就要有数学的模块(module)

>>> import math
>>> math
<module 'math' (built-in)>
>>> math.sqrt(49)
7.0
>>> math.sin(math.pi/6) #弧度制,瞧他还有浮点误差
0.49999999999999994

可以看到math是一个module object。用’.'可以使用module object里面的变量和函数。值得注意的是,三角函数用的是弧度制,而不是角度。
有了以上的知识,python是一个很好的计算器了

写函数~

>>> def print3(mySTR):
...     print(mySTR*3)
...
>>> print3 #可见定义其实就是创建函数对象,但是不直接执行函数体的语句。
<function print3 at 0x000002684965D1E0>
>>> print3('您好~')
您好~您好~您好~

Py中函数def定义函数,括号内是参数,然后:后面就是函数体,函数体用缩进来表示,相当于c的{ }。后面就可以调用这个函数了。
然后形参跟实参的关系跟c类似啦,但由于形参的类型并没有固定,所以会跟随实参的类型。然后函数里面的变量包括形参都是局部变量啦~
这里的函数是无返回值的,如果强行用它的值,会发现他是None。不是字符串,而是None type的。

>>> res = print3('~')
~~~
>>> print(res)
None
>>> type(res)
<class 'NoneType'>

四、案例研究:接口设计

这一章比较好玩,用来熟悉语法。这一章就开始用script mode了,也就是搞个IDE玩。

介绍第二个module:turtle,用来画图。就是一只乌龟,走到哪,哪就留下一条边。

import turtle
bob = turtle.Turtle()

运行这个代码就会弹出白窗口,箭头就是小乌龟了!这里bob就是一个Turtle对象了,也可以做很多个Turtle对象,也就是会出现很多个箭头。

下面是对?的一些操作:

bob.fd(10) #向前走10px
bob.lt(90) #左转90度
bob.rt(60) #右转60度

然后我就用这个做了方形,圆形,菊花。。。

import turtle
import math
bob = 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 = 24
if 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

七、迭代

用一个平方根,介绍一下whilebreak的用法。这里用牛顿迭代法做一个开平方跟熟悉这两个语句。

a = float(input())
x = a
epsilon = 1e-6
while True:
    print(x)
    y = (x + a/x) / 2
    if abs(y-x) < epsilon:
        break
    x = y
print(x)

我学到这就开始有点无聊了

八、字符串

字符串就非常好玩了~~~

>>> fruit = 'apple'
>>> type(fruit[0])
<class 'str'>
>>> 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)
...
a
p
p
l
e

特殊:字符串不能改变里面某一个字符

>>> fruit[1] = 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
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 fruit
True
>>> 'awp' in fruit
False

于是就可以写出这种类似英文的代码,找出两个串中相同的字符。

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 li
True
>>> 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 b
True
>>> l1 = [1,2,3]
>>> l2 = [1,2,3]
>>> l1 is l2
False

这里显示出s和b是同一个字符串的引用,而l1,l2不是同一个对象,只是值相同。有没有想起str不能改变,而list可以改变这个特性!?相信你知道了!
别名
理解了上面那个,看这个就更加诡异了~

>>> a = [1,2,3]
>>> b = a
>>> a is b
True
>>> 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']         # 若没有就Error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
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 d
myS = '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 "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in reverse_lookup
LookupError: 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 inverse
di = {'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,3
print_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: <zip object at 0x000001FE8ADA3888>
(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函数返回的是一个zip对象
  • zip对象是一种迭代器,跟列表类似,但不能下标访问,而且只能遍历一遍( for里遍历了tmp,所以tmp最后为
  • 元组的个数有len最小的序列决定
  • 元组里元素的顺序由参数顺序决定
  • 要是序列是字典,实际上只用了键,没用值
  • zip对象可以转换成list对象

zipfor组合起来就可以同时遍历多个序列。例如寻找是否有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 string
fin = 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)
统计文件中单词总数以及每个单词使用的次数

用这个去www.gutenberg.org扒书统计还是很有意思的。

import string
fin = 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)+1
moreThan20Word = dict()
for word in dic:
    if dic[word] >= 20:
        moreThan20Word[word] = dic[word]
print(moreThan20Word)

然而看了标程后,羞愧不已。

import string
def process_file(filename):
    hist = dict()
    fp = open(filename)
    for line in fp:
        process_line(line,hist)
    return hist

def 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)+1

hist = process_file("text.txt")
随机数

文件

类和对象

类和函数

类和方法

继承


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值