基本数据结构
1 列表:List [ ] 类似于数组
2 元祖 :tuple () 元素不可变,可存放不同类型的元素
tuple[0] 基本和列表相同 t(5,)只包含一个元素的元祖
我觉得python这一点很不合理
python格式化输出 print('%d'%20)中间没有逗号 %d十进制 并且有两个% 两个%
print('%.3f'%0.23454) f float数输出3前面有个点
字符串输出 %s %.2s截取两位字符
常见格式代码 %s字符串 %d十进制 %%字符%
常见转义 字符
\行末 续行符 \\代表\ \“ \n \r
相对于基本格式化输出 % ,format()功能更加强大 该函数把字符串当成一个模板,通过传入的参数进行格式化,并且使用大括号‘{}’作为特殊字符代替‘%’
>>> print('{} {}'.format('hello','world')) # 不带字段
hello world
>>> print('{0} {1}'.format('hello','world')) # 带数字编号
hello world
>>> print('{0} {1} {0}'.format('hello','world')) # 打乱顺序
hello world hello
>>> print('{1} {1} {0}'.format('hello','world'))
world world hello
>>> print('{a} {tom} {a}'.format(tom='hello',a='world')) # 带关键字
world hello world
>>> '{0}, {1}, {2}'.format('a', 'b', 'c')
'a, b, c'
>>> '{}, {}, {}'.format('a', 'b', 'c') # 3.1+版本支持
'a, b, c'
>>> '{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'
>>> '{2}, {1}, {0}'.format(*'abc') # 可打乱顺序
'c, b, a'
>>> '{0}{1}{0}'.format('abra', 'cad') # 可重复
'abracadabra'
通过位置匹配
print("用户数量:%d,男性人数:%d,女性人数:%d,职业数量:%d,地区数量:%d" % (num_users, num_genders_male,num_genders_female, num_occupations, num_zipCode)) 多个一起输出
并发 任务数大于 cpu核数
并行 任务数小于等于cpu核数
多线程 import threading
t1=threading.Thread(target=methodName,args=(100,))
or
#继承 threading.Thread
class MyThread(threading.Thread):
def run(self):
xxxxx
self.login() #调用其他方法
t1=MyThread()
t1.start()
#多线程锁
mutex=threading.Lock()
mutex.acquire()
mutex.release()
#注意不要有死锁,即两个线程互相等待,
多进程:
import multiprocessing
p1=multiprocessing.Process(target=test)
p1.start()
多进程,多线程区别
进程包括线程
多进程:多份资源 ,运行多份任务,每个进程里面有一个主线程,类似与qq多开
多线程:一份资源,多个任务,包括主线程,子线程,qq 发消息,接受文件
进程需要的资源比较大点
进程间独立的,线程间可以共享全局变量
所以进程间通信需要通信,可以采用socket,
Queue() 队列解耦
迭代器:是否可迭代 isinstance(xxx,Iterable)
迭代器必须要有__iter__方法 和__next__方法 迭代和取下一次的值
如例子
import time
class ClassMate(object):
def __init__(self):
self.names=list()
self.current_num=0
def add(self,name):
self.names.append(name)
def __iter__(self):
return self
def __next__(self):
if self.current_num < len(self.names):
result=self.names[self.current_num]
self.current_num+=1
return result
else:
raise StopIteration
classmate=ClassMate()
classmate.add(1)
classmate.add(2)
classmate.add(3)
classmate.add(4)
for name in classmate:
print(name)
time.sleep(0.5)
迭代器 存储的是生产数据的方式,而不是全部的数据,如果数据很大,根本装不下,所以需要迭代器,随用随取
如著名的斐波那契数列的生产方式
第一种:把所有的数据装到一个列表里面
nums=list()
a=0
b=1
i=0
while i <15:
nums.append(a)
a,b=b,a+b
i+=1
for num in nums:
print(num)
第二种通过迭代的方式进行产生:
class fbnq(object):
def __init__(self,numsCount):
self.numsCount=numsCount
self.current_num=0
self.a=0
self.b=1
def __iter__(self):
return self
def __next__(self):
if self.current_num < self.numsCount:
ret=self.a
self.a,self.b=self.b,self.a+self.b
self.current_num+=1
return ret
else:
raise StopIteration
fb=fbnq(10)
for f in fb:
print(f)
生成器:特殊的迭代器
第一种方式:将列表推导式 nums=[x*2 for x in range(10)] 的[] 换成 ()即可
nums=((x*2 for x in range(10))) 第二种为生成器 一个对象而不是数据可以调用for循环去数据
第二种占用空间小
第二种方式 在函数中通过yield 一旦函数中有yield即为生成器。生成器的食用方法如下:
def create_num(num_count):
a, b=0, 1
current_num=0
while current_num< num_count:
yield a # 生成器是一个特殊的迭代器,调用next方法,返回a 下次再调用继续从上次执行的地方继续 ,可以看作是函数在此暂停
#yield将值返回,暂停,在继续从上次暂停的地方继续
a, b=b,a+b
current_num +=1
obj=create_num(10)
for num in obj:
print(num)
迭代器 生成器(特殊迭代器,yield) 生产数据的代码,而不是直接结果数据,生成器保证执行一部分暂停,
协程 占用资源 进程> 线程>携程 效率高反过来
下面这个例子是一个进程内,一个线程间隔的暂停现在这个任务(遇到yield)去执行另外一个方法
import time
def task_1():
while True:
print("----1----")
time.sleep(0.1)
yield
def task_2():
while True:
print("----2----")
time.sleep(0.1)
yield
def main():
t1=task_1()
t2=task_2()
while True:
next(t1)
next(t2)
if __name__ == '__main__':
main()
#或者可以采用greenlet 封装了 yield
from greenlet import greenlet
import time
def test1():
while True:
print("A")
gr2.switch()
time.sleep(0.1)
def tet2():
while True:
print("B")
gr1.switch()
time.sleep(0.1)
gr1=greenlet(test1)
gr2=greenlet(tet2)
gr1.switch()
#gevent是对greenlet的封装
只有在延时操作时才会切换,多任务 gevent.sleep(0.5) gevent的延时
也可以用time.sleep() 但是需要打补丁 from gevent import monkey
monkey.patch_all()
import gevent
import time
def f1(n):
for i in range(n):
print(gevent.getcurrent(),i)
# time.sleep(0.5)
gevent.sleep(0.5)
def f2(n):
for i in range(n):
print(gevent.getcurrent(),i)
# time.sleep(0.5)
gevent.sleep(0.5)
def f3(n):
for i in range(n):
print(gevent.getcurrent(),i)
# time.sleep(0.5)
gevent.sleep(0.5)
print("11111111111111")
g1=gevent.spawn(f1,5)
print("22222222222222")
g2=gevent.spawn(f2,5)
print("33333333333333")
g3=gevent.spawn(f3,5)
print("44444444444444")
g1.join()
g2.join()
g3.join()
print("a")
print("b")
print("c")
print("a")
print("b")
print("c")
不是多任务 ,多任务指的是同时执行多个任务而不是执行完一个任务在去执行另外的任务
print("a")
print("a")
print("b")
print("b")
print("c")
print("c")
进程里面线程结束协程也要完蛋
程序运行起来称之为进程,进程是资源分配的单位,线程执行代码,一个线程只能做一件算,多任务多线程,
单线程也可以进行多任务,利用的是任务的等待时间去做其他的时间即协程,
协程依赖线程,线程依赖进程
协程是利用单线程在进行某项耗时任务时的时间去做别的事情例如网络堵塞
以上是在不考虑GIL的情况下(全局解释锁) pass 占位符 空的相当与一条语句
python的多线程是个假的,假的假的都是假的因为GIL锁,多个线程不会占用多个cpu
python的解释器c语言版 存在GIL问题导致,pytho多线程会GIL,即同一时刻只有一个线程在运行,历史原因
但是python多线程还是比单线程快,在网络通信下,等待
IO密集型读写网络等(采用多线程协程,只有一个核在用),计算密集型(用进程)
解决GIL,换取c语言解释器,用其他语言实现
深浅拷贝:普通的赋值就是浅拷贝 ,浅拷贝类似与cp的快捷方式 ,深拷贝完全拷贝,类似于linux 软硬链接
python中
a=[11,22]
b=a
实际上 给b的是a指向的引用,只是一个引用并没有实际赋值 浅拷贝
>>> a
[11, 22]
>>> b
[11, 22]
>>> id(a)
139814218076232
>>> id(b)
139814218076232
深拷贝
>>> import copy
>>> c=copy.deepcopy(a)
>>> id(a)
139814218076232
>>> id(c)
139814217260488
>>>
>>> a.append(3)
>>> a
[1, 2, 3]
>>> b
[1, 2, 3]
>>> c
[1, 2]
c 和e不同 e有两种情况,指向原来的a,b 2 直接拷贝一份a ,b
需要通过 id(c[0]) id(e[0])来判断 结果为第一个浅拷贝 copy.copy() 只拷贝最上面的一层
import copy
如果用copy.copy ,copy.deepcopy 对一个全部都是不可变类型的数据进行拷贝,那么他们的结果相同,都是引用指向
切片也是浅拷贝
字典拷贝的时候,value是共享的,即value是浅拷贝 但是整体id(a)!=id(b)
两个下划线开头为私有,子类不会继承
前后都有两个下划线依然公有子类会继承如 __init__ __iter__
一个下划线开头的,在其他包里面无法导入