1,for 删除中的问题
list1 = [1,2,3,4,5,6]
for i in list1:
list1.remove(i)
print(i)
print(list1)
for 语句如何循环的呢?步骤是:
(1)先判断对象是否为可迭代对象,不是的话直接报错,抛出TypeError异常,是的话,调用 __iter__或iter方法,返回一个迭代器
(2)不断地调用迭代器的__next__或next方法,每次按序返回迭代器中的一个值
(3)迭代到最后,没有更多元素了,就抛出异常 StopIteration,这个异常 python 自己会处理,不会暴露给开发者
因为执行for语句时,先生成一个迭代器,再用next方法,按序返回迭代器中的值,
当列表中删除了元素2时,元素3的索引变成了原来元素2的索引,
把元素3往前推到了元素2的位置,所以next方法就没返回值3.
2.提高numpy运行速度
import time
def foo(x,y):
tt = time.time()
s = 0
for i in range(x,y):
s += i
print('Time used: {} sec'.format(time.time()-tt))
return s
print(foo(1,100000000))
# 修改后
from numba import jit
import time
@jit
def foo(x,y):
tt = time.time()
s = 0
for i in range(x,y):
s += i
print('Time used: {} sec'.format(time.time()-tt))
return s
print(foo(1,100000000))
numba中提供了一些修饰器,它们可以将其修饰的函数JIT编译成机器码函数,并返回一个可在Python中调用机器码的包装对象。为了能将Python函数编译成能高速执行的机器码,我们需要告诉JIT编译器函数的各个参数和返回值的类型。
JIT所产生的函数只能对指定的类型的参数进行运算
如果希望JIT能针对所有类型的参数进行运算,可以使用autojit:
Numba和Jupyter更适合适合GPU计算的实验
Numba可以同时为CPU和GPU编译
Numba + Jupyter =快速CUDA原型开发
3.文件的读取
# 方法一:
# glob.glob 匹配全部后缀为.csv的文件(生成为列表)
"""
glob: 返回所有匹配的文件路径列表(list);
其返回的文件名只包括当前目录里的文件名,不包括子文件夹里的文件
"""
for i in glob.glob('./*.csv'):
fp = pd.read_csv(i)
# 写入成csv文件\
fp.to_csv('city_ocean.csv',mode='a',index=False)
方法二:
os.walk(): 可以遍历文件夹下所有的文件
os.walk(top, topdown=Ture, onerror=None, followlinks=False)
该函数可以得到一个三元tupple(dirpath, dirnames, filenames).
- dirpath:string,代表目录的路径;
- dirnames:list,包含了当前dirpath路径下所有的子目录名字(不包含目录路径);
- filenames:list,包含了当前dirpath路径下所有的非目录子文件的名字(不包含目录路径)。
import os
def file_name(file_dir):
for root, dirs, files in os.walk(file_dir):
print(root) #当前目录路径
print(dirs) #当前路径下所有子目录
print(files) #当前路径下所有非目录子文件
# 当需要特定类型的文件时
def file_name(file_dir):
L=[]
for root, dirs, files in os.walk(file_dir):
for file in files:
if os.path.splitext(file)[1] == '.jpeg':
L.append(os.path.join(root, file))
return L
python3实现链表
python是动态语言,可以直接把对象赋值给新的变量。在C/C++中,通常采用“指针+结构体”来实现链表;而在Python中,则可以采用“引用+类”来实现链表。
链表的定义:是一组数据项的集合,其中每个数据项都是一个节点的一部分,每个节点还包含指向下一个节点的链接
链表的结构:data为自定义的数据,next为下一个节点的地址。
基本元素:
- 节点:每个节点有两个部分,左边部分称为值域,用来存放用户数据;右边部分称为指针域,用来存放指向下一个元素的指针。
- head:head节点永远指向第一个节点
- tail: tail永远指向最后一个节点
- None:链表中最后一个节点的指针域为None值
# 链表结构实现 私有属性_pro_item是指向下个节点的指针,_item为此节点的值
class ChainDemo():
def __init__(self,item = None,pos_item=None):
self._item = item
self._pos_item = pos_item
if __name__ == '__main__':
chain = ChainDemo('A',(ChainDemo('B',ChainDemo('C',ChainDemo('D')))))
while True:
print(chain._item)
if chain._pos_item != None:
chain = chain._pos_item
else:
break
2、实现对链表的操作(增删)
#链表节点结构实现 私有属性_pro_item是指向下个节点的指针,_item为此节点的值
class Node():
def __init__(self,item = None,pos_item=None):
self._item = item
self._next = pos_item
def __repr__(self):
'''
用来定义Node的字符输出,
print为输出item
'''
return str(self._item)
#单链表实现
class Chain():
def __init__(self):
self._head = None
self.length = 0
#判空
def isEmpty(self):
return self.length == 0
#链表结尾插入
def append(self,item):
if isinstance(item,Node):
node = item
else:
node = Node(item)
if self._head == None:
self._head = node
else:
be_node = self._head
while be_node._next:
be_node = be_node._next
be_node._next = node
self.length += 1
#插入数据
def insert(self,index,item):
if self.isEmpty():
print('this chain table is empty')
return
if index<0 or index >= self.length:
print("error: out of index")
return
in_node = Node(item)
node = self._head
count = 1
while True:
node = node._next
count += 1
if count == index:
next_node = node._next
node._next = in_node
in_node._next = next_node
self.length += 1
return
# node = s
#删除数据
def delete(self,index):
if self.isEmpty():
print('this chain table is empty')
return
if index<0 or index >= self.length:
print("error: out of index")
return
# if index == 0
# self._head = None
else:
node = self._head
count = 0
while True:
count += 1
if index == count:
node._next = node._next._next
break
node = node._next
self.length -= 1
def __repr__(self):
if self.isEmpty():
print("the chain table is empty")
return
nlist = ""
node = self._head
while node:
nlist += node._item +''
node = node._next
return nlist
if __name__ == '__main__':
chain = Chain()
chain.append('A')
chain.append('B')
chain.append('C')
chain.append('D')
chain.append('E')
chain.append('F')
chain.append('G')
chain.insert(4,'p')
chain.delete(3)
print(chain,chain._head._item,chain.length)
4.mysql操作(事务、游标)案例
1. mysql事务
MySQL事务主要用于处理操作量大,复杂度高的数据。
比如,你操作一个数据库,公司的一个员工离职了,你要在数据库中删除他的资料,也要删除该人员相关的,比如邮箱,个人资产等。这些数据库操作语言就构成了一个事务。
mysql事务的方法
commit():提交当前事务,如果是支持事务的数据库执行增删改后没有commit则数据库默认回滚,白操作了
rollback():取消当前事务
2.游标
游标(cursor)
游标是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果
用户可以用SQL语句逐一从游标中获取记录,并赋给主变量,交由python进一步处理,一组主变量一次只能存放一条记录
常用方法:
cursor():创建游标对象
close():关闭此游标对象
案例
两人相互转账,
1, 检查账户是否存在合法
2, 检查转账金额与余额适合合理
3, 检查账户加钱,减钱是否成功
4, 任何一步发生错误的时候就进行回滚
import pymysql
# 定义一个函数类
class TransferMoney(object):
def __init__(self,conn):
self.conn = conn
# 检查账户是否合法text02.py:
def check_acct_avaiable(self,acctid):
# 游标
cursor = self.conn.cursor()
try:
sql = "select * from account where acctid=%s" % acctid
cursor.execute(sql)
print ("检查账户:" + sql)
rs = cursor.fetchall()
# print(len(rs))
if len(rs) != 1:
raise Exception("账户 %s 是不合法的" % acctid)
finally:
cursor.close()
# 检查是否有足够的钱
def has_enough_money(self,acctid,money):
cursor = self.conn.cursor()
try:
sql = "select * from account where acctid=%s and money > %s" % (acctid,money)
cursor.execute(sql)
print ("有足够的money:" + sql)
rs = cursor.fetchall()
if len(rs) != 1:
raise Exception("账户 %s 没有足够的余额" % acctid)
finally:
cursor.close()
# 账户减钱
def reduce_money(self,acctid,money):
cursor = self.conn.cursor()
try:
sql = "update account set money = money-%s where acctid = %s" % (money,acctid)
cursor.execute(sql)
print ("减钱:" + sql)
if cursor.rowcount != 1:
raise Exception("减钱失败 %s" % acctid)
finally:
cursor.close()
# 账户加钱
def add_money(self,acctid,money):
cursor = self.conn.cursor()
try:
sql = "update account set money = money+%s where acctid = %s" % (money,acctid)
cursor.execute(sql)
print ("加钱:" + sql)
if cursor.rowcount != 1:
raise Exception("加钱失败 %s" % acctid)
finally:
cursor.close()
# 主执行语句
def transfer(self,source_acctid,target_acctid,money):
try:
# 检查给钱的账户
self.check_acct_avaiable(source_acctid)
# 检查收钱的账户
self.check_acct_avaiable(target_acctid)
# 检查是否有足够的钱
self.has_enough_money(source_acctid,money)
# 账户减钱
self.reduce_money(source_acctid,money)
# 账户加钱
self.add_money(target_acctid,money)
self.conn.commit()
except Exception as e:
self.conn.rollback() # 事物回滚
raise e
# 程序执行文件
if __name__ == "__main__":
source_acctid = '1'
target_acctid = '2'
money = '100'
# 连接数据库
conn = pymysql.Connect(host='127.0.0.1', port=3306, user='root', password='123456', database='tencent', charset='utf8')
tr_money = TransferMoney(conn)
try:
tr_money.transfer(source_acctid,target_acctid,money)
except Exception as e:
print ("Happen:" + str(e))
finally:
conn.close()
4. 全局解释器锁
GIL的全称为Global Interpreter Lock,全局解释器锁。
在 Python 语言的主流实现 CPython 中,GIL 是一个货真价实的全局线程锁,在解释器解释执行任何 Python 代码时,都需要先获得这把锁才行,在遇到 I/O 操作时会释放这把锁。
如果是纯计算的程序,没有 I/O 操作,解释器会每隔 100 次操作就释放这把锁,让别的线程有机会执行
有在做IO操作时,GIL总是被释放。对所有面对内建的操作系统C代码的程序来说,GIL会在这个IO调用之前被释放,以允许其它的线程在等待这个IO的时候运行。如果是纯计算的程序,没有IO操作,解释器会每隔100次或每隔一定时间15ms去释放GIL。
GIL对线程执行的影响
多线程环境中,python虚拟机按照以下方式执行:
- 设置GIL
- 切换到一个线程去执行
- 运行代码,这里有两种机制:
- 指定数量的字节码指令(100个)
- 固定时间15ms线程主动让出控制
- 把线程设置为睡眠状态
- 解锁GIL
- 再次重复以上步骤
python中GIL使得同一个时刻只有一个线程在一个cpu上执行,无法将多个线程映射到多个cpu上执行,但GIL并不会一直占有,它会在适当的时候释放
import threading
count = 0
def add():
global count
for i in range(10**6):
count += 1
def minus():
global count
for i in range(10**6):
count -= 1
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=minus)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(count)
# 结果
# -59452
# 60868
# -77007
可以看到count并不是一个固定值,说明GIL会在某个时刻释放,那么GIL具体在什么情况下释放呢:
- 执行的字节码行数到达一定阈值
- 通过时间片划分,到达一定时间阈值
- 在遇到IO操作时,主动释放
网友评论