美文网首页
python 一些常用的小技巧

python 一些常用的小技巧

作者: Senter | 来源:发表于2019-03-13 10:40 被阅读0次

    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操作时,主动释放

    相关文章

      网友评论

          本文标题:python 一些常用的小技巧

          本文链接:https://www.haomeiwen.com/subject/puczpqtx.html