笨办法学 Python
- 单词符号表、名称、作用
- print:打印;
- “”:双引号,表示引号内的内容是字符串;
- ‘’:单引号,表示引号内的内容是字符串,作用同双引号,区别在于双引号表示长内容,单引号常用于表示短单词;可与双引号配合使用,即在双引号表示的长句子内,用单引号表示某个需要加引号的单词;
- #:井号,表示单行注释
- 井号后面的内容不会被执行
- 多行注释则在每一行开头加井号;
- 注释不一定写在一行的开头,也可以写在一行的末尾;
- 如果被双引号括起来,则此时井号不会被当作注释符,例如:print “Hi, # here.”
- +: 加号
- 数学运算符,对符号两侧的数值做加法运算;
- 还可以用来在print表示字符串变量的拼接,例如print var1 + var2 + var3(如果变量是数值,则此时就会运算了,如果有些是数值,有些是字符串,则会报错)
- -: 减号,同上,减法运算;
- *: 乘号
- 乘法运算;
- 还可以用来表示多次重复打印某个字符串,例如print “string” * 10(将string连续打印10遍);
- /,斜杠,同上,除法运算;
- %,百分号,同上,求余数运算;
- <,小于号
- />,大于号
- <=,小于等于号
- />=,大于等于号
- =
- 等于号,赋值;
- 可以这样用:a, b, c = 1, 2, 3(在一行中一次性将3个值赋值给3个变量)
- 这样做有一个意想不到的好处,示例: a, b = b, a+b(即在 a 改变数值前,将 a 原来的值用于运算得到新的 b 值)
- . 点
- 可用来表示浮点数
- 使用函数,示例:file.read()
- ==,双等号,用来判断两个值是否相同;
- %s
- 将字符串类型的变量带到字符串中
- 当变量是数值类型时,运行不会报错,仍然能够正常输出;(猜测可能将数值转成了字符串?)
- %d
- 将数值类型的变量带到字符串中;
- 当变量值是字符串时,运行会报错,提示需要数值类型,而非字符串类型;
- %r
- 将任何类型的变量带到字符串中(不管什么都打印出来,只有在想获取某些东西的调试信息时使用,正常应该使用%s)(%r用于调试,%s用于显示)
- %r 用来输出原始格式,debug时使用比较好,平时用%s;使用%r会使得字符串中的“\n”换行符失效;
- %:百分号
- 可在字符串中实现对变量的引用,经测试不能用来在字符串中做运算,但可以做好运算再引用到字符串中;
- ( ):括号
- 在字符串中引用变量时,可以用来容纳多个变量,例如 % (var1, var2)
- 和函数一起使用,括号内可放函数的参数,多个参数之间用逗号隔开;
- , 逗号
- 在字符串中引用变量时,可以用来连接两个变量;变量用逗号隔开,示例:% (var1, var2)
- 在print中,可以用来表示连接两个变量,输出时两个变量会在同一行,逗号会变成空格,例如print var1, var2(输出结果为var1 var2,如果没有逗号,会报错)(此处如果使用+加号,则表示将变量的字符串拼接在一起,中间没有空格)
- print打印自带换行,有逗号则不会换行;即如果在print后面加逗号,则print结束后,不会输出换行符跑到下一行,例如 print var1,
- 浮点数:通过在小数点后面加零实现(好奇,如果需要的小数位数比较多的话,每次输入岂不是很麻烦?貌似可以通过设定变量来解决)
- 函数round()可以实现四舍五入,例如:round(1.73333)
- 运算优先级:括号>指数>乘>除>加>减
- _ :下划线:常在变量命名时用来连接单词,意指空格,函数的命名也是使用下划线,类的命名则使用驼峰大写
- False,开头字母大写时,是一个布尔值;类似的还有True;输出这两个值的时候,不需要加引号,它们是python的关键字;
- 使用%r的时候,\n 就不灵了,因为%r会输出原始格式,例如:print “Hi %r here.” % Mon\nFeb
- “”” 或者 ‘’’,三个连续的双引号或者三个单引号,用来表示段落字符串;
- \n:换行;类似的还有\t(水平制表符),\v(垂直制表符),\r(回车符);
- \: 反斜杠,转义符,用来输入一些做为关键字符的符号本身;
- raw_input():
- 获得用户在控制台的输入信息;
- raw_input和input:
- 通过读取控制台的输入,实现与用户的交互;
- 二者的差别在于前者可以读取任何输入,后者希望读取一个合法的输入(合乎python的语法),例如字符串需要用引号括起来(会被当作代码处理,应该避开使用这个函数);
- raw_input()的括号里面可以放提示;
- from sys import argv:
- 从 sys 引入 argv 模块(全称:argument variable,参数变量;模块有一些特性,可以方便的产生一些作用;argv 的特性是会保存运行python脚本时传递给 python 脚本的参数
- 如果有多个参数传递给脚本,在引用argv模块后,需要将argv解包,并将参数依次赋值给相应的变量
- import 导入的参数会当作字符串来解包并赋值给相应的变量
- open(filename):
- 作用:打开文件,括号内的参数为要打开的文件的文件名;
- open返回的是文件对象本身,不是文件内容,可在这个对象中找出想要的内容;
- open(filename, ‘w’):第二个参数 w 的意思是以写入模式打开,此种模式允许对文件进行写入;如果是 r 参数,则是只读模式;a 参数(append)表示追加模式;
- w+, r+, a+:将文件以同时读写的方式打开,不同符号实现在文件内的不同定位;
- read():
- 作用:读取文件,可将结果赋值给一个变量,示例:txt = open(filename).read();
- read()一旦运行,文件会被python关掉,可以无需再运行open(filename).close();
- close():关闭一个文件,示例:open(filename).close();
- readline():
- 读取文件中的一行,示例open(filename).readline(3);
- 读完之后,会将“磁头”(游标)移动到该行的换行符”\n”后面;
- readline()会扫描文件,直至找到一个\n,然后返回前面的内容,同时停止在那个位置,位置信息记录在相应的文件中;下次再调用readline()时,会接着从停止的位置接着往下扫描;
- readlines() 会一次性将整个文件读入内存,而 readline() 一次只读一行,前者处理速度更快,但对内存大小有要求,后者则适合当文件超过内存大小时使用;
- truncate():清空文件,小心使用;
- write(stuff):将stuff写入文件中,示例open(filename).write(stuff);stuff如果是字符串,可以使用+将多个字符串连接起来(包括转义符)同时写入,示例:write(var1+”\n”+var2+”\n”)
- CTRL^C:可以在脚本运行的过程中途退出,一种方法是使用raw_input()来获得用户的这个指令;
- from oa.path import exists:exists(filename)可以用来判断filename文件是否存在,如果存在返回True,如果不存在,返回False;
- len(string):获得string字符串的长度,返回长度数值;示例:len(open(filename).read())
- def:
- 定义一个函数(或者叫创建一个函数);示例:def print_two(arg1, arg2);
- 函数里面的变量,和脚本里面的变量,是没有联系的;(目测在js里面叫做词法作用域?)
- 函数可以返回某些东西;也可以不返回值(此点跟 js 不一样, js 如果没有指定返回值,会返回undefined值)(后来发现一样,没有指定返回值,会返回none)
- *argv:可以用来接收多个参数,之后再解包依次赋值给变量,示例:def print_two(*argv);
- 函数的参数支持:单独的变量,数字与变量的运算、数字与数字的运算(如果参数是数值类型的话)、变量与变量的运算;
- seek():
- 作用:操作文件游标移动
- 示例:f.seek(0)
- 参数0表示从头,参数1表示从当前,参数2表示从末尾;
# -*- coding: utf-8 -*-:转成utf-8编码,可以直接写成 #coding: utf-8,不知为什么作者写得那么复杂,为了好看?
- 使用%s和%d,在字符串引用参数时,可以在语句后面直接写上参数名,也可以由函数返回参数值;示例:
- print “%s, %d, %d” % function(var),
- def function(var)
- {return var1, var2, var3)}
- from ex25 import *:将ex25文件里面的模块全部导出来,省得每次调用函数的时候老是需要写前缀“ex25.”;
- help(ex25):用来显示ex25里面的帮助文档,或者叫“文档注释”;文档注释是这么写的
- def function(var)
- “””这里是文档注释,用三个双引号括起来”””
- def function(var)
- 还可以这样:help(ex25.function1),只显示其中某个函数的注释;
- 布尔表达式
- and:从左到右找False,找到后返回False,找不到返回True;
- or:从左到右找True,找到后返回True,找不到返回False;
- 布尔表达式返回:按规则寻找,有找到时,按规则返回;没找到时,返回两个操作对象中后面的那个
- “test” and 1:返回1;
- 1 and “test”,返回test
- 1 and False:返回False;
- False and 1:返回False;
- 1 and True:返回True;
- Ture and 1:返回1;
- 1 or False:返回1;
- False or 1:返回1;
- 1 or True:返回1
- Ture or 1:返回True
- +=:此符号可以用来表示递增,用法示例:x += 2,表示:x = x + 2;类似的有 x -= 2, x *= 2;x /= 2;
- print i += 1是不可接受的,会报错;需要这样子:i += 1, print i;另外,print i + 1,是允许的(目测在print语句中不能使用等号=来给变量赋值)
- if 语句首先以冒号结束,接下来需要4个空格的缩进(经测试发现1个以上的空格就可以),如果不缩进,程序会报错;
- if, elif, else:组成段落后,python只会运行它遇到的第1个是True的块;
- 列表list:
- 一个按顺序存放东西的容器;以方括号[]开头和结束,中间的东西用逗号隔开;可以用等号=赋值给一个变量;
- list.append(i):在列表的尾部追加元素i;使用示例:list.append(i);
- list[-1]:获取倒数第一个元素;list[-2]:获取列表中倒数第2个元素;
- range(x, y):x和y需要是整数;如果x是以零开头,则可以简写成range(y);
- range()函数的返回值是一个列表,因此可以写成:elements = range(0, 6),它的意思等同于 elements = [], for i in range(0, 6), elements.append(i);
- 目测列表才有pop属性,字符串好像没有,因为使用string.pop会报错,提示无此属性;
- 字符串的操作
- replace
- 用法:用来将字符串的旧字符替换为新字符,并且可以指定最大替换条目(次数)(可选参数),返回替换后的新字符串
- 示例:
- str_A.replace(old_str, new_str)
- str_B.replace(old_str, new_str,5)
- replace
- 列表有很多操作,如下:
- add
- contains
- deitem
- delslice
- setitem
- setslice
- eq
- ge
- getattribute
- getitem
- getslice
- gt
- iadd
- lt
- sizeof
- reversed
- imul
- pop:
- pop( ):如果括号内没有数字,表示删除最后一个元素,并返回该元素
- pop(n),删除列表中位置为 n 的元素,并返回该元素 ;
- remove:
- 删除指定值的元素
- 例如: list = [1, 2, 3, 8, 9],则 list.remove(8) 之后,list 为 [1, 2, 3, 9]
- del
- 删除指定位置的元素
- 例如: list = [1, 2, 3, 8, 9],则 del li[2] 之后, list 为 [1, 2, 8, 9]
- reverse
- extend
- 用法:给当前列表在尾部追加另外一个列表的所有元素,另外一个列表做为 extend 函数的参数,参数必须是列表类型
- 示例:list_A.extend(list_B)
- append
- 用法:给当前列表在尾部增加一个元素,需要添加的元素做为 append 函数的参数,参数可以是任意类型
- 示例:list_A.append(var_B)
- sort
- insert
- index
- 列表和数组从经典意义上理解是不同的,因为它们的实现方式不同;不同的语言中称呼不同,ruby 和 js 中叫做数组,python 中叫做列表;
- for i in range()::循环开始的时候,定义了变量i;每次循环的时候,它会被重新定义一次;
- for i in range(1, 3):只会循环2次,而不是3次;从第1个数开始,但不包括最后一个数;
- 一行语句只要以冒号:结尾,下一行就需要缩进,不然会报错,例如函数和if语句;冒号的作用是告诉python接下来会创建一个新的代码块;if, elif, else, 函数等都是强制缩进的,首行以冒号结束
- while循环的规则
- 尽量少用while循环,大部分情况for循环是更好的选择;
- 重复检查while语句,确保测试的布尔表达式最终会变成False;
- 如果不确定,就在while循环的结尾打印出要测试的值。看看它的变化 ;
- 对于 while a != b 这种情况,目测好像 while 循环比 for 循环更好用一些;
- raw_input()抓取的东西是字符串,即使录入数字也会当做字符串对待,因此需要使用int(raw_input())将输入转化成数字;
- for i in range(0, x):i会在运行的过程中递增;
- 如果多个elif块都是True,python只会运行它遇到的第一个值为True的块,余下忽略不运行;
- 序数:用某种规则进行排列的数的集合;
- 基数:每个数有一个索引,对应一个地址,可以通过这个地址快速找到某个数;
- while True可以创建一个无限的循环;
- exit(0)可以中断某个程序,正常退出;exit(1)表示发生了错误;
- if 语句的规则
- 每一条 if 语句必须包含一个else;
- 如果这个 else 永远都不应该被执行到,那就必须在else语句后面使用 die 函数,让它打印出错误信息并且死给你看,这样可以找到很多错误;
- if 语句的嵌套不要超过两层,尽量保持一层;如果if里面要再嵌套一个 if,考虑将第二个if弄到一个函数里;
- 将 if 语句做为段落对待,即段落前面空一行,结束后空一行,有利于阅读,知道从哪里开始,到哪里结束;
- 布尔测试应该很简单,如果很复杂,则将它们的运算先放到一个变量里,给变量取个好名字(会更容易阅读,避免阅读的时候,还要做运算,因为此时大脑在思考逻辑);
- 循环的规则
- 只有在循环永不结束的时候使用while(显示这不可能,所以尽量别用while)
- 其他循环使用for;
- 调试的技巧
- 别用debugger:因为输出太多,干扰阅读
- 使用print:打印出关键变量,判断程序是否如期运行;
- 写一点,运行一点,再修改一点;不要等一个很长的脚本写完后再运行它;
- 关键字
- and
- 与运算符,用来做逻辑运算;
- 判断规则:从左往右寻找False,找到即返回,找不到返回True
- del
- 对列表进行元素的删除操作
- 示例,假设a = [8, ‘ss’, ‘kk’, 20]
- del a[0]:表示删除列表a的第1个元素;
- del a[1:3]:表示删除列表的第2到4个元素;
- del a #:表示删除整个列表,a会完全消失,跟没定义过一样;
- from
- 引入模块时使用,示例:from sys import argv
- from aa import bb与 import bb的区别
- 后者使用的时候需要写成:aa.bb(),前者不用,直接写 bb(),相当于把路径提前告知了;
- 如果不存在两个模块的重名问题,则可以写:from aa import *
- 如果存在重名问题,则只能写 import bb,然后使用的时候写:aa.bb(), 或者 cc.bb()
- not
- 非,逻辑运算符,将False变成True,反之亦然;
- while
- 循环,如果条件为True,运行代码块;运行后再回到开头位置,再判断条件,如果为True,再次运行代码块;直至条件变为False为止;
- as
- 跟with配套使用,示例:with aa as bb,意思是:执行aa对象的enter方法,将返回值赋值给bb,并执行aa对象的exit方法,结束;
- 作用类同于try…finally…
- elif
- 条件判断,跟if一起配套使用
- 常见句式:if…: elif…: else:
- global
- 用来说明变量是全局的,以便在函数内部使用
- 示例:
- x = 50
- def func():
- global x
- x = x * 2
- print x
- 如果要指定多个,可以这样:global x, y, z
- or
- 或,逻辑运算符
- 规则:从左到右寻找 True,找到即返回,找不到返回 False;
- with
- 跟 as 配套使用,with aa as bb,作用类同于 try…finallly…,执行 aa,将返回值赋值给 bb
- assert
- 用来将调试断点插入到程序中
- 示例:assert expression(表达式)
- 示例1:assert n>=2
- 示例2:assert expression1, expression2
- assert 5 > 3, print “肯定是错的”2
- assert 0 > 3, print “肯定是对的”
- 作用类似于:if not expression: raise AssertionError
- else
- 条件语句,跟 if 配套使用
- if
- 条件语句,跟else,elif(如需)配套使用
- 只会执行遇到的条件为 True 的代码块;
- pass
- 空操作:它是一个语句,这一点很重要,但同时告诉程序什么都不用做,往下走即可。如果没有它,有可能程序语法不完整导致报错
- 它可以用来放置在一些没有想好怎么写的位置,类似于先占个位子;
- yield
- 这个不简单,带有yield的函数有两个作用
- 生成器,每次调用的时候返回一个生成器对象,好处是内存占用小,因为使用迭代的方式来获得返回值,内存开销是一个固定值
- 例如生成斐波数列,如果上限很大,且使用列表的方式,会导致保存列表的内存占用很大;此时使用yield的好处是每次调用只返回一值,通过重复调用来获得完整的数列;
- 另外也可用于文件的读取,目的也是减少内存开销;
- 生成器,每次调用的时候返回一个生成器对象,好处是内存占用小,因为使用迭代的方式来获得返回值,内存开销是一个固定值
- 这个不简单,带有yield的函数有两个作用
- break
- 立即结束循环并退出,之后的代码不会被执行
- except
- 用来处理异常,常与try配合使用;当try里面的代码块被执行后,有可能引发异常,此时如果有except语句,则程序会跳到第一个except语句,判断异常是否符合语句表达的条件,如果符合,则执行except下的代码块,如果不符合,则寻找下一个except语句;如果找完全部没找到,貌似会调用python的l默认处理器,自动终止程序退出;有except处理则不会自动终止退出;
- import
- import用来导入模块,模块包含一些类和函数,可以实现某些功能;当我们需要这些功能的时候,就使用import来导入
- 模块
- 模块是包含函数和变量的 python 文件
- 可以导入这个文件
- 然后可以使用 . 操作符访问模块中的函数和变量
- print
- 用来输出内容,包括整数、16进制数、8进制数、浮点数、字符串、列表等
- class
- 用来定义类
- 什么是类:用来快速的创建对象,制造对象的工厂
- 类支持两种操作
- 一种是引用,即访问类中的属性;
- 一种是实例化,即通过类创建对象;
- exec
- 用来执行存储在字符串或文件中的python语句,例如 exec “print ‘Hello World’”
- in
- 可用来判断一个元素是否在列表里面,示例:if a in list
- raise
- 可以用来引发一个异常
- continue
- 用来跳出当次循环,但继续执行后续的循环
- 与break的区别:break跳出当次循环后,不再执行后续的循环,直接退出了
- finally
- 与 try 配合使用,执行完 try 的代码块后,继续执行 finally 的代码块,不管 try 是否抛出异常;
- 与 try…except…相冲突,二者只能用其一;
- finally 的代码块必会被执行,但 except 不一定,如果 try 没有抛出异常, except 的代码块不会被执行
- is
- 用来判断A对象是否是B对象,即它本人;对象有3个属性,分别是 id, type, value,is 的原理是判断两个对象的 id 是否相同
- == 用来判断两个对象的值是否相等;
- return
- 用在函数中的返回,可以选择性的返回一个值;
- 如果没有指定返回值,函数会默认返回None
- 如果没有写 return 语句,函数其实会默认执行一条 return None 的语句
- def
- 用来创建函数
- for
- 用来创建循环,它可以遍历一个序列中的所有项目
- 示例:for i in range(0, 6)
- lambda
- 用来创建一个匿名函数,示例:g = lambda x: x +1(类同于,def g(x): x+1)
- 好处:没有像普通 def 创建函数一样生成栈,更快更简洁,提高性能(不需多次调用的情况下)
- 语法:支持多个参数,示例:g = lambda x, y: x + y(冒号左边是参数,右边是返回值)
- try
- 主要用来处理异常,有两种风格
- try…except…else…
- 如果 try 发生异常,并没有匹配到 except,则会将异常抛给上一层 try (如果上一层 try 也法匹配呢?猜测要触发自动处理机制了)
- except: 捕获所有异常
- except name: 只捕获名字为 name 的特定异常;
- except name, value: 捕获异常,并获得它的附加数据
- except (name1, name2, … ):捕获多个异常
- else: 如果没有发生异常
- try…finally…
- try…except…else…
- 主要用来处理异常,有两种风格
- and
- 数据类型
- True:布尔值
- False:布尔值
- None:没有值
- strings:字符串,示例:’snow’, ‘winter’
- numbers:数字,示例:5, 4, 3
- floats:浮点数,示例:1.08
- lists:列表,示例:a = [8, 10, 12, 14, 16]
- 字符串转义序列
- \
- '
- "
- \a:alarm,响铃,会出现一声铃声;
- \b:backspace,退格,会删除一个字符;
- \f:换页符
- \n:换行符
- \r:回车符
- \t:tab,水平制表符
- \v:vertical,垂直制表符
- 字符串格式化
- %d:数字
- %i:据说等同于 %d,只是现在逐步不用了;
- %o:转成无符号八进制数
- %u:转成无符号十进制数
- %x:转成无符号的十六进制数(小写)
- %X:转成无符号的十六进制数(大写)
- %e:转成科学计数法(小写)
- %E:转成科学计数法(大写)
- %f:转成浮点数,示例:%.2f,取两位小数,四舍五入
- %F:转成浮点数,小数部分自然截断
- %g:%e 和 %f 的简写
- %G:%E 和 %F 的简写
- %c:转换成字符(ASCII 码值,或者长度为一的字符串)
- %r:优先用 repr() 进行字符串转换(调试用,会原原本本的输出字符串内容,不识别处理里面的符号)
- %s:转换成字符串
- %%:输出%
- 操作符
- :乘方,示例:24,表示2的4次方
- /:浮点数除法,返回结果为浮点数
- //:整数除法,返回结果为整数
- %
- <
- <=
=
- ==
- !=
- <>
- ( ):元组数据类型
- [ ]:列表数据类型
- { }:字典数据类型
- @:修饰符,据称是为了调用函数用的,暂时不明白具体用法,待后补
- , 逗号
- : 冒号
- . 点
- = 等号
- ; 分号
- += 自增
- -= 自减
- *= 自乘
- /= 自除
- //= (不知道啥意思,莫非是自整除?)
- %= 自求余数
- **= 自平方
- ‘ ‘.join(stuff):python实际执行的动作为 join(‘ ‘, stuff),前者翻译为:用空格 ‘ ‘ 连接 stuff,后者翻译为:为空格 ‘ ‘ 和 stuff 调用 join 函数,二者是一个意思
- dir(object):查看对象 object 内的所有属性和方法;
- 示例: import sys
- dir(sys)
- 示例: import sys
- 字典
- 作用之一:可以通过任何东西(不只是数字)找到元素;
- 字典可以将一个物件和另外一个物件关联,不管它们的类型是什么;这是一种将一种东西对应到另外一种的方式
- 可以通过字符串从字典里面提取东西,也可以通过字符串往字典里面添加东西;
- del 可以将字典里面的东西删除
- 字典的内容是无序的
- dict.get(k, d):如果 k 在 dict 里面,则返回 dict[k]; 如果不在,则返回 d
- dict.keys() :提取字典里面的key组成一个列表返回
- dict.values() :提取字典里面的value组成一个列表返回
- dict.items() : 提取字典里面的(key, value)组成一个元组列表返回;
- 字典与模块差不多
- 相同点:从 Y 获取 X 的概念
- 不同点
- 字典的语法:使用 [键],示例:dict[x](注:对于字典,键是一个字符串)
- 模块的语法:使用点 “.”,示例:module.x(注:对于模块,键是一个函数或者一个变量)
- 类和模块差不多
- 模块的另外一种理解方法:一种特殊的字典,存储一些代码,可以通过点“.”操作符来访问这些代码;Python还有另外一种结构来实现类似的目的,即类,可以把一组函数和数据放到容器中,从而用“.”操作符来访问它们(函数和数据)(类有些类似于迷你模块)
- 使用类而非模块的原因:可以用类重复创建出很多出来,它们之间不会互相干涉;而对于模块,一次导入后,整个程序里面只有一份内容;
- 对象:相当于迷你导入;
- 实例化:如果类和迷你模块差不多,则也会存在一个“导入”的动作,此动作称为“实例化”,名称很高深,其实就是“创建”的意思,实例化后,会得到一个“对象”
- 过程:
- 调用类
- 创建空对象(相当于创建迷你模块,然后导入它)
- 如果有 init() 函数,调用该函数对空对象进行初始化(init 函数里面有一个多余的函数 self,即是 python 创建的空对象,可以对它进行类似模块、字典等操作,为它设置一些变量进去)
- 将初始化后的对象赋值给一个变量
- 接下来可以对变量进行后续操作
- 单词练习
- 类(class):告诉 python 创建新类型的东西(貌似类的起名首字母习惯用大写)
- 对象(object):两个意思,即最基本的东西,或者某个东西的实例;
- 实例(instance):这是让 Python 创建一个对象时得到的东西;
- def:在类里面定义函数的方法
- self:在类的函数里,self 指代被访问的对象或者实例的一个变量;
- 继承(inheritance):指一个类可以继承另一个类的特性,和父子关系类似;
- 组合(composition):指一个类可以将别的类做为它的部件构建起来,有点儿像车子和车轮的关系;
- 属性(attribute):类的一个属性,它来自于组合,而且通常是一个变量;(如果没有组合呢?是否还有属性?)
- 是什么(is-a):用来描述继承关系,如 Salmon is-a Fish;
- 有什么(has-a):用来描述某个东西是由另外一些东西组成的,或者某个东西有某个特征,如 Salmon has-a mouth.
- 语汇练习
- class X(Y):创建一个叫做 X 的类,它是 Y 的一种;(难道有好几种 Y?)
- class X(object):def init(self, J):类X有一个_init_接收 self 和 J 做为参数;
- class X(object):def M(self, J):类X有一个函数名称为M,它接收 self 和 J 做为参数;
- foo = X():将 foo 设为类 X 的一个实例;
- foo.M(J):从 foo 中找到 M 函数, 并使用 self 和 J 参数调用它;
- foo.K = Q:从 foo 中获取 K 属性,并将其设为 Q;
- 类和对象并没有真正的不同,它们其实是同样的对象,只是在不同的时间名字不同罢了。对象是类的一个实例;
- __init__,init的左右两侧是两个下划线,不是一个,注意!
- __init__函数是默认存在的,它在创建类的实例时自动执行,不需要手动写class.function来运行;正常它什么都不做,但当在类中对其描述时,表示要让它做点什么;
- 自顶向下
- 把要解决的问题写下来,或者画出流程图
- 将第一条的关键概念摘录出来,并加以研究
- 创建一个类和对象的层次结构图
- 用代码实现各个类,并写一个测试来运行它们
- 重复上述步骤并细化代码
- 大部分使用继承的场合都可以用合成替代,而多重继承则需要不惜一切地避免之;
- 类和模块各自的适用场景,什么时候用类,什么时候用模块?如果有一些代码会在不同的位置和场合应用到,那就用合成来把它们做成模块
- 继承与合成
- 不惜一切代价避免使用多重继承,因为它们引发的问题比带来的好处多得多(如果非要用,得准备好专研类的层次结构,以及花时间寻找各种东西的来龙去脉)
- 如果有一些代码会在不同的位置和场合应用到,那就用合成来把它们做成模块
- 只有在代码之间有清楚关联,可以通过一个单独的共性联系起来的时候,使用继承;或者受现有代码或者别的不可抗力因素所限非用不可,那就用吧(程序员创建软件包,共享代码,是一种社交习俗,因此有时因为同事原因,需要打破这些习俗)
- 模块
- 为什么使用?
- 当函数很多的时候,进行分组,让每个文件的代码减少,提高可维护性;
- 一次编写,多个场合引用
- 避免函数名和变量名的冲突
- 其他
- 模块可以放在包里,避免模块命名的冲突,引用示例:包名.模块名
- 包可以有多层,即包上层还可以有包,支持多级结构,示例:大包名.小包名.模块名
- 为什么使用?
- 函数的风格
- 在类中创建函数时,使用动词来命名,作为给类的一个命令;
- 让函数保持简单小巧
- 类的风格
- 类命名应该使用驼峰式大小写,例如:ThisIsClass
- 函数命名应该使用下划线,例如:This_Is_Function
- __init__不应该做太多事情,这会让类变得很难用
- 注释
- 写注释的时候,描述清楚为什么要这么做,代码本身表明“如何实现”,但为什么更重要
- 函数的注释,用一两句话写写这个函数的用法,还是很有用的;
- 尽量让注释短小精悍,一语中的(如果更新了代码,记得检查注释是否需要更新维护)
- 在测试文件所在目录的上一级目录运行测试文件,人们常犯的一个错误是在测试目录中运行测试文件;
- pip 的用法
- pip:win10,先下载tar格式的压缩包,解压到某文件夹,powershell,cd命令进入该文件夹,输入指令:python setup.py install,即开始安装
- 有了pip后,其他几个就好办了,直接在powershell里面输入:pip install “包名字”.whl
- 显示安装了什么版本的包:pip show –files SomePackage
- 显示非最新版本的包:pip list –outdated
- 安装最新版本的包:pip install –upgrade SomePackage
- 卸载不需要的包:pip uninstall SomePackage
- dict.update(dict2):将 dict2 添加到 dict 中
- 示例:dict = {‘age’: 47, ‘sex’: male}, dict2 = {‘tall’: 6’5”}
- 运行:dic.update(dict2)
- 结果:dict = {‘age’: 47, ‘sex’: male, ‘tall’: 6’5”}
- dict.get(key, default):从字典中取 key 对应的 value,如果取不到则返回 default 值
- 测试用例应该保存在 test/ 下面,不然不会被 nosetests 执行;
- 测试用例的代码应该尽量保持整洁,尽量删除里面的重复代码,可以通过创建一些辅助函数来删除重复代码,这样在未来修改测试用例时,可以节省很多工作量;
- 别太把测试当做一回事,有时候,最好的办法是把代码和测试全部删掉,然后重新设计代码;
- nosetests 的用法
- 首先,是 nosetests,不是 notetests,名称别写错了
- 凡是有重复代码的地方,则应考虑是否抽象单独的函数或类
- 类里面的函数至少需要一个参数self
- split() 函数可以将字符串按空格(或者其它标记也行)拆分成多个字符串,返回由多个字符串组成的列表
- 元组是一个不能修改的列表,使用圆括号(为什么元组设定为不能修改,这样的好处是什么?)
- 对象只能通过对类的实例化进行创建,不能创建不基于类的对象;
- 列表的各个元素中间记得用逗号隔开!!!
- 从raw_input获得的数字是字符串,但当使用 int() 转换成数字后,后续的使用可以直接作为数字,不需要再用引号包含起来作字符串使用
- 字符串大小写转换的函数:
- upper( ):全部大写
- lower( ):全部小写
- capitalized( ):字符串的首字母大写
- title( ):字符串内所有单词首字母大写
- 用法:string.lower( )
- isdigit( ): 判断字符串是否为数字
- 类可以被单独导入,对象也可以被单独导入,例如 test.py 文件中有一个类叫做 SampleClass,有一个对象为 sample_object = SampleClass(),则可以如此导入:from test import sample_object
- 通过导入模块,可以访问模块中的函数、对象、变量;
- 对于字典来说,键是一个字符串,获得值的语法是“[键]”;对于模块来说,键是函数或者变量的名称,而语法是 “.键”
- 类的作用类似于一个迷你模块,在这个迷你模块中放了一些函数和数据,可以访问;相对模块,使用类的好处在于,它是一份模板,可以基于这份模板创建无数个对象,然后这些对象各自发挥作用并且不会相互影响,而使用模块,则无法实现这个效果;
- 当想让模块发挥作用的时候,通过 import 导入这个模块;当想让类发挥作用时,通过实例化,即创建对象发挥作用,例如: thing = SampleClass()
- 面向对象编程的好处:
- 封闭:统一接口,解藕(应付需求变更)
- 归一:简化设计(寻求事物的本质)
- 类变量和实例变量的不同
- 类变量由所有对象共有
- 实例变量由各个对象独有
- 因此:当由类生成A、B两个对象时,如果A对象对类变量进行了变更,则B对象再访问类变量时,值已被更新
- 另外,可以通过在变量名称前加双下划线“__”,来声明该类变量是类的内部私有(即只能在类的内部被访问,不能在类的外部访问)
- 在类的__init__创建变量时,记得加上前缀 self,例如:self.var = value
- assert_raises的用法
- 示例:assert_raises(ParseError, parse_verb, word.list1)
- 释意:ParseError 表示应引发的异常, parse_verb是要调用的函数,word.list1是要传给要调用的函数的参数
- assert的其他用法
- assert 和 assert_equal,示例如下:
- assert var1 == var2
- assert_equal(var1, var2)
- try..except 和 assert_raises
- assert_raises(Exception, func, var1, var2)
- try:
- func(var1, var2)
- except Exception
- except Exception:
- pass
- assert 和 assert_equal,示例如下:
- web.py
- python bin/app.py 1234(用1234来指定访问的端口号(不写则默认为8080),此时可使用 localhost:1234 来访问)
- $name 会将变量转义为字符串,如果变量中带有要执行的HTML代码,则可以使用 $:name 代替 $name(HTML文件中使用)
- 通过 urls = ( ‘/(.)’, ‘Index’),中的 ‘/(.)’ 替代之前的 ‘/‘ ,以获取 ‘/‘ 后面的字符并将其做为参数传递给 Index 类
- 可以在 urls 中放置多个元组(用逗号隔开),以便让不同的 url 指向不同的类
- seeother():用来跳转到其他页面,例如:当通过 form 提交一个表单后,使用 seeother(‘/someotherpage’),此时POST方法将返回给浏览器 303状态值和一个新网址,浏览器会对这个新网址发出GET请求;
- redirect(‘/someotherpage’):用来重定向到新的页面
- web.header(“Content-Type”, “text/html; charset=utf-8”):用来在输入内容前,向浏览器传送一些头部信息,目的是让浏览器能够正确识别内容;
- 使用 cgi 模块来限制上传文件的大小,示例:
- import cgi
- cgi.maxlen = 510241024 #表示最大为5M
- try:
- 正常代码
- except ValueError:
- return “File too large” #给出文件过大的提示
- web.input():包含一个从url(GET方法)或者header(POST方法)获取的变量的一个对象 web.stroage 对象(类似字典);当表单提交多个值时,此时写成 web.input(id=[]),以便告诉 input 默认传递值是一个多值列表,不然默认当成一个字符串处理(即使传递数字也会当作字符串处理);
- re 模块:regular expression, 正则表达式
- 怎么用?
- if name == “main“: app.run()
- 背景:模块有自带一个__name__属性
- 如果 py 文件被直接运行,则 name 被赋值为__main__
- 如果 py 文件被 import,则 name 被赋值为模块名(不带扩展名)
- 以上语句表示,当 name 的值为 main 的时候,语句被执行;若不是,则不执行;
- kill():用来杀死进程,退出程序,还有其他两种方法,分别为:
- sys.exit(),参数可为0,正常退出;1,异常退出;
- os.exit(),
- str(var) 和 repr(var):将任意值转化成字符串,前者供人阅读的格式,后者为供机器阅读的格式
- HTML
- pre 是 Preformatted text(预格式化文本) 的缩写。使用此标签可以把代码中的空格和换行直接显示到页面上。但是 < 、 > 和 & 等特殊文字需要用 < 、 > 和 & 的方式记述
- HTML 状态码
- 2系,成功
- 3系,重定向
- 4系,请求错误
- 5系,服务器错误
- HTML form 表单也可以通过 GET 方法提交,只是有些缺点,例如数据不安全(在 url 中可见),传输大小有限制;示例:<form ,action=”/hello”, method=”GET”>
- 在 HTML 中用 python 定义函数时,支持与 HTML 标签混编,但在调用函数时,需要在美元符后面加冒号
- 示例:$def hello(name):
- <h1>$name</h1>
- 调用:$:hello(name)
- 示例:$def hello(name):
- def foo(a, b=0)
- 函数有两个参数,其中第二个是可选参数,且有默认值0,此时如果调用函数的时候,只传递一个参数,则自动赋值给a;
- def foo(a, b, *c)
- 函数有两个固定参数和一个可选参数c
- 示例:foo(1, 2, 3, 4, 5),此时 a 赋值1,b 赋值2, c 赋值(3,4,5)元组;
- 如果只传递两个参数,则 c 会是一个空的元组;
- foo(a=100, b=99) 和 foo(b=99, a=100) 是等价的,即使用关键字参数时,顺序就不重要了,可以被打乱;另外还可以固定位置和关键字组合,例如 foo( 100, b=99, c=98),其中100会默认赋值给a
- foo(a, **b),表示除了正常形参 a 以外,余下的参数都将组成一个字典参数传递给函数
- 示例: foo(100, b=200, c=”Hello”)
- print a,得到 100
- print b,得到 {b:200, c:”Hello”}
- 示例: foo(100, b=200, c=”Hello”)
- sys 模块包含了与 python 解释器和它的环境有关的函数
- sys.path 是一个模块搜索的路径集 list,可以使用 sys.path.append(path) 添加相关的路径,但退出 python 环境后自己添加的路径将消失;
- string.strip([chars])
- 如果参数 chars 为空,则默认裁剪删除 string 前后的空格(包括回车’/n’,制表符’/t’, ‘/r’)
- 如果参数 chars 不为空,则裁剪删除 string 前后落在 chars 中的字符,无关乎顺序;
- lstrip(),只裁剪头部; tstrip(),只裁剪尾部;
- os.path.isdir(path) 可以用来判断路径是否为文件夹;os.path.dirname(path) 可以用来获取路径所在的文件夹;os.path 这个模块里面还有很多其他函数用来处理关于 path 的操作,点击查看
- 疑问:
- web 类除了可以有 GET 和 POST,还有哪些?
- 如果要从一个文件夹中导入文件,则此文件夹需要有一个 init 的文件(空内容也行),这样这个文件夹会被视作一个包;
- app.run( )忘了写括号,导致没运行起来
- 遍历列表值
- 方法1:
- for x in list: print x
- 方法2:
- for x in range(len(list)): print list[x]
- 方法1:
- 在 HTML 中给参数赋值,美元符号后面,变量名之前,需要有一个空格,正确示例 “$ a = 10”, 错误示例 “$a = 10”
- HTML,<input type=”radio” name=”action”, value=”render”>,注意别把 value 给忘了,不然不会提交表单给服务器;
- 抄写示例代码时,写完后,认真核对每一行的输入有没有遗漏,非常重要!!!
- 如果提示 no moduble named something,如果单词没有拼写错误且模块也存在,则有可能是没有设置环境变量造成的;环境变量的设置方法,windows下,在 powershell 中输入以下内容:$env:PYTHONPATH = “$env:PYTHONPATH;.”
- 元组的操作跟列表类似,唯一的区别是元组的内容不可修改;
- file.readlines( ):返回的列表中,会包括 file 里面每一行末尾的回车符,如果不需要它,可以通过 strip() 将其裁剪掉;
- 函数可以有两种写法,一种直接改变传入的参数并返回;一种不改变传入的参数,通过新增变量来赋值并返回,感觉后者的副作用更小;
- 如何给POST方法做测试?
1. 模拟数据提交,验证返回结果
2. 怎么模拟数据提交?- 原理:url 类里面的一种方法,通过传入参数,这个函数返回相应的结果,验证结果是否符合预期
- 作者做了一个测试网站响应的 tool,通过调用这个工具来判断网站是否正确响应;
- 除此之外,是否有更好的方法?
3. app.request( /url ) 这个函数是干嘛用的? - web.py中,web.application里面的一个函数,向 applicaiton 发送路径和方法进行请求,返回结果是一个 storage 对象,里面包含有:返回数据 data,状态 status,头部信息 header;
4. web.py 中的 application 类是干嘛的? - 作用:基于路径代理请求;
- application(self, mapping=( ), fvars={ }, autoreload=None),其中:
- mapping=( ): 是一个存有 url 与 相应类之间的映射关系的元组,例如:urls = (“/hello”, “Hello”),默认初始为空
- fvars={ }:默认初始为空的字典,这个字典存放命名空间,可以是局部的 locals( ),也可以是全局的 globals( )
- 命名空间,一个很重要的概念
1. 函数的命名空间- 每个函数都有自己的命名空间,在这个空间里面,放着函数的参数、变量等
- 这个空间类似于一个对象,放在里面的东西,用键来表示,键值则对应东西的值
2. 模块的命名空间 - 模块的命名空间跟函数一样,只是放入了更多东西,包括:模块的参数、模块的变量、模块的类、模块的函数等
- 对于 from module import something,它的原理是从 module 中调用 something,并放入当前的模块;
- 对于 import module,它的原理是调入整个 module,,因此这个 module 还保留着自己的命名空间;
- 对于后者,如果要访问 module 的函数,就需要加上 module 的名称作为前缀名,因为这样才能够访问到该命名空间;
- locals() 和 globals():
1. 作为两个内置函数,提供了访问局部命名空间和全局命名空间的方式
2. 前者是只读的,后者不是;调用 locals() 时,它并没有返回命名空间,而只是返回了一个拷贝,所以对它进行操作并不影响原空间;而globals() 返回的是全局命名空间的字典,所以对它进行操作,都会对全局变量发生影响;
3. 用途:使用这两个函数,通过提供变量的字符串名称,可以动态的得到任何变量的值; - vars(object )
1. 如果有参数,表示返回 object 的属性组成的字典,等同于 object.dict
2. 如果没有参数,其作用与 locals() 相同 - dir(object )
1. dir() 会自动寻找一个对象的所有属性,不管它是字典还是列表,包括__dict__中的属性
2. dir() 返回所找到的属性组成的列表 - python 的“非”运算符使用 “not”,而不是使用感叹号“!”
- 据说:虽然可以随时给对象的属性赋值,但好的编程规范是将属性的初始操作都封装在 init() 中;
- 对于在类的主体中初始化的属性,会立即被执行,但是使用 def 关键字声明的方法,则不会被立即执行,而是等到调用时才执行;
- 如果通过 def 定义了一个函数,实际是在全局定义了一个变量;如果用同样的方法在类中定义一个函数,则是为这个类添加了一个属性;因此,实例的方法,实际上是在类中,而不是在实例中;当调用 类Foo 的实例 f 的方法 say() 时,实际上是调用了 Foo 的 say() 方法,并且把 f 做为第一个参数传到 say 中,因此 f.say() 和 Foo.say(f) 实际上没有本质上的区别;
- 在 python 中,变量和属性的寻址略有不同;变量的查询遵循 LEGB 原则,即 local, enclosing, global, builtin;属性的查找原则则是:先查找属性声明的那个对象,然后是创建对象的类,然后顺着类的继承往上找,直到 object 对象;所以可以说,python 没有实例变量和类变量的说法,只有对象和属性(因为在 python 中,一切皆对象);但我们应该避免类属性和实例属性重名;
- format() 函数,用来格式化输出字符串,示例:
1. 例子1:- age = 25
- name = Rudi
- print(‘{0} is {1} years old. ‘.format(name, age)) #输出参数
- 结果:Rudi is 25 years old.
2. 例子2 - print(‘{0:.3} is a decimal. ‘.format(1/3)) #小数点后三位
- 结果:0.333 is a decimal.
3. 例子3 - print(‘My name is {0.name}’.format(open(‘out.txt’, ‘w’))) #调用方法
- 结果: My name is Rudi.
- 说明: 数字(0, 1, …)即代表format()里面的元素, 所以可以使用”.”调用元素的方法
- 如果要导入 A 文件夹中的 B 文件的 C 类,如下:
1. from A.B import C
2. 注意:A 和 B 使用点“.”连接,而不是斜杠“/” - web.py 里面有很多是模块,使用之前需要先导入才行,例如: from web import form,之后才能使用 form.** 来创建一些对象;
- 获取用户输入的选项,程序进行不同的处理,除了使用 if 来逐个判断外,更好的做法或是将选项与值组成一个字典 dict {key1:value1, key2:value2},然后使用 dict.get(key) 来进行处理
- raise 关键字有什么作用?
1. 可以用来触发错误
2. 还有以下用法- class Foo(object):
- def AA():
- #处理业务逻辑
- raise web.seeother(‘/‘)
- def AA():
- class Foo(object):
- session 和 cookie
1. 目的:由于 http 是一个无状态协议,所以如果想达到个性化服务的效果,就需要有一种机制来识别客户端的状态;
2. cookie 采取在客户端保存状态,session 采取在服务端保持状态;
3. 如果是持久保存,session 的实现需要 cookie 配合;如果只是本次访问期间保存,则 session 可以通过 url 重写或者表单隐藏字段来实现; - 疑问汇总
1. 代码写在一个文件里,跟分开写成多个文件:什么时候使用前者,什么时候使用后者,各自的使用场景是什么?
2. GET 方法,服务器返回值时,此时的值是如何存储,以及应该如何读取?- 通过 request( ) 函数向服务器发送请求,返回值是一个 storage 对象,里面带3个信息,分别是 data, header, status;可以使用 request(‘/**’).data 来访问,返回的 data 是一个字符串;
3. class, type, 的区别? - Classes are Instances of type.
- User-defined classes are instances of type classes.
- User-defined classes are types that generate instances of their own.
4. 可以根据需要再加载模块吗,而不是一次性都加载进来? - 可以动态的加载模块
5. web.config.get(‘_session’) 和 web.config._session 二者的区别是什么? - 前者表示获取字典 web.config 指定键 ‘_session’ 的值
- 后者表示访问对象 web.config 指定属性 _session
- 为什么 web.config 一会是字典,一会是对象呢?
- 在 python 里面,一切皆是对象,因此字典也是一种对象
- 对象的属性储存在对象的 dict 属性中,dict 是一个字典,它的键即是属性名,键对应的值即是属性本身;
- 通过 request( ) 函数向服务器发送请求,返回值是一个 storage 对象,里面带3个信息,分别是 data, header, status;可以使用 request(‘/**’).data 来访问,返回的 data 是一个字符串;
6. 点 "." 操作符可以应用在哪些场景?
1. 访问包中的模板
2. 访问模板中的函数、变量、属性
3. 访问对象内的函数、变量、属性
7. web.py 模板 template 中的 base="layout" 如何使用?
1. 详见 web.py 学习笔记中的站点布局模板
2. 原理:
1. 编写一个通用的布局模板 layout.html,base="layout.html"(如果有些页面不想用,就不加这个)
2. 使用变量 content,将变量 content 放在内容区 $content,外面由模板的HTML 标签包裹
3. 还可以在 content 下面设置一些变量,通过 content.var(变量名)来访问;
- 错误总结
1. 在类中定义的函数,至少要有一个参数self,不能没有参数;
2. 取字典的键值,需要使用 get(key) 函数,而不能直接 dict.key,但可以这样 dict[key];
3. 条件判断记得用 ==,而不是 =
4. 思考- A 引入 B,B 引入 C,从而使用在执行A 的时候,获得了 C 的代码?待实践
5. 判断 A 字符串是否包含在 B 字符串中,使用 if A in B
6. 创建类的时候,记得写 (object)
7. 自增是 i += 1;而不是 i =+1
8. 在函数中与全局变量同名的变量,如果在函数中有改变此变量的值,则函数内的变量会被识别为局部变量;如果确定两个变量是一样的,则需要在函数中给变量加上 global 关键字,用来告诉解释器,此处引用了一个全局变量;
9. 一行写多条语句的话,可以通过分号换行,不过不太推荐这种写法,建议一行一条语句,这样比较容易阅读
10. 多行一条语句,可以通过行的末尾加“/“ 符号来表示本行未结束
- A 引入 B,B 引入 C,从而使用在执行A 的时候,获得了 C 的代码?待实践
- 其他知识
1. rsplit([sep[, maxsplit]])- rsplit 可以从右侧开始分割,因此对于获取文件名特别有用;
- maxsplit 可以用来指定分割次数,默认为 -1,即分割所有;若指定1,则只分割一次;
2. windows powershell 输入文件结束符的方式为 ctrl + z;linux 下输入文件结束符的方式为 ctrl + d
3. 偏函数:当某个函数的参数比较多时,或者其中某个参数是固定值,可以使用 functools.partial 来包装这个函数,生成一个新函数,目的是后续调用的时候更加方便,可以减少重复写固定值的参数的工作量;
4. zip 函数用于将多个可迭代对象中的元素,一一配对,组成元组列表后返回;