Python是完全面向对象的语言,函数,模块,数字,字符串都是对象。
Python的值不用定义类型,直接赋值即可使用。(因为任何数据都是对象,包括数字。所以变量赋值就是把对象关联起来。每一次变量重新赋值,并没有改变对象的值,只是新创建了一个新对象,并用变量指向它。)
布尔值为True,False。为False的情况:
数字0(包括0.0),空字符串,None(None是Python里的一个特殊值,表示空值),
空集合,包括( ) , [ ] , { } 其他值都认为是True
变量名不能以 双下划线开头(这类标识符具有特殊意义,如: _init_( ) 代表类的构造函数)
同时只能由数字,字母,下划线组成。其他符号都不行。
算术运算符:
‘la ‘ * 3 = ‘la la la ‘
10 / 3 = 3.3333(普通的除) 10 // 3 = 3(取整,跟java的一样)
3**2 = 3^2 = 9
关系运算符,对于字符串,从左到右比较字符。
‘z’ > ‘a’ > ‘Z’ > ‘A’
逻辑运算符:not , and, or
在字符串前面加u,表示Unicode编码。 u’asdczx’
id( ):输出变量的地址。
当x = y,二者就指向了同一个地址,此时 x is y 返回True。 x is not y 返回False
print可以有占位符。
例子:
“X’s address is : %d” 此时%d就是普通的字符串,但如同在后面增加value
“X’s address is : %d” %(id(x)) 那么%d就会被 id(x) 所替换。
类型转换:
字符串转数字: int(x), long(x), float(x) 都有第二个可选参数,表进制。
eval(“..”) 计算字符串里的表达式。例子:eval(‘4+2’) 输出6
数字转字符串:str(x)
repr(obj) 将对象转换为可打印的字符串
chr(整数)将一个整数转换为ASCII字符。 ord(字符) 将一个ASCII字符进行转换为整数
hex()整数转16进制 oct() 转8进制
访问字符串某下标: [ ]
“asdefg”[3] = ‘e’ index从0开始。
截取子字段:[a : b] 获取index从a开始,到b-1的字串。
如果用 a - b,会将a - b计算出结果,然后再获取。如果是负数,则从后面算起。-1是最后一个。
范围是: [-length ~ length - 1] a[-length] == a[0] [-1] == a[length - 1]
in , not in 某字符/字符串是否存在于该字符串中
r”asdzxc\nsdew” 使得\n这种转义符失效,成为普通字符串。R同理。这个例子要在print里生效。
-—
Python对于缩进是有限制的,错误的缩进会报错。
(CMD中写Python,tab第一次是4个空格,后面是8个空格,容易出错。)
例如if语句:
if a > 10:
print(“xxx”); //如果不缩进,会报错
如果if中有多个语句,这些语句都要有相同的缩进。在cmd中,也要缩进,以一个空行结束if体。
elif : 相当于else if
1 | a = 15 |
while语句:
1 | i = 1 |
for语句: for i in range(start, end): <==> for (int i = start; i < end; i++) s
循环体
1 | i = 1 |
(这里前面i定义与否都可以,但不定义的话,print(i)里会有warning,但还是可以运行的。
try-except语句
1 | try: |
raise 可以显式抛出异常(相当于throw)
——–数据结构
1.列表List (跟数组差不多,index从0开始)
定义一个list: a = [ ]
len( ) 输出长度 append添加到最后 index(i, element) 插入到index为i处
a1.extends(a2) 将a2的元素全部添加到a1中
效果等同于: a1 = a1 + a2
PS:使用加号运算符,会导致a1的内存地址改变。(即a1指向了新的内存地址)
a1 = a2; #二者都是list
当a2改变的时候,a1也会跟着改变。(二者指向同一个list)
(但如果a2的改变是改变了内存地址,如上面的加号运算符,那么a1还是指向a2原本的内存地址,而a2指向了新的内存地址。此时a1 is a2 返回False)例子:
1 | a = [1, 3, 5, 7] |
list也可以用str( )转换成字符串。否则print的时候与字符串连接会报错。需要:
1 | print("some strings here: " + str(aList)) |
删除元素,length也会改变。(感觉也就C,JAVA的数组还是不可变长度了):
1 | del listName[index] |
相当于String的indexOf,找到第一个element 的index。如果不存在,抛出异常:
1 | a.index(element) |
遍历数组,for语句即可:
1 | a = [1, 3, 3, 3, 5, 7, 3] |
不换行print,第二个参数为 end=… 其中… 为每一次输出后面加到末尾的字符串,这里是一个空格。
同时for语句的range函数,如果省略掉一个参数,那么就是从0开始。
可以用for语句的同时,使用enumerate( )函数进行对 index跟value同时遍历,例子:
1 | a = ['a', 'csd', 'we', 'zca', 'ert', 'hnx'] |
(这个占位符的%后面要加空格,不然又有warning)
sort( ) : 对list进行排序 a.sort( ) 才是正确的。 sort(a) 没有效果
1 | a = ['a', 'z', 'A', 'Z', 'B'] |
(z > a > Z > A)
reverse( ): list倒转。如果希望倒序,应该先sort,再reverse
range(start, end) (range函数实际上会生成一个list)
从start到end递增(到end的时候就结束循环),start 默认值为0
2.元组 tuple
与list很相似,
区别在于:一经定义,内容就不能改变(所以没有插入,删除等功能)。而且可以同时存储不同类似的数据,用圆括号,而不是中括号括起来。
各种方法都与list一致:
1 | a = (1, 2, 3, 4) |
由于内容不能改变,所以没有sort函数,也没有reverse。可以先将tuple转换为list,然后再对list排序,再将结果赋值给tuple。
转换:
列表对象 = list(元组对象)
元组对象 = tuple(列表对象)
1 | a = (31, 12, 23, 14) |
3.字典 directory
用{ },就是键值对。 { key1: val1, key2: val2, … , keyn: valn}
len( ) 长度。
a[keyx] = valx 添加
a1.update(a2) 合并两个字典,结果放入a1.(此处不可以用a1 = a1 + a2,会报错)
删除键: pop
判断是否存在: in
遍历keys,values:
1 | d1 = {'name': '小明', 'sex': '男'} |
或者 : for (k, v) in dict.items( ): # items( ),获取key-value结果集 (代码略)
清空字段: a.clear( )
字典也可以嵌套,跟多维list一样。
{‘name’ : {‘first’: ‘Kevin’, ‘last’: ‘Seth’}, ‘age’: 40}
访问嵌套字典:字典[键] [键] print(d[‘name’] [‘first’])
1 | d1 = {'name': {'first': 'Kevin', 'last': 'Seth'}, 'age': 24} |
4.集合 set
集合由一组无序排列的元素组成,同时集合里没有重复的元素。
分为可变集合(set) 和不可变集合(frozenset)
(可变集合 创建后,可以添加元素,修改元素,删除元素)
创建集合:
1 | s = set('python') |
len( ) :获取集合的长度
for e in s 遍历。
add 添加。添加后的元素也在随机位置
s1.update(s2) 添加集合。
1 | s = set([41, 22, 13, 54, 19, 38, 77, 5, 6]) # 也可以直接{41, 22, 13, ……} |
remove(value) 删除指定的集合元素
clear( ) 清空
in:判断某个value是否存在于集合中 存在返回True。否则False
A < B , 如果A是B的真子集,返回True。
A <= B, A是B的子集。
A > B, A是B的真超集 A >= B A是B的超集
| : 并集, s1 | s2 == s1 ∪ s2
也可以用这个union方法: s = s1.union(s2)
& : 交集 s1 & s2 == s1 ∩ s2
也可以用这个intersection方法: s = s1.intersection(s2)
1 | s1 = {1, 2, 3} |
^ :差分集 即 (s1 ∪ s2) - (s1 ∩ s2)
也可以用这个symmetric_difference方法: s = s1.symmetric_dirrerence(s2)
1 | s1 = {1, 2, 3} |
按位运算: &与 |或 ^异或
-————————-
函数:
在函数里定义的变量是局部变量,作用域就是在函数体内。如果全局变量和局部变量同名,那么在函数体内只能访问局部变量。如果在定义局部变量之前调用了同名的“全局变量”,会报错。因为函数体内只能访问局部变量,会显示:UnboundLocalError: local variable ‘a’ referenced before assignment
Python的传值是按值传递的(但传的值都是对象,数字也是对象,这点跟java不一样)
(经过测试:传数值,字符串都不会随着函数而改变,但list,directory会发生改变!)
1 | def sum(list): |
函数定义后面的参数可以指定默认值,(有默认值的参数只能出现在没默认值的参数的后面)
1 | def say(message, times = 1): |
如果没有指定默认值,那么调用say(‘hello’)的时候参数个数就不对,会报错。当参数个数不一致的时候(或多或少),都会报错(不要跟JS混淆)
可变长参数(跟java不一样),这里是指参数可以是元组,或者是字典。
在形参前面加,表示为 可变长参数。 是元组,是字典
例子:def f(*t): 此时调用可以是:f(1),f(1,2), f(5,756,234,23), f({‘a’: ‘111’, ‘b’: ‘324534’})
def f(**t): 此时调用可以是: f(a=1), f(a=1, b=2, c=3), f(a=1, b=12, c=543, d=765)
函数可以指定返回值,return。在函数体里用就行,定义上不用写什么。
Python预定义函数:
abs, pow(x, y), ound(x [, n]) 四舍五入,保留n位小数。 divmod(a,b) 返回 a / b , a % b
(这个四舍五入,-2.5的结果是-2,2.5的结果是2)
PS:Python2中,2.5的结果是3.0。但在python3中,2.5会返回2,2.5000000001才会返回3
字符串处理函数: lower, upper , swapcase(大写转小写,小写转大写)
capitalize 首字母大写。 title 首字母大写,其余为小写
title是每一个单词的首字母大写,例子:
1 | s = 'hello woRLd'.title() |
ljust,rjust, center 左对齐,右对齐,居中对齐,第一个参数为width表示字符串总长度,第二个参数可选,当长度不足时填充,默认是空格填充。
zfill, 用0填充到width长,右对齐。
搜索和替换:
str.find(substr) 查看字符串str中出现子串substr的第一个字母的位置,找不到则返回-1
index 与find函数相同,但找不到的时候会报错
rfind 从右侧开始find (注意index的结果还是顺序来算的)
rindex
count 计算子串的出现次数
(以上5个方法还有两个可选参数,start,end,表示搜索范围从start到end - 1)
str.replace(oldstr, newstr [,count]) 替换。count为替换次数。
strip,lstrip,rstrip,把前后,前,后的[chars]字符去掉。默认为空白符。
expandtabs 把tab字符替换成空格,每个空格替换成[tabsize]个空格,默认是8个
分割和组合:
split(跟java一样), splitlines 按照行分隔符划分 join把字符串序列用特定字符连接起来
1 | list = ['214, '233', '532'] |
startwith,endswith,isalnum(是否全是字母或数字),isalpha 字母 isdigit
islower isupper
help(obj) 输出这个对象的帮助信息(可能是命令,可能是list等等的对象)
(传入一个list,就能看到List列表对象的源码)
type(obj) 显示一个对象的数据类型
字符串会返回: <class ‘str’>
数值会返回: <class ‘int’> <class ‘float’>
列表会返回: <class ‘list’>
-——————————-
类
1.变量,构造函数,析构函数,调用等等:
PS: xxx 表示系统定义的名字 __xx:表示是类的私有变量名(类外不能直接访问)
直接在构造器里调用 self.str11 = ‘111’ 也算是定义了一个成员变量str11(即使函数外部没有定义str11这个变量。)
1 | class Person: |
2.静态变量,静态方法:
1 | class MyString: |
定义静态方法需要在方法前加:@staticmethod (而且参数列表里不能有self)
而定义静态变量不需要任何东西,每一个变量都同时是实例变量和静态变量。只要是通过类名访问的就是静态变量(看上面的例子,str通过instance访问时,就是实例变量,通过类名访问时则是静态)
类方法:@classmethod,第一个参数是cls(表示当前的类)
(其实类方法跟静态方法区别不大,静态方法可以直接用类名表示当前类。但一般的区分是这样的:静态方法存放与类无关的逻辑代码,如单纯的表达式计算。而类方法存放与类属性相关的逻辑代码)
isinstance(对象名, 类名或类型名)
例子: isinstance(str, MyString) isinstance(1, int)
继承:class B (A) B继承A,同时构造器里需要显式调用一次父类构造器
子类会继承父类的属性跟方法(私有除外)但如果提供了访问私有函数的公共接口,那么子类通过继承了这个public方法,也是可以间接访问父类私有函数的。
1 | class A: |
如果子类不调用父类的构造器,那么在父类构造器执行的语句就不会生效。比如,父类有属性a = 1,构造器里有赋值语句 a = 5.如果调用了父类构造器,那么子类继承的a属性值为5,如果没有调用,子类继承的属性值为1.如果父类的属性a仅仅定义在构造器里,那么调用父类构造器之后,子类成功继承属性a。如果没有调用父类构造器,则没有继承属性a,会报错(但其他构造器之外的成员都可继承)
1 | class A: |
同时,子类和父类有同名函数,此时是多态,会调用子类的函数,而非父类。(类型是子类)
抽象类和抽象方法:
Python通过类库abc实现抽象类,所以需要先import
from abc import ABCMeta, abstractmethod
在抽象类的第一行写下: _metaclass_ = ABCMeta
在抽象方法前增加: @abstractmethod
抽象方法的定义: def abs_method_name (self): pass
PS:亲测,不需要前面三个步骤,想定义抽象方法直接在函数体 改为 pass 即可!
例子:
1 | from abc import ABCMeta, abstractmethod |
值得注意的是,抽象类是可以实例化的,也可以调用非抽象方法跟抽象方法。而且子类也会继承这个抽象方法。但调用没有实现的抽象方法(pass),不会产生任何结果。
而且抽象类可以实例化,跟普通的没有区别。想定义抽象方法直接定义为pass即可
(我觉得抽象方法的主要用途是定义一个公共的方法,但未提供实现。子类可以选择实现并且使用,可以不实现,这时候甚至还能调用这个方法,但没有结果。比直接报错要好)
至于抽象类,似乎目前没有用,可能后面配合 模块 可以实现抽象类禁止实例化? //TODO
多态:在不同的子类,同名方法可以有不同的实现。(如果子类没有实现该方法,就调用父类方法)
对象复制:
直接a2 = a1,之后二者指向同一个对象。除非指向其他对象,否则仅仅改变属性,内存地址并不会发生变化。而且a1的属性值改变之后,a2也跟着改变(二者始终指向同一个对象)
1 | class A: |
当函数的参数是对象是自定义的类对象时,由于传入的参数并没有声明类型,所以这个时候应该先对参数进行类型判断。 if isinstance(str, MyString): …
-——————————
模块module 相当于java里的jar包,有封装好的函数,变量可以使用。
import xxx 调用:xxx.f xxx.val
常用模块:
1.sys
可以获取系统的信息,还可以获取运行时的命令行参数,用作输入等等,例子:
1 | # 调用命令: python test.py 3, 4, 9, 1 (如果逗号后面没有空格,好像会把整个当作list) |
2.platform
可以获取操作系统的详细信息和与Python有关的信息
3.math
与数学有关的。
常量:e,pi
常用方法:
fabs:取绝对值
floor:返回小于等于x的最大整数
log(x,a):返回loga(x) 如果不指定a,默认是e
log10
pow(x,y) : x^y
sqrt : 根号x
trunc: 返回x的整数部分
4.random
生成随机数
random( ) :生成一个0到1的随机浮点数 0 <= n < 1.0
uniform(a, b) :生成a~b范围内的随机浮点数 [a, b] 或者 [b, a] (看哪个比较大)
randint(a,b):生成a~b之间的随机整数(a不能比b大) [a, b]
randrange (a, b, c):
生成 [a, b)范围里的随机数,每次递增的间隔为c。即获取a, a+c, a+2c, a+3c ……(不包括b)
choice(sequence) : 从sequence里随机获取一个元素。sequence可以是list,tuple,string
shuffle 打乱list
sample(sequence, k) : 从sequence中随机获取长度为k的片段。原有sequence不会被修改
5.Decimal
导入: from decimal import Decimal (用于浮点数计算,精度更高)
6.fractions
用于表现和处理分数。
x = fractions.Fractions(1, 3)
print(x) # 1/3
对x计算之后,还会进行自动约分。如1/6 * 4会变成 2/3
\7. time模块 (常用)
struct_time数组,表示时间 或者时间戳(1970.1.1到现在的总毫秒数)
year,month,day,hours,minutes,seconds,weekday(星期一为0),yday一年一共几天
1 | import time |
自定义模块:一个.py文件就是一个模块,外部可以通过import导入
1 | import myPackage.m1.myMath |
-—————
函数式编程(感觉跟面向过程差不多,只是功能都封装到函数里)
lambda表达式, 可用作匿名函数
返回函数名 = lambda 参数列表 : 返回值表达式
还可以将lambda表达式作为数组里的value:
1 | sum1 = lambda x, y, z: x + y + z # 输入参数是x, y, z,返回值是三个的和 |
(但PEP8标准觉得def比lambda要好。准确的是,lambda一般用于匿名函数,如果要把lambda赋值给一个变量作函数变量,那还是用def比较好)
map函数
result_sequence = map(function,sequence1 [,sequence2 …])
(function里有n个参数,那么就需要sequenceN)
1 | arr = map(lambda x: x**2, [2, 4, 6, 8, 10]) |
filter函数
filter(function,sequence)
对sequence里的每一个元素调用function,结果为true的返回。最终的结果序列成为filter的返回值
reduce函数
reduce(function,sequence)
function必须有2个参数。然后sequence里的前两个参数调用function,返回结果和第三个参数继续调用function,直到最后一个。
zip函数 压缩,解压(下面例子不能同时for,迭代器对象只能单向迭代一次,到了结尾之后,第二次迭代就像是迭代了一个空的list)
1 | a = [1, 2, 3] |
闭包:即函数的嵌套。
在fun1里定义另一个fun2,然后fun1里的返回语句是return fun2,这时候就去调用fun2.
递归,一样的道理。
迭代器。
1.iter( ) 可以获取一个sequence的迭代器。 next(Iterator)获取下一个元素
1 | list = [12, 345, 234, 65, 78, 54] |
(原生迭代器竟然没有hasNext方法!辣鸡,建议自己实现一个Iterator)
2.enumerate() 将列表或者元组生成一个有序号的序列(index,value)
生成器:
当存在迭代器的时候,比如for in,实际上每一次都会调用一次next()函数,表示生成下一个对象。
1 | def addList(alist): |
用生成器 yield。https://blog.csdn.net/mieleizhi0522/article/details/82142856
yield相当于return,但下一次再进入到这个方法体的时候,会从yield这个语句后面开始执行。显式用next(generator)来调用相应的generator(有yield的方法),在for in的时候,实际上是每一次都隐式调用了next方法的。
同时如果要传值进行next,那么就用generator.send(value),这样就不会出现yield那一句的值丢失(因为return了之后,从下一个语句开始执行,当前语句在下一次是失效的。如a = yield 4,相当于return了4,但下次是从a的赋值才是进行,但右边的值实际上已经丢失,此时传值才可以让a有值,否则是None值。)
那么,生成器和普通的递归有什么区别?
首先,代码可以更加的简洁,看例子:

或者这个例子:https://blog.csdn.net/weixin_40581980/article/details/80986026
(用了生成器语法,直接用1行代码替代了一整个class的功能)
同时,迭代器其实是隐式调用next,而每一步(+1)都会生成元素,开辟空间,添加元素到list
比如我们要获取10000000里的所有素数。如果用迭代器,那么就是 for i in range(2,100000000)
,这样会生成一个很大的list。虽然结果不会有那么多,但中间隐式调用next还是会生成一个临时是长度为10000000的list,极度消耗内存空间。(每一步都要调用next)
1 | class Primes: |
如果使用生成器呢,此时首先无须迭代,那么也就无须用class来实现,用函数即可。然后在循环里,是先进行check,然后check通过之后,才开始yield(生成),并且下一次next的时候,可以从这一步继续执行下去,生成下一个素数。即无须像迭代器一样,首先需要逐步生成所有的数,然后再check。(相当于比如1到1亿里面,有1000万个素数,那么迭代需要生成一个1亿长度的list,然后再查找,找到1000万个素数,再输出。而用生成器,则是找到一个素数,再添加元素到list里,最后的list长度就只有1000万,远小于1亿!)
1 | def Primes(max): |
Python的可移植性:先编译成字节码,然后将其转发到虚拟机(Python虚拟机)中运行(跟java一样)
生成的字节码文件:.pyc文件
Python的编译器总是在运行时出现,因为程序执行之前不需要预编译和链接等等的操作,使得开发周期大大缩短。(具备了更多的动态语言特性,可以在一个Python程序中执行另一个Python程序,即可以动态地修改代码,无须拥有或者编译整个系统的代码)
Python的实现,即编译器,PVM的实现方式:CPython,Jython,IronPython
执行优化工具:Psyco实时编译器(对PVM的增强工具)
print语句,在Python2不需要括号,在Python3需要(被视为一个函数调用)
模块:一个.py文件实际上就是一个模块
UNIX输入输出重定向(Python支持UNIX输入输出重定向)
例子:python xxx.py > saveit.txt 输出会输出到saveit.txt中,而非控制台
导入模块。
import a.b <==> from a import b
也可以用一个变量来赋值:import a.b.c.d q = a.b.c.d
导入的时候,被导入的模块文件会从头执行一次(包括def,class的定义,还是简单的print,都会执行)同时由于导入消耗较大,因此运行两次import(即使在中途模块文件被修改了),也不会执行第二次import,这时候要使用reload(在Python2是内置,Python3里并没有)
exec( open(‘xxx.py’).read( ))
对于exec,代码都相当于粘贴到当前模块文件中,因此同名变量会产生冲突。
而import跟from并不会。例子:
(我们在myMath.py里定义了一个ak变量,值为100)
1 | ak = 50 |
(对于import和from,当我们要访问它的变量,我们需要使用myModule.myMath.ak, myMath.ak等)
Python是动态类型的(自动地跟踪类型,而不是要求声明代码),
但Python也是强类型语言(只能对一个对象进行适合该类型的有效的操作)
字符串截取(跟数组一样操作):
例子:
1 | s = 'python' |
字符串是不可变的,不能对单独一个字符进行改变等,只能重新赋值(指向另一个字符串对象!)
1 | s = 'python' |
实际上还有第三个参数,a[ i : j : k ] k默认是1,表示每隔k个字符索引一次。
所以如果是’abcdefg’[::2] == ‘aceg’
如果K为-1,表示反转字符串。 “hello”[::-1] == “olleh”
如果是 [a : b : -1] 会将[b + 1, a]的字符串反转输出(b最小为0,因此不能获取第一个字符,只能通过index为0获取第一个字符)
slice( ) 切片函数。
dir(obj) 返回一个list,即该obj包含的所有方法(包括继承而来的各种方法,默认方法)
1 | import textwrap |

(textwrap是一个Python标准库的模块,可以用于格式化输出,这里使得每行输出长度最大为100)
help(obj) 返回obj的类定义。 help(obj.func) 返回obj该方法的定义,帮助信息
(因为Python一切皆对象,当然函数也是一个对象)
关于len( ),转义符也属于长度1
len(‘A\nB\tC’) == 5
关于字符串匹配。
导入re模块,用match( reg, str)方法匹配,返回匹配的结果串,并且可以根据括号进行分组
PS:使用group可以获取分组内容,而且括号仅限小括号。
1 | import re |
这些字符串操作都是一个真正的序列操作,所以很多对于list等等都是有效的。
比如list也可以用-1下标表示最后一个元素!
list的赋值不能超出边界。比如:
1 | L = [1, 2, 3] |
Python的核心数据类型,都支持任意的嵌套。(同时list允许不同类型的元素)例子:
1 | list = [1, 2, ['fsd', 4], 5] |
列表解析表达式 list comprehension expression
语法: [ result_expression for item in list filter_expression]
(第一个的result_expression可以调用后面for item的item数组)
例子:[ [1, 2, 3], [4, 5, 6], [7, 8, 9]] 一个二维矩阵,现在要提取第二列,并且每个值加1:
1 | list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] |
如果使用括号的解析语法,就变成了生成器generator:
1 | list1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] |
(直接用map函数,对列表的每一列进行sum操作,然后用list转换成列表)
ps:sum跟list都是标准模块里的函数,可以直接使用,平时不要覆盖掉
1 | mydir = {'name': 'hong', 'jobs': ['student'], 'age': 24} |
Python也有GC机制,但我们也可以手动删除不再需要的对象(del),也可以赋值为0,引发GC
字典可以用in判断是否存在某个key,也可以get(key1, default_value)
如果存在key1,则返回,如果不存在,返回default_value
文件。 要调用open函数来生成file对象。
第一个参数是路径,第二个参数是权限。默认是’r’,只能是’r’或者’w’,不能是’rw’
同时还可以是’rb’,表示将读出来的数据改为二进制。
1 | f = open('data.txt', 'w') |
判断类型,isinstance是最好的选择
1 | list1 = [1, 2, 3] |
Python操作符表达式:
yield x 生成器表达式
lambda args : expression 匿名函数
x if y else z y为真时,x。否则z
x or y, x and y, not x
x in y, x not in y (iterables,sets)
x is y, x is not y
< , > ,== , != |, & , ^(异或), <<左移 >>右移 /除, //除,取整数结果
s[i: j: k] 数组切片,从[i, j)中,每隔k个数输出一个列表
……
当两个类型不一样的数字进行运算时,结果为更复杂的那个类型。
如:40 + 3.14 = 43.14 3.14 + (2+3j) = 5.14+3j
x < y > z, x > y > z, x > y < z 这种是可行的
math.floor( ) 返回不大于x 的最大整数。所以x为2.5时,结果为2.为-2.5时候,结果为-3
//整除,实际上就是对获得的结果,再进行floor。
所以 5 // 2 == 2 5 // -2 == -3
如果真的只想要整数部分,应该用trunc
python的整数没有范围,支持无穷的大小
进制计数:
0o开头:八进制 (第一个是0,第二个是小写的o)
0x开头:十六进制
0b开头:二进制
oct(x) 十进制转八进制
hex(x) 十进制转十六进制
bin(x) 十进制转二进制
或者是 int( num, x) 第二个参数可选,表示进制,默认是10
eval函数,可以将字符串作为python代码执行,然后运行结果就是返回结果。一般的作用是将字符串对象转换成更具体的对象(比如数字,list,set,directory等等)。但由于eval实际上会将里面的字符串作为程序的一个小片段进行编译运行,所以可以做一些其他的工作。比如甚至可以偷偷地拿一个字符串,将电脑上的某个文件删除:
1 | import os |
位运算:
1 | print(11 | 0b1100) # 0b1111 == 15 (11 == ob1011, 1011 | 1100 == 1111) |
buildins(Python的内建模块,预定义的功能函数)
max,min,sum都在此中。
decimal模块设置全局精度:
decimal.getcontext( ).prec = 4
获得运行环境
decimal.Decimal(1)
print(decimal.Decimal(1) / decimal.Decimal(‘7’))
# 0.1428571428571428571428571429 (默认精度)
关于布尔值(bool)
原本只是一个数字,
如果要用==来判断,那么只有True == 1才会返回True。0 == False才会返回False
如果用if来判断,那么只有特定情况下是返回False。
返回False的情况:
数字0(包括0.0,0.00000等)
空字符串(仅限’’, “”)(前面是一对单引号,后面是一对双引号)
其他诸如:” “(一个空格), ‘0’, “‘’”(双引号里面再加一对单引号)等等,都是返回True的。
空值:None
空集合: [ ] , ( ), { }
(此外,由于python里的True跟False其实就是1跟0,所以甚至能跟数字进行运算。比如:
True + 3 + 5J == 4 + 5J
False + 7.4 == 7.4 True + 5.5 == 6.5
(不过一般意义不大,omit it!)
多个字符串用空格分隔开赋值,相当于加号运算符。例子:
s = “Meaning “ ‘of’ ‘ the life’
s # Meaning of the life
如果中间是用 逗号 分隔开,那么会生成元组。
s = “Meaning “ , ‘of’ “ the life’
s # (‘Meaning ‘, ‘of the life’)
关于转义:
在cmd中直接输出,会变成自动带有转义效果的字符串。比如换行会变成\n,\会变成\
然后,如果赋值的时候,反斜杠后面跟的并不是转义的字符,那么反斜杠会直接写入,例子:
x = “C:\py\code”
print(x) # C:\py\code 因为并没有\p,\c,但建议在使用反斜杠而非转义时,还是直接转义
即: x = “C:\py\code” 结果会是一样的
同时,无论如何,print(x),里面的反斜杠会是\,而直接x时候(在cmd),会是\
在字符串前面加一个r,表示不转义。例子:
c = r’c:\py\code’
print(c) # c:\py\code
三重引号(无论单引号,双引号都可以),可以用于编写多行文本数据。
即’’’ asdzxc…………(包括各种换行)’’’ 这时候里面所有行加起来成为一个字符串。
(cmd中换行会变成\n)
而多行文本中的引号都会直接输出,无须转义。(直到遇见三重引号结束的时候)
同时,可以利用三重引号来作为多行注释(对性能影响不大,一般应该还是用于调试阶段)
转换。int( ), str( ) , repr( )
repr函数能将一个对象转换成其字符串形式。
ord将字符转换成ASCII码,chr则将ASCII码转换成字符。
格式化字符串的两种方法:
1.用%d,%s等占位符
“That is %d %s bird!”% (1, ‘dead’)
2.使用占位数组
‘That is {0} {1} bird!’.format(1, ‘dead’)
显然,format紧接着的就是一个数组,从{0}开始慢慢对应替换。format方法是新的格式化方法。
一般除非要进行特殊的格式化,否则直接用%s就行了,因为每种类型的对象都可以转换为字符串。
PS:格式化的结果是一个新的字符串对象,而不是对原本的字符串进行的修改。
其他格式化代码 P194
字符串方法:P186,此处略
Python一共有3个主要类型(以及操作):
1.数字(整数,浮点数,二进制,分数等):
支持加法,乘法等等。
2.序列(字符串,列表,元组):
支持索引,分片,合并等等。
3.映射(字典):
支持通过键的索引等。
(集合是自成一体的一个分类,不在此中)
每种类型的操作都是相通的,比如:
对于字符串,乘法运算符* 的作用是创建一个字符串的N份拷贝。
s = ‘abc’
s = s * 3 # PS: s * 3 <==> 3 * s
s # ‘abcabcabc’
那么对于其他的序列sequence来说,的运算也是相同的。比如对于list,之前没对list用过,实际上效果也是一样的:
x = [1, 2, 3] * 3
x # [1, 2, 3, 1, 2, 3, 1, 2, 3]
可变类型:数字,字符串,元组,不可变集合。
可变类型:列表,字典,可变集合。
-———
list的append与extend:
append是添加一个元素,extend是添加一个iterable的元素(list,tuple等等,并且迭代展开来。
例子:
[1, 2, 3].append([4, 5, 6]) ==> [1, 2, 3, [4, 5, 6]]
[1, 2, 3].extend([4, 5, 6]) ==> [1, 2, 3, 4, 5, 6]
分片赋值:
L = [1, 2, 3, 4, 5, 6, 7, 8]
L[2: 4] = [100, 200, 300, 400, 500]
使得L的[2, 3]替换成右边的。结果:[1, 2, 100, 200, 300, 400, 500, 3, 4, 5, 6, 7, 8]
字典的key不一定要是字符串,整数也行。只要是不可变对象就行。
获取不存在的key的值时会报错,然后程序就会结束,避免程序结束:
1.if key1 in dir: … else: … 通过if判断是否存在该key
2.try: …… except KeyError: …… 如果出错就执行except里的语句,然后继续执行。
3.dir.get(key1, 0) get方法,获取key1的值,获取不到就返回第二个参数
创建字典的方法:
dir = {‘name’ : ‘xxx’ , ‘age’ : 45}
D = { }
D[‘name’] = ‘xxx’
D[‘age’] = 45
dir = dict(name = ‘mel’, age = 45) # key必须都是字符串才行
dir = dict( [(‘name’, ‘mel’), (‘age’, 45)]) # 给dict传入一个list对象的时候比较适用
嵌套对象用> , <比较大小时,会一直递归,从左到右比较,走到最深的层次,逐步比较差值。
关于乘法运算符,是返回一个新的对象(重复n次连接起来的),这时即使是重复一个对象,也不会因为原对象引用改变而改变新的对象。但在嵌套可变序列(对象)时,情况会不一样:
1 | L = [4, 5, 6] |
对于x = L * 4,是生成了一个新的list,不存在共享引用,因此L改变时,x并不会改变。
但是对于y = [L] * 4,相当于[ … ] * 4生成了一个新的list,而每个[ ]里面又引用了一个外部的list(共享引用),此时L改变时,y也会跟着改变。
解决方法就是拷贝,y2 = [L[:]] * 4,这样就不存在共享引用。
当复合对象包含指向自身的引用,称为循环对象,而这个自身的引用会打印成[…],避免无限循环
1 | x = ['hong'] |
对于sequence:假如 L = [0, 1, 2, 3, 4] len = 5
1.索引值超过边界时,会发生error (如L[5])
2.但分片运算超出边界时,会把超出的数字限制回最大值。
如L[2: 100] 会自动改为L[2: 5] 不会报错
3.但左边界大于右边界时,会返回空sequence。
如:L[3: 1] ==> [ ]
(以翻转的方式提取序列是行不通的( 较低边界值比较高边界值更大, 例如,
L[3:1] )。你会得到空分片( [] ),因为Python会缩放分片限制值,以确定较低边
界永远比较高边界小或相等(例如, L[3:1] 会缩放成 L[3:3] ,空的插入点是在偏
移值3处))
但对这部分赋值是可行的,并且是以左边界处进行插入。
如: L[3: 1] = [‘10’, ‘20’, ‘30’, ‘40’, ‘50’] 但不等于L[3] = [‘10’, ‘20’, ‘30’, ‘40’, ‘50’]
结果会是: [0, 1, 2, 10, 20, 30, 40, 50, 3, 4] (与有边界的数字无关)
如果是L[3]=。。。 则是直接更新list,更新list[3]的值了,而且L[3]的值会变成一个[。。 ] list
L[3] = [‘10’, ‘20’, ‘30’, ‘40’, ‘50’] ==> L == [0, 1, 2, [‘10’, ‘20’, ‘30’, ‘40’, ‘50’], 4]
(如果分片赋值的时候,也超出边界,那么仍然按照第二条来执行:
L[10000:200] = […] 这样就相当于append(超出时是append)
(这种反向(左边界不小于右边界)分片赋值在插入元素时是一个可行的选择)
4.L[2] = [ ] 那么L[2]的值就变成了[ ],即 L == [0, 1, [ ] , 3, 4]
但如果是分片赋值,L[2: 4] = [ ] ,则这里面的值会删除,最后:L == [0, 1, 4]
赋值空列表给一个分片,则会删除该分片
(但如果是第三条的情况下赋值[ ],则不会生效。如L[3: 1] = [ ] ,并不会删除L[3],不会执行任何操作。
而只有当左边界小于右边界(即正常情况),才会删除)
if state:
state2
try:
statement1
except:
statement2
else:
statement3
finally:
statement4
else可以与if连用,也可以与try-except连用。上述语句else是与try连用,就近原则。
try-except-else-finally的意思是:
如果出现了错误,那么就执行except里的语句,如果没有错误,就执行else里的语句。finally一定执行
关于作用域,global和nonlocal:
(global用于在函数里访问全局同名变量,如果没global,按照LEGB原则,全局变量会被局部变量名覆盖,因而访问不到全局变量。)
(而nonlocal用于在嵌套函数里访问外部函数的同名变量,如果没global,按照LEGB,也是会先访问当前层次的局部变量,访问不到外部函数的同名变量)
1 | y, z = 1, 2 |
Python的嵌套函数类似于JS的闭包,也可以保存已经结束了的外部函数的变量。如下面,就相当于可以视为一个工厂函数:(同时还能根据类型而做出不同的选择)
1 | def maker(N): |