python学习小记
多版本环境配置
一般下载python并安装即可在命令行中使用python,不需要进行其他配置。
多版本的情形:若多个python项目对同一个依赖包要求的版本不同,甚至不同项目要求的python版本不同,则要用到python的多版本管理能力。
解决:在同一台机器上同时开发多个项目时,通常是为每个项目分别创建python环境而不是使用安装在OS的python环境,以在各自环境下安装依赖包,从而减少可能的互相干扰。有 venv、pyenv 两种途径达到该目的。
venv 是 python 自带的模块,可通过 python -m venv $dir_name && cd $dir_name && ./bin/pip install -r $project/requirements.txt 创建一个 venv 环境、在该环境内安装项目的依赖包,然后在该 venv 下执行 ./bin/activate 启用该环境(每次登录都要手动启用,除非加到启动脚本例如 ~/.bashrc 中)
pyenv 是一个程序,用于在同一个OS安装并管理不同版本的 python ,需要单独下载安装(见:https://github.com/pyenv/pyenv-installer)。两大功能:
管理不同版本 python :可通过 pyenv install $version 命令安装不同版本 python 。
管理 venv : pyenv virtualenv $YourVenvName && pyenv activate $YourVenvName && pip install -r $project/requirements.txt ,背后实际上就是以当前版本的 python 创建 venv 并将依赖安装到该 venv 中,与上面 venv 的效果等价。
通过 pyenv 创建 venv 时可能会由于OS上同时有2.7、3.5+ 版本且默认 python 版本为2.7而报小于3.5的错,需要将默认版本改为3.5以上。如果真的去改可能会遇到很多阻力,怎么解决?直接通过 python3 创建个 3.5+ 的 venv、接着激活该venv、然后再执行pyenv的上述功能。这有点鸡生蛋蛋生鸡的感觉。
可见,pyenv 比 venv 功能更强大,因此更推荐用 pyenv 。缺点是需要单独另外安装。
一行代码启动Python自带的http server:
# python 2 python -m SimpleHTTPServer 端口号 # python 3 python -m http.server 端口号
python HTTP请求示例:
1 # coding=utf-8 2 3 # more materials: http://docs.python-requests.org/zh_CN/latest/user/quickstart.html 4 5 import requests 6 import json 7 import time 8 9 import pymysql 10 11 myhost = "http://127.0.0.1:8080" 12 myurl = "" 13 mytoken = "" 14 myheaders = {} 15 myparams = {} 16 mybodydata = {} 17 18 19 20 def test1(): 21 # POST demo 22 print "\n POST demo" 23 myurl = myhost + "/api/v1/auth/login" 24 mybodydata = {"username": "杜甫", "password": "123"} 25 r = requests.post(myurl, data=json.dumps(mybodydata)) 26 # print r.text 27 mytoken = r.json()["token"] 28 print mytoken 29 30 # GET demo 31 print "\n GET demo" 32 myurl = myhost + "/api/v1/student/experiment" 33 myheaders = {"X-Authorization": "Bearer "+mytoken} 34 myparams = { 35 "studentId": "664e8106-0552-45e9-8518-5fab535fe036", "chapter": 2} 36 r = requests.get(myurl, headers=myheaders, params=myparams) 37 # print r.text 38 print r.json()[0]["studentId"] 39 40 # PUT demo 41 print "\n PUT demo" 42 myurl = myhost + "/api/v1/student/experiment/completion" 43 myheaders = {"X-Authorization": "Bearer "+mytoken} 44 myparams = {"studentId": "664e8106-0552-45e9-8518-5fab535fe036", "experimentId": "2.1", 45 "modifyTimestamp": "2018-11-21 11:10:11", "finishedSteps": 3} 46 r = requests.put(myurl, headers=myheaders, params=myparams) 47 # print r.text 48 # print r.json()["studentId"] 49 return 50 # test1() 51 52 53 def test2(i, postfix): 54 # POST demo 55 print "\n POST demo" 56 myurl = myhost + "/api/v1/admin/student" 57 myheaders = {'content-type': 'application/json', "X-Authorization": "Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiLnrqHnkIblkZgiLCJzY29wZXMiOlsiUk9MRV9BRE1JTiJdLCJ1c2VySWQiOiJhZG1pbjAwMDEiLCJpc3MiOiJ6aHV5YW5ibyIsImlhdCI6MTUyODMzODkzMCwiZXhwIjoxNTMxOTM4OTMwfQ.psAqK4nl5eE9DkD14c3TMYXaMkp4ydDnjNagT61ja96WzBl41M3ZTL-oatMXSqvXk1ExDQkW0SCyl01HJyEiSg"} 58 mybodydata = {"schoolId": "1", "schoolNumber": "SY1506"+postfix, 59 "name": name[i], "gender": "0", "grade": "高一(6)班", 60 "age": 18, "status": "online", "bz": bz[i], 61 "phone": "110", "ip": ip[i], "port": port[i]} 62 r = requests.post(myurl, headers=myheaders, data=json.dumps(mybodydata)) 63 print r.text 64 # mytoken=r.json()["token"] 65 # print mytoken 66 return 67 # 不能有分号,fuck 68 # test2() 69 70 71 ip = ["10.5.31.18", "10.5.31.18", "10.5.31.18", "10.5.31.18", "10.5.31.18", "10.5.31.18", "10.5.31.18", "10.5.31.18", "10.5.31.21", "10.5.31.21", "10.5.31.21", "10.5.31.21", "10.5.31.21", "10.5.31.21", "10.5.31.21", "10.5.31.21", "10.5.31.24", "10.5.31.24", "10.5.31.24", "10.5.31.24", "10.5.31.24", "10.5.31.24", "10.5.31.24", "10.5.31.24", "10.5.31.27", "10.5.31.27", "10.5.31.27", "10.5.31.27", "10.5.31.27", "10.5.31.27", "10.5.31.27", "10.5.31.27", "10.5.31.30", "10.5.31.30", "10.5.31.30", "10.5.31.30", 72 "10.5.31.30", "10.5.31.30", "10.5.31.30", "10.5.31.30", "10.5.31.33", "10.5.31.33", "10.5.31.33", "10.5.31.33", "10.5.31.33", "10.5.31.33", "10.5.31.33", "10.5.31.33", "10.5.31.36", "10.5.31.36", "10.5.31.36", "10.5.31.36", "10.5.31.36", "10.5.31.36", "10.5.31.36", "10.5.31.36", "10.5.31.39", "10.5.31.39", "10.5.31.39", "10.5.31.39", "10.5.31.39", "10.5.31.39", "10.5.31.39", "10.5.31.39", "10.5.31.42", "10.5.31.42", "10.5.31.42", "10.5.31.42", "10.5.31.42", "10.5.31.42", "10.5.31.42", "10.5.31.42"] 73 port = ["5001", "5002", "5003", "5004", "5005", "5006", "5007", "5008", "5001", "5002", "5003", "5004", "5005", "5006", "5007", "5008", "5001", "5002", "5003", "5004", "5005", "5006", "5007", "5008", "5001", "5002", "5003", "5004", "5005", "5006", "5007", "5008", "5001", "5002", "5003", "5004", 74 "5005", "5006", "5007", "5008", "5001", "5002", "5003", "5004", "5005", "5006", "5007", "5008", "5001", "5002", "5003", "5004", "5005", "5006", "5007", "5008", "5001", "5002", "5003", "5004", "5005", "5006", "5007", "5008", "5001", "5002", "5003", "5004", "5005", "5006", "5007", "5008"] 75 name = ["林达华", "戴娟", "周丹", "倪枫", "范青", "郑文滨", "张富华", "蔡文晖", "吴军", "王若晖", "李治中", "朱雁博", "李晓波", "吴青", "张绍铭", "杨焕州", "王睿", "陈向东", "严一滨", "周畅", "胡志洪", "朱元锟", "敖培", "冷春波", "马军", "张龙", "王英", "段斯译", "闫兴华", "黄山", "方小培", "汪义超", "王梦", "佟彤", "张秀政", "李卫平", "曾皓明", 76 "王广科", "张振堂", "徐正一", "沈杨", "何博", "刘晓丹", "钱 晋", "王霄驰", "穆青", "朱永生", "崔懿", "朱勋", "万景华", "王美佳", "王辉", "江艳萍", "张炜其", "李守志", "刘平", "李鲋瑞", "王智荣", "于新平", "常学勤", "王明江", "章良", "姜波", "王建伟", "武绍玮", "吴时敏", "蓝滚波", "stu01", "stu02", "stu03", "stu04", "stu05"] 77 bz = ["商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "商汤", "华东师范大学第二附属中学", "华东师范大学第二附属中学", "华东师范大学第二附属中学乐东黄流中学", "上海交通大学附属中学", "上海交通大学附属中学", "上海市晋元高级中学", "上海市晋元高级中学", "中山纪念中学", "晋城市第一中学", "山西省汾阳中学校", "深圳外国语学校", "广东广雅中学", "广东广雅中学", "合肥市第一中学", "合肥市第一中学", "中央民族大学附属中学", "哈尔滨工业大学附属中学校", "山西孝义中学", "孝义市教育局", "浙江省镇海中学", "江苏省邗江中学", "甘肃省兰州第一中学", 78 "上海市格致中学", "上海市格致中学", "上海市格致中学", "上海市格致中学", "上海市市西中学", "上海市市西中学", "山东省青岛第二中学", "合肥市第六中学", "上海市七宝中学", "河南大学附属中学", "东北育才学校", "辽宁省实验中学", "新疆农业大学附属中学", "浙江省温岭中学", "北京市第十一中学校", "贵阳市第一中学", "深圳华侨城中学", "深圳华侨城中学", "山西省实验中学", "山西省实验中学", "未来科技", "西北师范大学附属中学", "上海光华教育集团", "郑州市第二中学", "郑州市第二中学", "郑州市第二中学", "贵阳一中金塔英才学校", "博罗县东江广雅学校", "绑定端口的学生测试账号", "绑定端口的学生测试账号", "绑定端口的学生测试账号", "绑定端口的学生测试账号", "绑定端口的学生测试账号"] 79 80 for i in range(1, 73): 81 num = "%02d" % i 82 # test2(i-1,num) 83 84 85 for i in range (24,25): 86 num = "%03d" % i 87 myhost="http://10.5.31.15:8081" 88 myurl = myhost + "/api/v1/admin/student" 89 myheaders = {'content-type': 'application/json', "X-Authorization": "Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiLnrqHnkIblkZgiLCJzY29wZXMiOlsiUk9MRV9BRE1JTiJdLCJ1c2VySWQiOiJhZG1pbjAwMDEiLCJpc3MiOiJ6aHV5YW5ibyIsImlhdCI6MTUyODMzODkzMCwiZXhwIjoxNTMxOTM4OTMwfQ.psAqK4nl5eE9DkD14c3TMYXaMkp4ydDnjNagT61ja96WzBl41M3ZTL-oatMXSqvXk1ExDQkW0SCyl01HJyEiSg"} 90 mybodydata = {"schoolId": "1", "schoolNumber": "cmcc"+num, 91 "name": "邢孝慈", "gender": "0", "grade": "高一(6)班", 92 "age": 18, "status": "online", "bz": "student test account", 93 "phone": "110", "ip": "10.5.31.15", "port": 5000+i} 94 # print mybodydata 95 # r = requests.post(myurl, headers=myheaders, data=json.dumps(mybodydata)) 96 # print r.text 97 98 99 def test3(): 100 print "\n PUT demo" 101 myurl = myhost + "/api/v1/teacher/course/experiment/step" 102 myheaders = {"X-Authorization": "Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiLlvKDogIHluIgiLCJzY29wZXMiOlsiUk9MRV9URUFDSEVSIl0sInVzZXJJZCI6InRlYWNoZXIwMDAxIiwiaXNzIjoiemh1eWFuYm8iLCJpYXQiOjE1MjgxMDExODcsImV4cCI6MTUzMTcwMTE4N30.7c7j4vCqqNoguoA6FXuTXqkIXPLdYrSf9kYl-Yurmi0gjrOwukt5eDM1bW1O_L4yz6gbo_FpPH1murvFg8-EUg"} 103 myparams = {"courseId": "1", "experimentId": "2.1", 104 "step": 1} 105 mybodydata = "\"he<p>你好aolisfjdlasfjklis</p>he\"" 106 print mybodydata 107 r = requests.put(myurl, headers=myheaders, 108 params=myparams, data=mybodydata) 109 print r.text 110 # test3() 111 112 113 # 实验步骤插入 114 myurl = myhost + "/api/v1/teacher/course/experiment/step" 115 myheaders = {'content-type': 'application/json', "X-Authorization": "Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiLnrqHnkIblkZgiLCJzY29wZXMiOlsiUk9MRV9BRE1JTiJdLCJ1c2VySWQiOiJhZG1pbjAwMDEiLCJpc3MiOiJ6aHV5YW5ibyIsImlhdCI6MTUyODMzODkzMCwiZXhwIjoxNTMxOTM4OTMwfQ.psAqK4nl5eE9DkD14c3TMYXaMkp4ydDnjNagT61ja96WzBl41M3ZTL-oatMXSqvXk1ExDQkW0SCyl01HJyEiSg"} 116 for i in range (1,7): 117 tmpContent= "(请添加 实验 0-4 步骤 "+ str(i) +" 的内容描述)" 118 mybodydata = {"experimentId": "0.4", "content": tmpContent } 119 # r = requests.post(myurl, headers=myheaders, data=json.dumps(mybodydata)) 120 121 122 def sqlTest(): 123 try: 124 conn = pymysql.connect(host="127.0.0.1", db="sensestudydev", user="root", passwd="123", port=3306) 125 sql = "select * from user" 126 cur = conn.cursor() 127 cur.execute(sql) 128 rows = cur.fetchall() 129 print rows[0] 130 # print json.dumps(json.loads(rows[0][0]), indent=4) 131 except: 132 conn.close() 133 conn.close() 134 sqlTest()
python json序列化
通过 json.dumps 可能的问题:dic 的 key不是基本类型导致dumps时报key类型不支持的错、被序列化的对象是或者包含自定义的class且该classs没有在 __init__中定义属性名从而导致没有 __dict__ 属性。下面的用法解决了该两个问题:
tmp_data = convert_dict_key_to_str(data) # 解决 json.dumps 时对于dic key不能为tuple等类型的问题 json_data = json.dumps(tmp_data, indent = 4, default = python_to_json_value) if ret_json == True else "" return data, json_data def convert_dict_key_to_str(input_dict): if not isinstance(input_dict, dict): return copy.deepcopy(input_dict) else: return {str(k): convert_dict_key_to_str(v) for k, v in input_dict.items()} def python_to_json_value(data): if isinstance(data, Decimal): return str(data) if isinstance(data, type({}.values())): return list(data) if not hasattr(data, '__dict__'): attr_list = [attr for attr in dir(data) if not attr.startswith('_')] attr_dict = {attr: getattr(data, attr) for attr in attr_list} return attr_dict return data.__dict__
时间/日期的时区转换
import datetime import pytz def printInfo(date_obj): print('日期对象:', date_obj) print('时区:', date_obj.tzname(),"timestamp:", date_obj.timestamp()) # 再将 datetime 对象转换为日期字符串 new_date_str = date_obj.strftime(format_str) print('日期字符串:', new_date_str) # 定义日期字符串和格式 date_str = '2023-06-30 23:59:59' format_str = '%Y-%m-%d %H:%M:%S' print('原始日期字符串:', date_str) print(1 ) # 将日期字符串转换为 datetime 对象 date_obj = datetime.datetime.strptime(date_str, format_str) printInfo(date_obj) #纵向转换:字面日期和时间值一样,但不是同时的(时间戳不同) print(2 ) date_obj = pytz.timezone('Australia/Sydney').localize(date_obj.replace(tzinfo=None)) printInfo(date_obj) print( 3) date_obj = pytz.timezone('Asia/Shanghai').localize(date_obj.replace(tzinfo=None)) printInfo(date_obj) #斜向转换:字面日期和时间值不同,但是同时的(时间戳一样) print(4 ) date_obj = date_obj.astimezone(pytz.timezone('Australia/Sydney')) printInfo(date_obj) print(5 ) date_obj = date_obj.astimezone(pytz.timezone('Asia/Shanghai')) printInfo(date_obj) #方案 1->3->2 print(6) open_time = 1625065200 open_time= datetime.datetime.fromtimestamp(open_time) .astimezone(pytz.timezone('Asia/Shanghai')) .strftime('%d/%m/%Y') print(open_time) # 以下是输出 原始日期字符串: 2023-06-30 23:59:59 1 日期对象: 2023-06-30 23:59:59 时区: None timestamp: 1688169599.0 日期字符串: 2023-06-30 23:59:59 2 日期对象: 2023-06-30 23:59:59+10:00 时区: AEST timestamp: 1688133599.0 日期字符串: 2023-06-30 23:59:59 3 日期对象: 2023-06-30 23:59:59+08:00 时区: CST timestamp: 1688140799.0 日期字符串: 2023-06-30 23:59:59 4 日期对象: 2023-07-01 01:59:59+10:00 时区: AEST timestamp: 1688140799.0 日期字符串: 2023-07-01 01:59:59 5 日期对象: 2023-06-30 23:59:59+08:00 时区: CST timestamp: 1688140799.0 日期字符串: 2023-06-30 23:59:59 6 30/06/2021