Python常用代码块&编程规范

常用代码块

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def main():
    print('hello world')

if __name__ == '__main__':

    main()

tkinter经典面向对象写法

from tkinter import *
from tkinter import messagebox
class Application(Frame):
    def __init__(self,master=None):
        super().__init__(master)
        self.master = master
        self.pack()
        self.createWidget()
    def createWidget(self):
        self.btn01 = Button(self)
        self.btn01["text"] = "点我"
        self.btn01.pack()
        self.btn01["command"] = self.btnCmd
    def btnCmd(self):
        messagebox.showinfo('标题','显示内容')
if __name__ == '__main__':
    root = Tk()
    root.geometry("400x100+200+300")
    root.title("www.code8cn.com")
    app = Application(master=root)
    root.mainloop()

一、请求接口(短链接)

1、requests

requests库的七个主要方法

方法解释
requests.request()构造一个请求,支持以下各种方法
requests.get()获取html的主要方法
requests.head()获取html头部信息的主要方法
requests.post()向html网页提交post请求的方法
requests.put()向html网页提交put请求的方法
requests.patch()向html提交局部修改的请求
requests.delete()向html提交删除请求

详解: https://blog.csdn.net/pittpakk/article/details/81218566

最常用的就是 get \post,传递json参数

import requests  #导入requests库
r=requests.get(url,params,**kwargs) #get请求目标url
r = requests.post(url, data)  # post推送目标url

#获取xx接口数据
def get_data():
  #确认请求链接
  url ="http://test"
  #构建参数
  params={
    "参数名a": "参数值a",
    "参数名b": "参数值b"
  }
  response=[requests.post(url = url, data=params).json #一般接口返回需要json化,方便解析数据
  print(response.status_code) #输出http请求的返回状态,若为200则表示请求成功
  print(response)#输出结果,查看返回数据结构

二、链接数据库

1、pymysql

常用的mysql数据库,可以直接使用pymysql组件,链接数据库进行简单的增删改查操作。

#导入第三方资源包
import pymysql
#进行数据库操作
def Con_Data(sql):
    # 进行数据库连接
    try:
        db = pymysql.connect(host='test.mysql.com',
                             port='端口号',
                             user='账号',
                             passwd='密码',
                             charset='utf8',
                             db='数据库名',
                             connect_timeout=6)
    except Exception as e:
        print('连接数据库错误,错误是%s' % e)
    # 使用 cursor() 方法创建一个游标对象 cursor
    cursor = db.cursor()
    # 使用 execute()  方法执行 SQL 查询
    try:
        cursor.execute(sql)
        #简单判断,是进行什么操作
        if 'SELECT' in sql:
            pass
        key = 'update,UPDATE,delete,DELETE,insert,INSERT'
        #如果是增删改操作
        if any(k in sql and k for k in key.split(',')):
            #进行提交
            db.commit()
    except Exception as e:
        db.rollback()# 发生错误时回滚
        print('执行sql语句失败,错误是%s' % e)
    #根据需要选择
    data1 = cursor.fetchone()# 使用 fetchone() 方法获取一条数据.
    data2 = cursor.fetchmany(2) # 使用 fetchmany(x) 方法获取 x 条数据.
    data3 = cursor.fetchall() # 使用fetchall() 方法获取所有的数据
    # 关闭游标
    cursor.close()
    # 关闭数据库连接
    db.close()
    return data

三、线程 threading

创建、撤消与切换进程,存在较大的时空开销,所以引入线程
一个程序至少一个进程,一个进程至少一个线程
Python中使用线程有两种方式:函数或者用类来包装线程对象。
进程是资源分配的最小单位,线程是程序的最小执行单位
多线程类似于同时执行多个不同程序,多线程运行有如下优点:

  • 程序进程速度可能加快(多线程不一定更快,参考链接:https://blog.csdn.net/weixin_42176112/article/details/117790945);
  • 可以大量创建线程
  • 线程与线程之间是独立的,并发执行。有好处,在收发数据时;坏处,在赋值时,容易发生错位赋值。
  • 线程主要针对于具有大量输入、输出以及网络收发数据等限制程序的速度时
#线程
'''
num:int #启用线程数,参考电脑cpu
'''
def ThreadRun(num):
    thread_list = []
    # 创建线程
    for i in range(num):
        thread = threading.Thread(target= '''方法名''' , args=[ '''方法参数''' ])
        thread_list.append(thread)
    # 启用线程
    for Start_th in thread_list:
        Start_th.start()
        time.sleep(0.01)
    # 停用线程
    for Stop_th in thread_list:
        Stop_th.join()

为避免多线程同时修改同一数值,此时可以采取加锁的方式

threadLock = threading.Lock() #锁对象实例化 
threadLock.acquire() #获得锁
'''
此处进行相关数据操作
同一时间只有一个线程再此处执行
'''
threadingLock.release #释放锁

四、协程gevent

gevent是python的一个并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效。
而且其中有个monkey类,将现有基于Python线程直接转化为greenlet(类似于打patch)。

在运行时的具体流程大概就是:

  • 当一个greenlet遇到IO操作时,比如访问网络/睡眠等待,就自动切换到其他的greenlet,
  • 等到IO操作完成,再在适当的时候切换回来继续执行。

由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。同时也因为只有一个线程在执行,会极大的减少上下文切换的成本

#gevent monkey
from gevent import monkey;monkey.patch_all()# 给所有的耗时操作打上补丁 , 在脚本开头导入时声明
import gevent
import time

def shui(n):
    time.sleep(n)

def task_1(name,nn):
    for i in range(10):
        print(name,nn, i,time.time())
        shui(5)  # 协程遇到耗时操作后会自动切换其他协程运行

def task_2(name):
    for i in range(10):
        print(name,'>>>>>>', i,time.time())
        shui(3)
l = task_1 #创建 <class 'function'> 的变量
if __name__ == "__main__":
        gevent.joinall([  # 等到协程运行完毕
          gevent.spawn(l, "task_1","-----"),  # 创建协程,带参数
          gevent.spawn(task_2, "task_2")# 创建协程,不带参数
        ])

上面可见,gevent.joinall()方法,以字典的形式去进行切换,
如果需要执行的方法较多,或者想要多次执行同一方法,就不太方便。
我们可以直接将创建协程存入字典,就方便重复调用一个方法(并发、压测)
得到以下代码

if __name__ == "__main__":
    threads = []
    for i in range(100):#添加协程数
        threads.append( gevent.spawn(l, "name", i))
    gevent.joinall(threads)
    print("the main thread!")
])

Python常用的基本编程规范

1、在文件开头声明文件编码,以下两种均可

# -*- coding: utf-8 -*-   
# coding = utf-8

2、缩进规则
统一使用 4 个空格进行缩进,不要用tab, 更不要tab和空格混用

3、注释部分,# 号后面要空一格

# 注释部分 

4、空行
双空行:编码格式声明、模块导入、常量和全局变量声明、顶级定义(类的定义)和执行代码之间空两行
单空行:方法定义之间空一行,方法内分隔某些功能的位置也可以空一行

5、模块导入部分
导入应该放在文件顶部,位于模块注释和文档字符串之后,模块全局变量和常量之前。
导入应该照从最通用到最不通用的顺序分组,分组之间空一行,依次为:标准库导入-》第三方库导入-》应用程序指定导入
每个 import 语句只导入一个模块,尽量避免一次导入多个模块

6、Python命名建议遵循的一般性原则:
模块尽量使用小写命名,首字母保持小写,尽量不要用下划线
类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头
函数名、变量名一律小写,如有多个单词,用下划线隔开,私有函数用一个下划线开头
常量采用全大写,如有多个单词,使用下划线隔开

7、引号
输出语句中使用单双引号都是可以正确的,此外 正则表达式推荐使用双引号、文档字符串 (docstring) 推荐使用三个双引号


1.用户代理 User Agent
在浏览器地址栏输入:about:version

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36

2.文件读写

if not os.path.exists(path):
    os.makedirs(path)

with open(file_path, "w", encoding='utf8') as f:
    f.write("")

with open(r'c:/path/to/file', 'r') as f:
    print(f.read())

3.基本爬虫正则

res = requests.get(url)
res.encoding = 'utf8'

body = re.compile(r'<body.*</body>', re.S).findall(r.text)[0]
ret = re.sub(r'[0-9]', "*", s)

4.python打开文件w和wb,r和rb的区别

w表示正常写入 wb表示二进制写入

r表示正常读取 rb表示二进制读取

5.python常用函数

# 通过指定分隔符对字符串进行切片
string = "www.code8cn.com"
print(string.split('.')[-1]) # -1代表倒数第1个
print(string.split('.')[1:]) # 1:代表从第二个往后

# 得到6位随机数
def v_code(n=6):
        """
            Returns:
                ret:random six num and letter
        """
        ret = ""
        for i in range(n):
            num = random.randint(0, 9)
            # num = chr(random.randint(48,57))#ASCII表示数字
            letter = chr(random.randint(97, 122))  # 取小写字母
            Letter = chr(random.randint(65, 90))  # 取大写字母
            s = str(random.choice([num, letter, Letter]))
            ret += s
        return ret

pic_name = hashlib.md5(b'123').hexdigest()

6.爬虫常用代码

# request.get封装
def getHtmlStr(url):

    params = {
        'query':'site:code8cn.com' # getHtmlStr('https://sogou.com/web')
    }

    headers ={
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"
    }

    #res = requests.get(url=url,params=params,headers=headers)
    res = requests.get(url=url,headers=headers)
    res.encoding = 'utf8'

    return res.text