python 一些常用的小技巧

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为下一个节点的地址。

基本元素:

  1. 节点:每个节点有两个部分,左边部分称为值域,用来存放用户数据;右边部分称为指针域,用来存放指向下一个元素的指针。
  2. head:head节点永远指向第一个节点
  3. tail: tail永远指向最后一个节点
  4. 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具体在什么情况下释放呢:

  1. 执行的字节码行数到达一定阈值
  2. 通过时间片划分,到达一定时间阈值
  3. 在遇到IO操作时,主动释放
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容

  • 有一天晚上,在睡梦中梦见一对情侣在争吵。 结果第二天晚上发现,原来不是梦,真的是隔壁邻居在吵架。我知道偷听人家吵架...
    ceiba沐清阅读 366评论 0 1
  • 最近由于需要绘制界面的一些操作,用到了CALayer,需要自己去重绘layer。 需要自定义以上方法,这个方法告诉...
    Calvin_Shen阅读 1,077评论 2 1
  • 今天因为雾霾太大,我们就没有到,操场上去做操,而是到会议室,去听小朋友讲故事啦,小朋友们都可厉害了,讲的故事特别好...
    段智耀阅读 120评论 0 0
  • 有的人为人处世过于柔软,这样的人往往个人领域不断被侵犯,因为他们缺乏底线,把自己的原则一退再退。 忍让是一个好品性...
    很帅的粑粑阅读 371评论 0 1