-
基础
1.r''表示''内部的字符串默认不转义 2.'''...'''表示多行内容 3. 布尔值:True、False(注意大小写) 4.与运算and、或运算:or、非运算:not 5. None代表空值 6.声明一个变量(前面不用声明类型--动态语言): a = 1;//a是整数 b = 'hello'//b是str(字符串) 7.除法: /: 9/3 = 3.0(计算结果是浮点数) 地板除//: 10/3 = 3(计算结果是整数) 8.ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符 9.对bytes类型的数据用带b前缀的单引号或双引号表示:x = b'ABC' 10.要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes '中文'.encode('utf-8') 得到bytes类型为b'\xe4\xb8\xad\xe6\x96\x87' 从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode() b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')得到str类型为'中文' 11.计算长度len():计算的是str的字符数,如果换成bytes应该这么写len(b'ABC')输出3 len('中文'.encode('utf-8'))输出6,可见一个英文字符占一个字节,一个中文字符占3个字节 12.如果源代码中有中文,则需要在开头加上 # -*- coding: utf-8 -*- 告诉Python解释器按utf-8编码读取,注意:声明了这个并不代表文件本身是utf-8编码的 13.格式化字符串%: 'Hello, %s' % 'world' -----'Hello, world' 'Hi, %s, you have $%d.' % ('Michael', 1000000)-----'Hi, Michael, you have $1000000.' 格式化整数和浮点数还可以指定是否补0和整数与小数的位数: '%2d-%02d' % (3, 1)----' 3-01' '%.2f' % 3.1415926-----'3.14' %015d ----至少15位(不足高位补0) 如果你不太确定应该用什么,%s永远起作用,它会把任何数据类型转换为字符串: 'Age: %s. Gender: %s' % (25, True)----'Age: 25. Gender: True' 字符串里面的%是一个普通字符怎么办?这个时候就需要转义,用%%来表示一个% 14.有序列表list(可变)和tuple(不可变) list: s = ['first','second','three']//索引从0开始s[0] //还可以-1做索引代表最后一个s[-1]是three、s[-2]、s[-3] s.append('x') s.insert(1,'x') s.pop()//删除末尾元素 s.pop(1)//删除index为1的元素 s[1]='haha'//替换 list里面的元素的数据类型也可以不同,比如: L = ['Apple', 123, True] [] 是空列表 tuple: ()是空tuple (1)定义的不是tuple而是小括号1这个数 所以,只有1个元素的tuple定义时必须加一个逗号,,来消除歧义:(1,) “可变的”tuple: t = ('a', 'b', ['A', 'B']) t[2][0] = 'X' t[2][1] = 'Y' 15.条件判断: if x://只要x是非零数值、非空字符串、非空list等,就判断为True,否则为False print('True')//注意要缩进 16.int()函数把str转换成整数 17.循环有两种:a.for...in循环 b.while循环 names = ['Michael', 'Bob', 'Tracy'] for name in names: print(name) sum = 0 n = 99 while n > 0: sum = sum + n n = n - 2 print(sum) 18. 字典dict,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度 d = {'Michael': 95, 'Bob': 75, 'Tracy': 85} d['Michael']//得到 95 避免key不存在的错误,有两种办法, 一是通过in判断key是否存在:'Thomas' in d 二是通过dict提供的get方法,如果key不存在,可以返回None,或者自己指定的value: d.get('Thomas') d.get('Thomas', -1) pop(key)//删除 dict的key必须是不可变对象 19. set(无序和无重复元素的集合):set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key s = set([1, 2, 3])//传入的参数[1, 2, 3]是一个list add(key) remove(key) 20.字符串可以通过+相连(和java一样) 21.bin()十进制转二进制,hex()十进制转十六进制,oct()十进制转八进制,0b二进制 0x十六进制 0八进制 22.join()方法: fields = [] fields.append('a') fields.append('b') fields.append('c') fields.append('d') print(" ".join(fields))#输出a b c d print(",".join(fields))#输出a,b,c,d
-
函数
1.函数名是指向一个函数对象的引用,可以把函数名赋给一个变量,相当于“别名” eg: a = abs #abs是内置函数取绝对值 a(-1) 2.定义函数: def my_abs(x): #有冒号 if x >= 0: #注意缩进 return x #注意缩进 else: return -x 3.默认参数: def power(x, n=2): power(5)和power(5,2)的结果是一样的 默认参数的坑:L默认是一个空列表,每次调用这个方法L的内容会改变,导致L的内容是改变后的内容 def add_end(L=[]): L.append('END') return L 调用第一次返回['END'] 调用第二次返回['END','END'] ... 解决方法: def add_end(L=None): if L is None: L = [] L.append('END') return L 因为None是不可变对象,所以每次调用只会加一个 调用第一次返回['END'] 调用第二次返回['END'] 4.可变参数(*):在函数调用时自动组装为一个tuple def calc(*numbers): calc(1,2,3) #调用 如果已经有了一个list或tuple,只需要在前面加*就会当成可变参数 nums = [1, 2, 3] calc(*nums) 5.关键字参数(**):可变参数在函数调用时自动组装为一个dict,是参数的拷贝,改变不会影响参数本身 def person(name, age, **kw): print('name:', name, 'age:', age, 'other:', kw) eg:person('Adam', 45, gender='M', job='Engineer') 输出name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'} 如果已经有了一个dict,只需要在前面加**就会当成关键字参数 extra = {'city': 'Beijing', 'job': 'Engineer'} person('Jack', 24, **extra) 6.命名关键字参数 对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数 如果要限制关键字参数的名字,就可以用命名关键字参数 例如,只接收city和job作为关键字参数,定义如下: def person(name, age, *, city, job): #*后面的参数被视为命名关键字参数 print(name, age, city, job) 此时调用函数时必须传递四个参数,并且最后两个字典的key必须分别是 city和job,否则会报错 如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了: def person(name, age, *args, city, job): print(name, age, args, city, job) 命名关键字可以有缺省值: def person(name, age, *, city='Beijing', job): #调用时可以不用传city的字典 7.参数组合 def f1(a, b, c=0, *args, **kw): print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw) 注意 tuple 和 list可以调用 eg: args = (1, 2, 3, 4) kw = {'d': 99, 'x': '#'} f1(*args, **kw) 输出a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'} 8.尾递归 在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况 普通递归: def fact(n): if n==1: return 1 return n * fact(n - 1)#表达式 尾递归: def fact(n): return fact_iter(n, 1) def fact_iter(num, product): if num == 1: return product return fact_iter(num - 1, num * product) #没有表达式,仅返回递归函数本身
-
高级特性
1. 切片(Slice):取一个list或tuple的部分元素 L[0:3]代表取L的[0,3),如果第一个索引为0,还可以省略:L[:3] L[1:len(L)]代表L的[1,L的长度),可以省略为L[1:] L[-1]取倒数第一个元素,L[-2:]代表取后面两个 L[:10:2] 前10个元素 每隔两个取一个 L[::5] 所有元素,每隔五个取一个 对tuple切片得到的结果还是tuple 字符串'xxx'也可以看成是一种list,可以进行切片(类似java中的substring),eg: 'ABCDEFG'[:3] ->'ABC' 2.迭代(for ... in):只要是可迭代对象就可以使用这种方式 dict默认是对key迭代,若要对value 则 for value in dict.values(): 若同时对key value迭代则for k, v in d.items() 字符串也是可迭代对象 eg:for ch in 'ABC': 如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断: from collections import Iterable isinstance('abc', Iterable) # str是否可迭代 输出true 对list实现类似Java那样的下标循环: for i, value in enumerate(['A', 'B', 'C']): print(i, value) #输出0 A (","逗号会输出空格) 1 B 2 C 同时遍历两个变量 for x, y in [[1, 1], [2, 4], [3, 9]]: print(x, y) 3.列表生成式(#注意操作在for前面) list(range(1, 11)) 生成 [1,10] [x * x for x in range(1, 11)] 生成[1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 还可以过滤: [x * x for x in range(1, 11) if x % 2 == 0] 生成[4, 16, 36, 64, 100] 两层循环,可以生成全排列: [m + n for m in 'ABC' for n in 'XYZ']生成 ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'] for循环其实可以同时使用两个甚至多个变量: d = {'x': 'A', 'y': 'B', 'z': 'C' } for k, v in d.items(): print(k, '=', v) 输出:y = B x = A z = C 把一个list中所有的字符串变成小写: L = ['Hello', 'World', 'IBM', 'Apple'] [s.lower() for s in L] #注意操作在for前面 4.生成器(generator):不必创建完整的list,从而节省大量的空间 把一个列表生成式的[]改成(),就创建了一个generator 如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator 每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行,eg定义一个generator,依次返回数字1,3,5: def odd(): yield 1 yield(3) yield(5) for i in odd(): print(i) 输出1 3 5 也可以这样 o = odd() next(o) next(o) next(o) 同样输出1 3 5(到了最后一个元素,再调用next(o)会报错) 5.迭代器(Iterator) 凡是可作用于for循环的对象都是Iterable类型; 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列; 集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。 Python的for循环本质上就是通过不断调用next()函数实现的
-
函数式编程
1.map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回 2. reduce()和map接收参数一样,把结果继续和序列的下一个元素做累积计算eg:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) 3.字符串转int(利用 map 和reduce) from functools import reduce def str2int(s): def fn(x, y): return x * 10 + y def char2num(s): return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s] return reduce(fn, map(char2num, s)) 4.filter()筛选和map接收参数一样,返回也是Iterator惰性序列 5.sorted()函数可以对list进行排序,还可以接收一个参数key函数来实现自定义排序eg:按绝对值排序: sorted([36, 5, -12, 9, -21], key=abs) # 输出 [5, 9, -12, -21, 36] 要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True 6.返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量 def count(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) return fs f1, f2, f3 = count() #此时f1() f2() f3()的结果都是9,因为引用了同一个变量i ,解决办法: def count(): def f(j): def g(): return j*j return g fs = [] for i in range(1, 4): fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f() return fs 7.匿名函数 def f(x): return x * x 等价于 lambda x: x * x 8.装饰器:在不改变某个函数具体实现的情况下,增加函数的功能 def now(): print('2015-3-25') 需要增加打印函数名的功能: def log(func): @functools.wraps(func)#用于把原始函数的__name__等属性复制到wrapper()函数中,否则调用now.__name__会得到 wrapper def wrapper(*args, **kw): print('call %s():' % func.__name__)#__name__是函数对象内置 return func(*args, **kw) return wrapper 使用@ @log def now(): print('2015-3-25') @log 等价于 now = log(now) 输出:call now(): 2015-3-25 如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数eg: def log(text): def decorator(func): def wrapper(*args, **kw): print('%s %s():' % (text, func.__name__)) return func(*args, **kw) return wrapper return decorator 用法: @log('execute') def now(): print('2015-3-25') 9.偏函数(functools.partial):把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单 int()函数默认按十进制转换 int('12345', 8)转化8进制到十进制 import functools int2 = functools.partial(int, base=2)#偏函数,转换二进制到10进制 int2('1000000') 相当于kw = { 'base': 2 } int('10010', **kw) max2 = functools.partial(max, 10)#实际上会把10作为*args的一部分自动加到左边,也就是: max2(5, 6, 7)相当于args = (10, 5, 6, 7) max(*args)
-
模块
1.一个.py文件就是一个模块 2.if __name__=='__main__': #运行本模块会为True,在其他模块导入这个模块时会为False 3.作用域: 正常的函数和变量名是公开的(public)eg:a、b、c 类似_xxx和__xxx这样的函数或变量就是非公开的(private)eg:_a、__b
-
面向对象编程
1.类(class)和实例: class Student(object):#表示Student类继承object def __init__(self, name, score):#第一个参数必须是self,init前后有两个下划线,代表初始化必须传name、score两个参数 self.name = name#public self.__score = score#private 不能直接访问__score是因为Python解释器对外把__score变量改成了_Student__score,所以,仍然可以通过_Student__score来访问__score变量(不建议!!) bart.__score = 20 # 设置__score变量!是给bart新增了一个变量__score 2.type()获取对象的类型 3.类属性(类似java的静态变量) class Student(object): name = 'Student' 4.在类中定义的函数第一个参数永远是实例变量self(self指向创建的实例本身),并且调用时不用传递该参数 5.__init__类似于构造方法,用于创建类时必须传递的参数 6.变量名类似__xxx__的是特殊变量,特殊变量是可以直接访问的,不是private变量 7.dir()获得一个对象的所有属性和方法 8.类似__xxx__的属性和方法在Python中都是有特殊用途的,调用len()函数试图获取一个对象的长度,实际上,在len()函数内部,它自动去调用该对象的__len__() eg: len('ABC') == 'ABC'.__len__() 我们自己写的类,如果也想用len(myObj)的话,就自己写一个__len__()方法 9.给实例绑定属性的方法是通过实例变量,或者通过self变量 10.给类动态绑定方法: def set_age(self, age): # 定义一个函数作为实例方法 self.age = age from types import MethodType s.set_age = MethodType(set_age, s) # 给实例绑定一个方法 s.set_age(25) # 调用实例方法 s.age # 测试结果 输出25 但是,给一个实例绑定的方法,对另一个实例是不起作用的,解决方法给class绑定: def set_score(self, score): self.score = score Student.set_score = set_score
-
面向对象高级编程
1.动态绑定允许我们在程序运行的过程中动态给class加上功能: def set_score(self, score): self.score = score Student.set_score = set_score #动态绑定方法 s = Student() s.set_score(100) s.score 2.__slots__限制实例可绑定的属性(仅对当前类实例起作用,对继承的子类不起作用) class Student(object): __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称 s = Student() # 创建新的实例 s.name = 'Michael' # 绑定属性'name' s.age = 25 # 绑定属性'age' s.score = 99 # 绑定属性'score'会报错 3.多继承 class Dog(Mammal, Runnable): 4.__str__ 类似java 的toString方法 class Student(object): def __init__(self, name): self.name = name def __str__(self): return 'Student object (name: %s)' % self.name 使用:print(Student('Michael')) 输出 Student object (name: Michael) 直接显示变量调用的不是__str__(),而是__repr__()(可以令__repr__ = __str__) 5.__iter__ 使一个类可用于for ... in循环 class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化两个计数器a,b def __iter__(self): return self # 实例本身就是迭代对象,故返回自己 def __next__(self): self.a, self.b = self.b, self.a + self.b # 计算下一个值 if self.a > 100000: # 退出循环的条件 raise StopIteration() return self.a # 返回下一个值 6.__getitem__使一个类可按照下标取出元素 7.__getattr__使可以访问一个非类的属性 class Student(object): def __init__(self): self.name = 'Michael' def __getattr__(self, attr): if attr=='score': return 99 Student().score 实例:链式调用 class Chain(object): def __init__(self, path=''): self._path = path def __getattr__(self, path): return Chain('%s/%s' % (self._path, path)) def __str__(self): return self._path __repr__ = __str__ Chain().status.user.timeline.list #输出:'/status/user/timeline/list' 8.__call__ 使得对象方便的调用方法 class Student(object): def __init__(self, name): self.name = name def __call__(self): print('My name is %s.' % self.name) 调用:s = Student('neo') s() #输出My name is neo 所以你完全可以把对象看成函数,把函数看成对象 通过callable()函数,我们就可以判断一个对象是否是“可调用”对象. 9.枚举 from enum import Enum Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')) 直接使用Month.Jan来引用一个常量,枚举它的所有成员: for name, member in Month.__members__.items(): print(name, '=>', member, ',', member.value) 10.type()函数既可以返回一个对象的类型,又可以创建出新的类型 返回类型: from hello import Hello h = Hello() h.hello()#Hello, world. print(type(Hello))#<class 'type'> Hello是一个class,它的类型就是type print(type(h))#<class 'hello.Hello'> h是一个实例,它的类型就是hello.py模块下的 Hello类 创建类型: def fn(self, name='world'): # 先定义函数 print('Hello, %s.' % name) Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class h = Hello() h.hello()#Hello, world. print(type(Hello))#<class 'type'> print(type(h))#<class '__main__.Hello'> # __main__模块的Hello类 type()函数参数: 1.class的名称; 2.继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法; 3.class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。 11.元类metaclass(可以把类看成是metaclass创建出来的“实例”) # metaclass是类的模板,所以必须从`type`类型派生: class ListMetaclass(type): def __new__(cls, name, bases, attrs): attrs['add'] = lambda self, value: self.append(value) return type.__new__(cls, name, bases, attrs) class MyList(list, metaclass=ListMetaclass):#说明Python创建MyList会去调用元类ListMetaclass的__new__方法 pass L = MyList() L.add(1) print(L)#输出[1] __new__()方法接收到的参数依次是: 1.当前准备创建的类的对象; 2.类的名字; 3.类继承的父类集合; 4.类的方法集合。 12.使用@property:@property装饰器就是负责把一个方法变成属性调用。 class Student(object): @property def birth(self): return self._birth#下划线开头的变量名是可以外部直接方法的(但是不建议这么做) @birth.setter #@property内部创建的:方法名.setter def birth(self, value): self._birth = value @property def age(self): return 2015 - self._birth birth是可读写属性,而age就是一个只读属性 s = Student() s.birth = 12#等同于s.birth(12) .方法名 s.birth #等同于s.birth() 13.python可以多继承
-
错误、调试、测试
1. try: print('try...') r = 10 / int('2') print('result:', r) except ValueError as e: print('ValueError:', e) except ZeroDivisionError as e: print('ZeroDivisionError:', e) else: print('no error!') finally: print('finally...') 2. raise类似java的throw logging类似Log 3. pdb命令行方式进行调试
-
IO编程
1.文本文件(默认utf-8) try: f = open('/Users/neo/fps.txt', 'r',encoding='gbk')#'r'表示读 print(f.read()) finally: if f: f.close()#及时关闭 等价于 with open('/Users/neo/fps.txt', 'r') as f: print(f.read())#不用close read()一次性读取全部内部到内存有危险,可反复调用read(size)方法 2.二进制文件 f = open('/Users/michael/test.jpg', 'rb') 3. StringIO:在内存中读写str from io import StringIO f = StringIO() f.write('hello') f.write(' ') f.write('world!') print(f.getvalue())#输出hello world! from io import StringIO f = StringIO('Hello!\nHi!\nGoodbye!') while True: s = f.readline() if s == '': break print(s.strip())#输出Hello! Hi! Goodbye! 4.BytesIO:用法和StringIO类似,是内存中读写字节 5.import os os.path.abspath('.')# 查看当前目录的绝对路径: os.path.join('/Users/neo', 'testdir')# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来: os.mkdir('/Users/neo/testdir')# 然后创建一个目录: os.rmdir('/Users/neo/testdir')# 删掉一个目录: os.rename('test.txt', 'test.py')# 对文件重命名: os.remove('test.py')# 删掉文件: 5.列出所有的.py文件 [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py'] 6. pickling序列化(利用pickle模块) 对象到JSON格式的转换(json模块) import json d = dict(name='Bob', age=20, score=88) print(json.dumps(d))#输出{"name": "Bob", "age": 20, "score": 88} JSON转为对象 import json json_str = '{"age": 20, "score": 88, "name": "Bob"}' persion = json.loads(json_str) print(persion['age'])#输出20 7.json模块序列化类 import json class Student(object): def __init__(self, name, age, score): self.name = name self.age = age self.score = score def student2dict(std): return { 'name': std.name, 'age': std.age, 'score': std.score} s = Student('Bob', 20, 88) print(json.dumps(s,default=student2dict)) print(json.dumps(s, default=lambda obj: obj.__dict__))#把任意class的实例变为dict 反序列化: import json class Student(object): def __init__(self, name, age, score): self.name = name self.age = age self.score = score def dict2student(d): return Student(d['name'], d['age'], d['score']) json_str = '{"age": 20, "score": 88, "name": "Bob"}' print(json.loads(json_str, object_hook=dict2student))
-
进程和线程
1.Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次, 但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程(返回子进程id)和子进程(返回0)内返回 import os print('Process (%s) start...' % os.getpid()) # Only works on Unix/Linux/Mac: pid = os.fork() if pid == 0: print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())) else: print('I (%s) just created a child process (%s).' % (os.getpid(), pid)) 输出Process (1812) start... I (1812) just created a child process (1813). I am child process (1813) and my parent is 1812. 2.Windows没有fork,可使用multiprocessing模块 from multiprocessing import Process import os # 子进程要执行的代码 def run_proc(name): print('Run child process %s (%s)...' % (name, os.getpid())) if __name__=='__main__': print('Parent process %s.' % os.getpid()) p = Process(target=run_proc, args=('test',)) print('Child process will start.') p.start() p.join()#等待子进程结束后再继续往下运行 print('Child process end.') 3.多线程(使用threading模块) import time, threading # 新线程执行的代码: def loop(): print('thread %s is running...' % threading.current_thread().name) n = 0 while n < 5: n = n + 1 print('thread %s >>> %s' % (threading.current_thread().name, n)) time.sleep(1) print('thread %s ended.' % threading.current_thread().name) print('thread %s is running...' % threading.current_thread().name) t = threading.Thread(target=loop, name='LoopThread') t.start() t.join()#主线程等待子线程执行完毕 print('thread %s ended.' % threading.current_thread().name) 4.锁:lock = threading.Lock() lock.acquire()#获取锁 lock.release()#一定要手动释放锁 5.Python解释器由于设计时有GIL全局锁,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码, 解释器就自动释放GIL锁,让别的线程有机会执行,导致了多线程无法利用多核(可以使用多进程) 6. ThreadLocal import threading # 创建全局ThreadLocal对象: local_school = threading.local() def process_student(): # 获取当前线程关联的student: std = local_school.student print('Hello, %s (in %s)' % (std, threading.current_thread().name)) def process_thread(name): # 绑定ThreadLocal的student: local_school.student = name process_student() t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A') t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B') t1.start() t2.start() t1.join() t2.join() 输出Hello, Alice (in Thread-A) Hello, Bob (in Thread-B)
-
正则表达式
1. \d:匹配一个数字 \w:匹配一个字母或数字 \s:匹配一个空格(也包括Tab等空白符) 2.匹配变长的字符: *表示任意个字符(包括0个) +表示至少一个字符 ?表示0个或1个字符 {n}表示n个字符,用{n,m}表示n-m个字符 3.需要转义的字符: _ :\_ 4.表示范围:[] [0-9a-zA-Z\_]可以匹配一个数字、字母或者下划线 [0-9a-zA-Z\_]+可以匹配至少由一个数字、字母或者下划线组成的字符串,比如'1','a100','0_Z','Py3000'等等 5.^表示行的开头,^\d表示必须以数字开头。 $表示行的结束,\d$表示必须以数字结束。 6.re模块 判断是否匹配: import re if re.match(r'^\d{3}\-\d{3,8}$', '010-12345'): print('yes') else: print('no') 输出yes �切分字符串:
-
网络编程
1.网络通信其实就是两个进程通信 2.如果一台计算机同时接入到两个或更多的网络,比如路由器,它就会有两个或多个IP地址,所以,IP地址对应的实际上是计算机的网络接口,通常是网卡 3.IP地址实际上是一个32位整数(称为IPv4),以字符串表示的IP地址如192.168.0.1实际上是把32位整数按8位分组后的数字表示,目的是便于阅读 4.IPv6地址实际上是一个128位整数 5.IP协议负责把数据从一台计算机通过网络发送到另一台计算机 6.TCP协议则是建立在IP协议之上的。TCP协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP协议会通过握手建立连接,然后,对每个IP包编号,确保对方按顺序收到,如果包丢掉了,就自动重发 7.HTTP协议基于TCP协议 8.端口的作用:同一台计算机上跑着多个网络程序。一个IP包来了之后,到底是交给浏览器还是QQ,就需要端口号来区分 9、端口号小于1024的是Internet标准服务的端口,端口号大于1024的,可以任意使用 10.UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包,不可靠、速度快
-
电子邮件
1.Email从MUA(Mail User Agent--电子邮件软件)发出去,发到发件人邮箱所属的MTA:Mail Transfer Agent——邮件传输代理(Email服务提供商), 从发件人所属的MTA发送到目标邮件地址所属的MTA(这个过程中间可能还会经过别的MTA), 目标地址所属的MTA会把邮件发送到最终目的地MDA:Mail Delivery Agent——邮件投递代理,Email到达MDA后,就静静地躺在目标服务器,等待MUA从MDA中取邮件 2.发邮件时,MUA和MTA使用的协议就是SMTP 3.收邮件时,MUA和MDA使用的协议有两种:POP3、IMAP4 4.MUA在发邮件时,要先配置SMTP服务器,也就是你要发到哪个MTA上 假设你正在使用163的邮箱,你就不能直接发到新浪的MTA上,因为它只服务新浪的用户, 所以,你得填163提供的SMTP服务器地址:smtp.163.com,为了证明你是163的用户,SMTP服务器还要求你填写邮箱地址和邮箱口令 类似的,从MDA收邮件时,Outlook之类的邮件客户端会要求你填写POP3或IMAP服务器地址、邮箱地址和口令 from email.mime.text import MIMEText msg = MIMEText('hello, send by Python...', 'plain', 'utf-8') # 输入Email地址和口令: from_addr = '755766986@qq.com' password = 'iwfcltqyzjbpbbjj' # 输入收件人地址: to_addr = '578179809@qq.com' # 输入SMTP服务器地址: smtp_server = 'smtp.qq.com' import smtplib server = smtplib.SMTP(smtp_server, 587) # SMTP协议默认端口是25 server.set_debuglevel(1) server.starttls() server.login(from_addr, password) server.sendmail(from_addr, [to_addr], msg.as_string()) server.quit()
-
访问数据库
# -*- coding: utf-8 -*- # 导入MySQL驱动: import mysql.connector # 注意把password设为你的root口令: conn = mysql.connector.connect(user='root', password='zq112hf', database='test') cursor = conn.cursor() # 创建user表: cursor.execute('create table IF NOT EXISTS user (id varchar(20) primary key, name varchar(20))') # 插入一行记录,注意MySQL的占位符是%s: cursor.execute('insert into user (id, name) values (%s, %s)', ['2', 'Michael']) print('cursor.rowcount = %d'%cursor.rowcount) # 提交事务: conn.commit() cursor.close() # 运行查询: cursor = conn.cursor() cursor.execute('select * from user where id = %s', ('2',)) values = cursor.fetchall() print(values) # 关闭Cursor和Connection: cursor.close() conn.close()
Web开发
1.Python内置了一个WSGI(Web Server Gateway Interface)服务器:wsgiref模块,效率比较低,仅供开发和测试使用
# server.py
# 从wsgiref模块导入:
from wsgiref.simple_server import make_server
# 导入我们自己编写的application函数:
from hello import application
# 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')
# 开始监听HTTP请求:
httpd.serve_forever()
# hello.py
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, web!</h1>']
运行server.py来启动WSGI服务器
2.Web框架-Flask。每个请求对于一个方法
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def home():
return '<h1>Home</h1>'
@app.route('/signin', methods=['GET'])
def signin_form():
return '''<form action="/signin" method="post">
<p><input name="username"></p>
<p><input name="password" type="password"></p>
<p><button type="submit">Sign In</button></p>
</form>'''
@app.route('/signin', methods=['POST'])
def signin():
# 需要从request对象读取表单内容:
if request.form['username']=='admin' and request.form['password']=='password':
return '<h3>Hello, admin!</h3>'
return '<h3>Bad username or password.</h3>'
if __name__ == '__main__':
app.run()
3. 使用模板
在Jinja2模板中:
{{ name }}:需要替换的变量
{% ... %}:指令
- 异步IO
1.异步IO模型需要一个消息循环,在消息循环中,主线程不断地重复“读取消息-处理消息”过程
当遇到IO操作时,代码只负责发出IO请求,不等待IO结果,然后直接结束本轮消息处理,进入下一轮消息处理过程。
当IO操作完成后,将收到一条“IO完成”的消息,处理该消息时就可以直接获取IO操作结果
2.协程:一个线程执行,效率高(子程序切换不是线程切换、不需要锁)
协程通过generator实现(包含yield关键字的方法就是一个generator,不知道这样理解对不对)
def consumer():#generator
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK'
def produce(c):#参数是一个generator
c.send(None)
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
x = c.send(n)
print('[PRODUCER] Consumer return: %s' % x)
c.close()
c = consumer()#把generator赋值给变量c
produce(c)
执行过程:
1.首先调用c.send(None)启动生成器(generator);
2.然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
3.consumer通过yield拿到消息,处理,又通过yield把结果传回(就是给consumer()的r赋值);
4.produce拿到consumer处理的结果(上面的x),继续生产下一条消息;
5.produce决定不生产了,通过c.close()关闭consumer,整个过程结束
3. asyncio内置了对异步IO的支持(消息循环)
import asyncio
@asyncio.coroutine#标记为coroutine
def hello():
print("Hello world!")
# 异步调用asyncio.sleep(1):
r = yield from asyncio.sleep(1)#执行到这里会直接中断并去执行EventLoop中其他可以执行的coroutine
#过了1秒返回一个None(r = None),CPU再来执行后面的代码
print("Hello again!")
# 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
loop.run_until_complete(hello())#把协程放到消息队列里执行,如果有多个使用wait:asyncio.wait([hello(),A(),B()])
loop.close()#记得关闭循环
4.Python 3.5开始
@asyncio.coroutine = async
yield from = await
5. aiohttp则是基于asyncio实现的HTTP框架
import asyncio
from aiohttp import web
async def index(request):
await asyncio.sleep(0.5)
return web.Response(body=b'<h1>Index</h1>')
async def hello(request):
await asyncio.sleep(0.5)
text = '<h1>hello, %s!</h1>' % request.match_info['name']
return web.Response(body=text.encode('utf-8'))
async def init(loop):
app = web.Application(loop=loop)
app.router.add_route('GET', '/', index)
app.router.add_route('GET', '/hello/{name}', hello)
srv = await loop.create_server(app.make_handler(), '127.0.0.1', 8000)
print('Server started at http://127.0.0.1:8000...')
return srv
loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()
- 其他
1.with关键字的用法:
with expression as variable:
with block
该代码快的执行过程是: 1.先执行expression,然后执行该表达式返回的对象实例的__enter__函数,然后将该函数的返回值赋给as后面的变量。(注意,是将__enter__函数的返回值(返回expression的值)赋给变量)
2.然后执行with block代码块,不论成功,错误,异常,在with block执行结束后,会执行第一步中的实例的__exit__函数。)
2.