├── PythonCode ├── FaceAPI.py ├── GUI--Button.py ├── GUI--Listdir.py ├── GUI--Resize.py ├── MutilProcessTCPServer.py ├── MutilThreadTCPServer.py ├── Non-BlockingTCPServer.py ├── SimpleChatWithSocketUDP.py ├── SingleProcessTCPServer.py ├── Spider--Aitaotu.py ├── Spider--DoubanTop250.py ├── Spider--GetProxyIPAddress.py ├── Spider--Lianjia.py ├── Spider--Pic360.py └── Spider--Xiaoxiang.py ├── Python知识点汇总 ├── Python面试题.md ├── README.md ├── img ├── 1534302969970.png ├── 1534303067466.png ├── 1534314173618.png ├── 1534314262045.png ├── 1534314401023.png ├── 1534314404356.png ├── 412b4451-2738-3ebc-b1f6-a0cc13b9697b.jpg └── bddb00b6-a3e1-3112-a4f4-4b3cb8687c70.jpg ├── 使用Python 发送SMTP协议电子邮件.md ├── 八大排序算法.md ├── 关于OOP.md ├── 列表推导式.md └── 微信itchat 图灵api.md /PythonCode/FaceAPI.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import os 3 | import mimetypes 4 | import csv 5 | from fake_useragent import FakeUserAgent 6 | 7 | 8 | class GetFakeAgent(object): 9 | """docstring for GetFakeAgent""" 10 | 11 | @staticmethod 12 | def get_agent(choice='random'): 13 | # 获取伪装Agent 14 | ua = FakeUserAgent() 15 | browser = {'ie': ua.internetexplorer, 16 | 'opera': ua.opera, 17 | 'safari': ua.safari, 18 | 'random': ua.random, 19 | 'chrome': ua.chrome, 20 | 'firefox': ua.firefox 21 | } 22 | return {'User-Agent': browser[choice]} 23 | 24 | 25 | class FaceApi(object): 26 | """docstring for FaceApi""" 27 | 28 | def __init__(self, spath, attrs='gender,age'): 29 | self.attrs = attrs 30 | self.spath = spath 31 | self.frist_write = True 32 | self.faceurl = 'https://api-cn.faceplusplus.com/facepp/v3/detect' 33 | self.payload = {'api_key': 'your_api_key', 34 | 'api_secret': 'your_api_secret', 35 | 'return_attributes': self.attrs} 36 | self.headers = GetFakeAgent.get_agent() 37 | self.info_dict = {'pic': '', 38 | "width": '', 39 | "top": '', 40 | "left": '', 41 | "height": ''} 42 | 43 | def get_result(self): 44 | file_list = os.listdir(self.spath) 45 | if len(file_list) > 0: 46 | for file in file_list: 47 | self.request_api(self.spath + file) 48 | 49 | def request_api(self, file): 50 | fname = file 51 | bname = os.path.basename(fname) 52 | ftype = mimetypes.guess_type(fname)[0] 53 | files = {'image_file': (bname, open(fname, 'rb'), ftype)} 54 | req = requests.post(self.faceurl, 55 | data=self.payload, 56 | headers=self.headers, 57 | files=files) 58 | self.parse_json(req, bname) 59 | 60 | def parse_json(self, obj, bname): 61 | json = obj.json() 62 | info_dict = {'pic': '', 63 | "width": '', 64 | "top": '', 65 | "left": '', 66 | "height": ''} 67 | for key in info_dict.keys(): 68 | if key == 'pic': 69 | info_dict[key] = bname 70 | else: 71 | info_dict[key] = json['faces'][0]['face_rectangle'][key] 72 | for attr in self.attrs.replace(' ', '').split(','): 73 | info_dict.update( 74 | {attr: json['faces'][0]['attributes'][attr]['value']}) 75 | print(bname, '获取完毕,正在保存...') 76 | self.save_info(info_dict) 77 | 78 | def save_info(self, obj): 79 | with open(self.spath + 'result.csv', 'a+') as csvfile: 80 | writer = csv.writer(csvfile) 81 | if self.frist_write: 82 | writer.writerow(['图片名', 'width', 'top', 'left', 'height'] + 83 | self.attrs.replace(' ', '').split(',')) 84 | self.frist_write = False 85 | writer.writerow(list(obj.values())) 86 | 87 | 88 | if __name__ == '__main__': 89 | spath = './360pic/' 90 | attrs = 'gender,age' 91 | faceapi = FaceApi(spath, attrs) 92 | faceapi.get_result() 93 | -------------------------------------------------------------------------------- /PythonCode/GUI--Button.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | from functools import partial as pto 3 | from tkinter.messagebox import showinfo, showwarning, showerror 4 | 5 | WARN = "warn" 6 | CRIT = "crit" 7 | REGU = "regu" 8 | 9 | SIGNS = { 10 | "do not enter": CRIT, 11 | "railroad crossing": WARN, 12 | "55\nspeed limit": REGU, 13 | "wrong way": CRIT, 14 | "merging traffic": WARN, 15 | "one way": REGU, 16 | } 17 | 18 | 19 | def critCB(): return showerror("Error", "Error Button Pressed!") 20 | # critCB = lambda : print("run") 21 | 22 | 23 | def warnCB(): return showwarning("Warning", "Warning Button Pressed!") 24 | 25 | 26 | def infoCB(): return showinfo("Info", "Info Button Pressed!") 27 | 28 | 29 | top = Tk() 30 | top.title("Road Signs") 31 | Button(top, text="QUIT", command=top.quit, bg="red", fg="white").pack() 32 | 33 | MyButton = pto(Button, top) 34 | CritButton = pto(MyButton, command=critCB, bg="white", fg="red") 35 | WarnButton = pto(MyButton, command=warnCB, bg="goldenrod1") 36 | ReguButton = pto(MyButton, command=infoCB, bg="white") 37 | 38 | for eachSign in SIGNS: 39 | signType = SIGNS[eachSign] 40 | cmd = "%sButton(text=%r%s).pack(fill=X, expand=1)" % ( 41 | signType.title(), eachSign, ".upper()" if signType == CRIT else ".title()") 42 | eval(cmd) 43 | 44 | top.mainloop() 45 | -------------------------------------------------------------------------------- /PythonCode/GUI--Listdir.py: -------------------------------------------------------------------------------- 1 | import os 2 | from time import sleep 3 | from tkinter import * 4 | 5 | 6 | class DirList(object): 7 | """This class used for create GUI.""" 8 | 9 | def __init__(self, initdir=None): 10 | """__init__ for GUI.""" 11 | self.top = Tk() 12 | self.label = Label(self.top, text="Directory Lister v1.1") 13 | self.label.pack() 14 | 15 | self.cwd = StringVar(self.top) 16 | 17 | self.dirl = Label(self.top, fg="blue", font=("Helvetica", 12, "bold")) 18 | self.dirl.pack() 19 | 20 | self.dirfm = Frame(self.top) 21 | self.dirsb = Scrollbar(self.dirfm) 22 | self.dirsb.pack(side=RIGHT, fill=Y) 23 | self.dirs = Listbox(self.dirfm, height=15, width=50, 24 | yscrollcommand=self.dirsb.set) 25 | self.dirs.bind("", self.dirs.yview) 26 | self.dirs.pack(side=LEFT, fill=BOTH) 27 | self.dirfm.pack() 28 | 29 | self.dirn = Entry(self.top, width=50, textvariable=self.cwd) 30 | self.dirn.bind("", self.doLS) 31 | self.dirn.pack() 32 | 33 | self.bfm = Frame(self.top) 34 | self.clr = Button(self.bfm, text="Clear", command=self.clrDir, 35 | activeforeground="white", activebackground="blue") 36 | self.ls = Button(self.bfm, text="List Directory", command=self.doLS, 37 | activeforeground="white", activebackground="green") 38 | self.quit = Button(self.bfm, text="Quit", command=self.top.quit, 39 | activeforeground="white", activebackground="red") 40 | self.clr.pack(side=LEFT) 41 | self.ls.pack(side=LEFT) 42 | self.quit.pack(side=LEFT) 43 | self.bfm.pack() 44 | 45 | if initdir: 46 | self.cwd.set(os.curdir) 47 | self.doLS() 48 | 49 | def clrDir(self, ev=None): 50 | """Default cwd.set.""" 51 | self.cwd.set("") 52 | 53 | def setDirAndGo(self, ev=None): 54 | """Set dir and go.""" 55 | self.last = self.cwd.get() 56 | self.dirs.config(selectbackground="red") 57 | check = self.dirs.get(self.dirs.curselection()) 58 | if not check: 59 | check = os.curdir 60 | self.cwd.set(check) 61 | self.doLS() 62 | 63 | def doLS(self, ev=None): 64 | """Set doLS.""" 65 | error = "" 66 | tdir = self.cwd.get() 67 | if not tdir: 68 | tdir = os.curdir 69 | if not os.path.exists(tdir): 70 | error = tdir + ":no such file" 71 | elif not os.path.isdir(tdir): 72 | error = tdir + ":not a directory" 73 | 74 | if error: 75 | self.cwd.set(error) 76 | self.top.update() 77 | sleep(2) 78 | if not (hasattr(self, "last") and self.last): 79 | self.last = os.curdir 80 | self.cwd.set(self.last) 81 | self.dirs.config(selectbackground="LightSkyBlue") 82 | self.top.update() 83 | return 84 | 85 | self.cwd.set("FETCHING DIRECTORY CONTENTS...") 86 | self.top.update() 87 | dirlist = sorted(os.listdir(tdir)) 88 | os.chdir(tdir) 89 | 90 | self.dirl.config(text=os.getcwd()) 91 | self.dirs.delete(0, END) 92 | self.dirs.insert(END, os.curdir) 93 | self.dirs.insert(END, os.pardir) 94 | for eachFile in dirlist: 95 | self.dirs.insert(END, eachFile) 96 | self.cwd.set(os.curdir) 97 | self.dirs.config(selectbackground="LightSkyBlue") 98 | 99 | 100 | def main(): 101 | """Main of progroum""" 102 | d = DirList(os.curdir) 103 | mainloop() 104 | 105 | 106 | if __name__ == '__main__': 107 | main() 108 | -------------------------------------------------------------------------------- /PythonCode/GUI--Resize.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | 3 | 4 | def resize(ev=None): 5 | label.config(font="Helvetica -%d bold" % scale.get()) 6 | 7 | 8 | top = Tk() 9 | top.geometry("250x150") 10 | 11 | label = Label(top, text="Hello world!", font="Helvetica -12 bold") 12 | label.pack(fill=Y, expand=1) 13 | 14 | scale = Scale(top, from_=10, to=40, orient=HORIZONTAL, command=resize) 15 | scale.set(12) 16 | scale.pack(fill=X, expand=1) 17 | 18 | quitX = Button(top, text="QUIT", command=top.quit, activeforeground="white", 19 | activebackground="red") 20 | quitX.pack() 21 | 22 | mainloop() 23 | -------------------------------------------------------------------------------- /PythonCode/MutilProcessTCPServer.py: -------------------------------------------------------------------------------- 1 | from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR 2 | from multiprocessing import Process 3 | 4 | 5 | def recv_data(new_socket, new_address): 6 | while True: 7 | recv_msg = new_socket.recv(1024).decode("gb2312") 8 | if recv_msg: 9 | print("收到消息:{}".format(recv_msg)) 10 | new_socket.send("THANKS!".encode("gb2312")) 11 | if not recv_msg: 12 | print("连接丢失,已断开") 13 | break 14 | new_socket.close() 15 | print("关闭{}客户端".format(new_address)) 16 | 17 | 18 | def main(): 19 | tcp_socket = socket(AF_INET, SOCK_STREAM) 20 | tcp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 21 | tcp_socket.bind(("", 8080)) 22 | tcp_socket.listen(5) 23 | while True: 24 | new_socket, new_address = tcp_socket.accept() 25 | Process(target=recv_data, args=(new_socket, new_address)).start() 26 | new_socket.close() 27 | 28 | tcp_socket.close() 29 | 30 | 31 | if __name__ == '__main__': 32 | main() 33 | -------------------------------------------------------------------------------- /PythonCode/MutilThreadTCPServer.py: -------------------------------------------------------------------------------- 1 | from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR 2 | from threading import Thread 3 | 4 | 5 | def recv_data(new_socket, new_address): 6 | while True: 7 | recv_msg = new_socket.recv(1024).decode("gb2312") 8 | if recv_msg: 9 | print("收到消息:{}".format(recv_msg)) 10 | new_socket.send("THANKS!".encode("gb2312")) 11 | if not recv_msg: 12 | print("连接丢失,已断开") 13 | break 14 | 15 | 16 | def main(): 17 | tcp_socket = socket(AF_INET, SOCK_STREAM) 18 | tcp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 19 | tcp_socket.bind(("", 8080)) 20 | tcp_socket.listen(5) 21 | while True: 22 | new_socket, new_address = tcp_socket.accept() 23 | Thread(target=recv_data, args=(new_socket, new_address)).start() 24 | tcp_socket.close() 25 | 26 | 27 | if __name__ == '__main__': 28 | main() 29 | -------------------------------------------------------------------------------- /PythonCode/Non-BlockingTCPServer.py: -------------------------------------------------------------------------------- 1 | from socket import * 2 | 3 | tcp_socket = socket(AF_INET, SOCK_STREAM) 4 | tcp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 5 | tcp_socket.bind(("", 8080)) 6 | tcp_socket.listen(5) 7 | tcp_socket.setblocking(False) 8 | client_list = [] 9 | 10 | while True: 11 | try: 12 | new_socket, new_address = tcp_socket.accept() 13 | except Exception as result: 14 | pass 15 | else: 16 | print("有新的连接:{}".format(new_address)) 17 | new_socket.setblocking(False) 18 | client_list.append((new_socket, new_address)) 19 | 20 | for new_socket, new_address in client_list: 21 | try: 22 | recv_msg = new_socket.recv(1024).decode("gb2312") 23 | except Exception as result: 24 | pass 25 | else: 26 | if recv_msg: 27 | print("收到信息:{}".format(recv_msg)) 28 | new_socket.send("已经收到信息:{}".format(recv_msg).encode("gb2312")) 29 | if not recv_msg: 30 | print("{}连接丢失,已断开".format(new_address)) 31 | client_list.remove((new_socket, new_address)) 32 | tcp_socket.close() 33 | -------------------------------------------------------------------------------- /PythonCode/SimpleChatWithSocketUDP.py: -------------------------------------------------------------------------------- 1 | from socket import socket, AF_INET, SOCK_DGRAM 2 | from threading import Thread 3 | 4 | 5 | class RecvMessage(Thread): 6 | def __init__(self, udp_socket): 7 | super().__init__() 8 | self.udp_socket = udp_socket 9 | 10 | def run(self): 11 | self.recv_data() 12 | 13 | def recv_data(self): 14 | while True: 15 | recv_msg = self.udp_socket.recvfrom(1024) 16 | print("接收到的信息:", recv_msg[0]) 17 | 18 | 19 | class SendMessage(Thread): 20 | def __init__(self, udp_socket, target_host, target_port): 21 | super().__init__() 22 | self.udp_socket = udp_socket 23 | self.target_host = target_host 24 | self.target_port = target_port 25 | 26 | def run(self): 27 | self.send_data() 28 | 29 | def send_data(self): 30 | while True: 31 | send_msg = input("发送消息:") 32 | self.udp_socket.sendto(send_msg.encode( 33 | "gb2312"), (self.target_host, self.target_port)) 34 | 35 | 36 | class ChatSystem(object): 37 | def start(self): 38 | udp_socket = socket(AF_INET, SOCK_DGRAM) 39 | target_host = input("目标主机地址:") 40 | target_port = int(input("目标主机端口:")) 41 | udp_socket.bind(("", 8082)) 42 | 43 | RecvMessage(udp_socket).start() 44 | SendMessage(udp_socket, target_host, target_port).start() 45 | 46 | 47 | if __name__ == "__main__": 48 | ChatSystem().start() 49 | -------------------------------------------------------------------------------- /PythonCode/SingleProcessTCPServer.py: -------------------------------------------------------------------------------- 1 | from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR 2 | 3 | 4 | def main(): 5 | tcp_socket = socket(AF_INET, SOCK_STREAM) 6 | tcp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 7 | tcp_socket.bind(("", 8080)) 8 | tcp_socket.listen(5) 9 | 10 | while True: 11 | new_socket, new_address = tcp_socket.accept() 12 | while True: 13 | recv_msg = new_socket.recv(1024).decode("gb2312") 14 | if recv_msg: 15 | print("收到消息:{}".format(recv_msg)) 16 | new_socket.send("THANKS!".encode("gb2312")) 17 | if not recv_msg: 18 | print("连接丢失,已断开") 19 | new_socket.close() 20 | break 21 | tcp_socket.close() 22 | print("关闭{}客户端".format(new_address)) 23 | 24 | 25 | if __name__ == '__main__': 26 | main() 27 | -------------------------------------------------------------------------------- /PythonCode/Spider--Aitaotu.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | from bs4 import BeautifulSoup 4 | from urllib import request 5 | from threading import Thread 6 | 7 | 8 | class HttpRequest(object): 9 | """docstring for HttpRequest""" 10 | 11 | @staticmethod 12 | def request_url(url): 13 | # 得到url地址,进行连接 14 | # 判断是否链接成功,如果成功,获取内容并返回 15 | 16 | url_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' 17 | req = request.Request(url) 18 | req.add_header('User-Agent', url_agent) 19 | req = request.urlopen(req) 20 | if req.code == 200: 21 | context = req.read() 22 | return context 23 | else: 24 | print('code==', req.code) 25 | 26 | 27 | class StartSpider(object): 28 | """docstring for StartSpider""" 29 | 30 | def __init__(self, spath="d:/", baseurl=''): 31 | self.spath = spath 32 | self.baseurl = baseurl 33 | self.download_list = [] 34 | 35 | def start(self, url): 36 | # 连接网页,返回内容 37 | # 判断内容 38 | # 如果有内容,开爬 39 | # 下载后判断是否有下一页,有的话进入继续爬 40 | # 如果没有下一页,进入下一套图,继续爬 41 | page = HttpRequest.request_url(url) 42 | if page: 43 | context = BeautifulSoup(page, 'lxml') 44 | if url not in self.download_list: 45 | self.parse_page(context) 46 | self.download_list.append(url) 47 | next_page = self.get_next_page(context) 48 | if next_page: 49 | self.start(next_page) 50 | 51 | def parse_page(self, context): 52 | # 分析网页中的文件 53 | # 如果文件存在,调用下载函数下载 54 | title = list(context.h1.strings)[0] 55 | retitle = title.replace('(', '.').replace(')', '.') 56 | retitle = title.replace('[', '.').replace(']', '.') 57 | pic_list = context.find_all(alt=re.compile(retitle)) 58 | for pic in pic_list: 59 | try: 60 | picurl = pic['src'] 61 | picname = picurl.rsplit('/', 1)[1] 62 | Thread(target=self.save_image, args=( 63 | title, picurl, picname)).start() 64 | except Exception as e: 65 | print('有图片src错误') 66 | # self.save_image(title, picurl, picname) 67 | 68 | def save_image(self, title, url, name): 69 | # 得到要下载的连接和名字 70 | # 保存 71 | print('正在保存:%s图集的%s' % (title, name)) 72 | if not os.path.exists('d:/aitaotu/' + title): 73 | os.mkdir('d:/aitaotu/' + title) 74 | file = os.path.join(self.spath, title, name) 75 | request.urlretrieve(url, file) 76 | 77 | def get_next_page(self, context): 78 | # 分析链接,判断是否有下一页 79 | # 有的话将下一页链接返回 80 | # 如果没有的话,将下一套图链接返回 81 | a = context.find('a', string='下一页') 82 | b = context.find(class_='preandnext connext') 83 | next_page = a['href'] if a else b.a['href'] if b else '' 84 | if next_page: 85 | go_next = self.baseurl + next_page 86 | return go_next 87 | 88 | 89 | if __name__ == '__main__': 90 | baseurl = 'https://www.aitaotu.com' 91 | targeturl = 'https://www.aitaotu.com/guonei/34463.html' 92 | filepath = 'd:/aitaotu/' 93 | startspider = StartSpider(filepath, baseurl) 94 | startspider.start(targeturl) 95 | -------------------------------------------------------------------------------- /PythonCode/Spider--DoubanTop250.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | from urllib import request 4 | 5 | 6 | class HttpRequest(object): 7 | """docstring for UrllibRequest""" 8 | 9 | def urllib_request(self, url): 10 | # 使用urlopen打开url并赋值给req 11 | req = request.urlopen(url) 12 | # 得到返回的code状态码 13 | if req.code == 200: 14 | # 如果200成功,读取页面信息,赋值给context 15 | print("连接成功...") 16 | context = req.read() 17 | # 将context返回出去 18 | return context 19 | 20 | 21 | class DoubanSpider(object): 22 | """docstring for DoubanSpider""" 23 | 24 | def __init__(self, spath='./', baseurl=""): 25 | self.spath = spath 26 | self.baseurl = baseurl 27 | 28 | def start_req_url(self, url): 29 | # 调用HttpRequest.urllib_request,会返回context 30 | page = HttpRequest().urllib_request(url) 31 | # 如果返回context为真,即得到了context数据 32 | if page: 33 | # 将context解码重新赋值给context 34 | context = page.decode('utf-8') 35 | # 获取当前页面需要的信息并进行处理 36 | self.parse_page(context) 37 | # 完成信息处理后获取下一页信息,使用正则获取 38 | nexturl = self.get_next_page(context) 39 | # 如果有下一页,则重新调用start_req_url方法,将下一页的url传入 40 | if nexturl: 41 | self.start_req_url(nexturl) 42 | else: 43 | print("所有连接获取完毕,请检查结果") 44 | 45 | def parse_page(self, context): 46 | # 使用正则获取标题和图片链接 47 | target = re.findall(r'alt="(.+)" src="(.+)" cl', context) 48 | # 使用if判断是否获取 49 | if target: 50 | # 如果获取到内容,使用name和url接收 51 | for name, url in target: 52 | # 提升人类友善度,获取url最后的格式结尾并追加给name 53 | tail = url.rsplit('.', 1)[1] 54 | name += '.' + tail 55 | # 调用saveImage保存文件,传入url和修改后的name 56 | self.save_image(name, url) 57 | 58 | def save_image(self, name, url): 59 | print('当前正在获取:', name) 60 | # 考虑多平台使用,使用os.path.join将路径和文件名拼接 61 | filepath = os.path.join(self.spath, name) 62 | # 使用urlretrieve保存文件 63 | request.urlretrieve(url, filepath) 64 | 65 | def get_next_page(self, context): 66 | # 使用正则获取下一页的链接 67 | nextpage = re.search('后页', context) 68 | # 使用if判断链接是否被抓取到 69 | if nextpage: 70 | # 如果有下一页,将下一页信息返回出去 71 | return self.baseurl + nextpage.groups()[0] 72 | 73 | 74 | if __name__ == '__main__': 75 | requrl = "https://movie.douban.com/top250" 76 | spath = '/home/ubuntu/spider/douban250/' 77 | doubanspider = DoubanSpider(spath, requrl) 78 | doubanspider.start_req_url(requrl) 79 | -------------------------------------------------------------------------------- /PythonCode/Spider--GetProxyIPAddress.py: -------------------------------------------------------------------------------- 1 | from fake_useragent import FakeUserAgent 2 | from urllib import request 3 | from bs4 import BeautifulSoup 4 | # from threading import Thread 5 | from multiprocessing import Pool 6 | 7 | 8 | class GetFakeAgent(object): 9 | 10 | @staticmethod 11 | def get_agent(choice='random'): 12 | # 获取伪装Agent 13 | ua = FakeUserAgent() 14 | browser = {'safari': ua.safari, 15 | 'random': ua.random, 16 | 'chrome': ua.chrome, 17 | 'ie': ua.internetexplorer, 18 | 'opera': ua.opera, 19 | 'firefox': ua.firefox} 20 | return {'User-Agent': browser[choice]} 21 | 22 | 23 | class GetProxyIP(object): 24 | 25 | def __init__(self, save_path='./'): 26 | self.save_path = save_path 27 | 28 | def get_proxy(self, url, choice='random'): 29 | request_page = self.req_page(url, choice) 30 | checked_list = self.parse_page(request_page) 31 | self.save_proxy(checked_list) 32 | 33 | def req_page(self, url, choice): 34 | headers = GetFakeAgent.get_agent(choice) 35 | req_hd = request.Request(url, headers=headers) 36 | req = request.urlopen(req_hd) 37 | if req.code == 200: 38 | return req 39 | 40 | def parse_page(self, obj): 41 | if obj: 42 | con = BeautifulSoup(obj, 'html5lib') 43 | ip_text = con.body.text.split('\n\t\n\n\n') 44 | proxy_ip_list = ip_text[0].split("\n\t\t") 45 | if len(proxy_ip_list) > 0: 46 | pools = Pool(5) 47 | checked_list = [] 48 | for ip in proxy_ip_list: 49 | checked_list.append( 50 | pools.apply_async( 51 | self.check_proxy, (ip,))) 52 | pools.close() 53 | pools.join() 54 | checked_list = [x.get() for x in checked_list if x.get()] 55 | return checked_list 56 | else: 57 | print('没有获取到ip信息,请检查...') 58 | 59 | def save_proxy(self, checked_list): 60 | with open(self.save_path + "proxylist.txt", 'w+') as f: 61 | for ip in checked_list: 62 | f.write(ip + '\r\n') 63 | with open(self.save_path + "proxylist.txt", 'r+') as f: 64 | count = len(f.readlines()) 65 | if count == 0: 66 | print('没有可用的代理,请重新获取...') 67 | else: 68 | print('获取了{}个可用代理,请检查结果...'.format(count)) 69 | 70 | def check_proxy(self, ip, site='httpbin'): 71 | check_site = {'httpbin': 'http://httpbin.org/get', 72 | 'ip138': 'http://2017.ip138.com/ic.asp'} 73 | proxy_hd = request.ProxyHandler({'http': ip}) 74 | opener = request.build_opener(proxy_hd) 75 | try: 76 | req = opener.open(check_site[site], timeout=1) 77 | if ip.split(':')[0] in req.read().decode('gb2312'): 78 | print(ip, '验证成功') 79 | return ip 80 | except Exception as e: 81 | pass 82 | 83 | 84 | if __name__ == '__main__': 85 | save_path = './' 86 | how_many = input('获取多少代理ip? :') 87 | proxy_site = 'http://www.66ip.cn/mo.php?sxb=&tqsl=' + how_many 88 | get_proxy_ip = GetProxyIP(save_path) 89 | get_proxy_ip.get_proxy(proxy_site, 'random') 90 | -------------------------------------------------------------------------------- /PythonCode/Spider--Lianjia.py: -------------------------------------------------------------------------------- 1 | from bs4 import BeautifulSoup 2 | from urllib import request 3 | from http import cookiejar 4 | import gzip 5 | import csv 6 | 7 | 8 | class WebSpider(object): 9 | """docstring for WebSpider""" 10 | 11 | def __init__(self, spath='./', baseurl='', headinfo=None, info=None, url_name=None): 12 | # 定义初始属性 13 | ck = cookiejar.CookieJar() 14 | cookie = request.HTTPCookieProcessor(ck) 15 | httphd = request.HTTPHandler(debuglevel=0) 16 | httpshd = request.HTTPSHandler(debuglevel=0) 17 | self.opener = request.build_opener(httphd, httpshd, cookie) 18 | self.spath = spath 19 | self.baseurl = baseurl 20 | self.headinfo = headinfo 21 | self.search_name = info 22 | self.frist_write = True 23 | self.rec_list = [] 24 | self.web_site = "" 25 | self.url_name = url_name 26 | self.page_num = 1 27 | 28 | def start(self, url): 29 | # 得到地址,使用HttpRequest.get_request得到页面信息 30 | # 得到返回值后进行页面解析 31 | req = self.get_request(url) 32 | if req: 33 | self.parse_page(req) 34 | 35 | def get_request(self, url): 36 | reqhd = request.Request(url, headers=self.headinfo) 37 | req = self.opener.open(reqhd) 38 | if req.code == 200: 39 | con = req.read() 40 | con = gzip.decompress(con) 41 | con = con.decode('utf-8') 42 | return con 43 | else: 44 | print('someting wrong! maybe need check! ') 45 | 46 | def parse_page(self, obj): 47 | # 解析页面,得到相关信息 48 | # 保存页面 49 | obj = BeautifulSoup(obj, 'lxml') 50 | house_list = obj.find_all('a', attrs={'data-el': 'ershoufang', 51 | 'class': 'img '}) 52 | for item in house_list: 53 | if item['href'] not in self.rec_list: 54 | house_obj = self.get_request(item['href']) 55 | self.get_detail(house_obj) 56 | print("进入链接:", item['href']) 57 | self.rec_list.append(item['href']) 58 | else: 59 | print("本次搜索区域所有房屋探索完毕,程序运行结束,请检查结果。") 60 | break 61 | next_page = self.get_next_page(obj) 62 | if next_page: 63 | self.start(next_page) 64 | 65 | def get_detail(self, obj): 66 | # 得到页面,处理信息 67 | # 获取顶部信息 68 | house_details = [] 69 | 70 | obj = BeautifulSoup(obj, 'lxml') 71 | content = obj.find('div', attrs={'class': 'content'}) 72 | removelist = ['关注房源', '下载链家APP', '房源动态早知道', '预约看房', '已加入待看'] 73 | title_info = [x for x in content.text.split( 74 | '\n') if x.strip() and x not in removelist] 75 | print('开始探索新房源:', title_info[0]) 76 | 77 | # 价格信息 78 | price_info = obj.find("div", class_='price').text.replace( 79 | '正在获取首付和月供...', '').replace('万', '万!!').replace( 80 | ' 首付及税费情况请咨询经纪人 ', '').split('!!') 81 | 82 | # 房屋信息 83 | obj.select('.aroundInfo .label') 84 | house_info = [] 85 | for item in obj.select('.aroundInfo .label'): 86 | house_info += item.next_sibling.text.replace( 87 | '举报', '').split('\xa0') 88 | 89 | # 基本信息 90 | baseinfo = obj.find('div', attrs={'class': 'newwrap baseinform'}) 91 | base_info = [] 92 | for item in baseinfo.find_all('span', class_='label'): 93 | item = item.parent.text.replace('\n', '') 94 | base_info.append(item[4:].strip()) 95 | 96 | # 更多信息 97 | basemore = obj.find( 98 | 'div', attrs={'class': 'introContent showbasemore'}) 99 | more_info = [] 100 | for item in basemore.findAll('div', class_='baseattribute clear'): 101 | item = item.text.replace('\n', '').replace(' ', '') 102 | if not item[:4] == '核心卖点': 103 | more_info.append(item[4:].strip()) 104 | 105 | # 经纪人信息 106 | broker_info = obj.find('div', attrs={'class': 'brokerInfoText fr'}) 107 | broker_info = broker_info.text.replace('微信扫码拨号', '').replace( 108 | '400', '链家400').replace('/', '链家').split('链家') 109 | 110 | house_details += title_info 111 | house_details += price_info 112 | house_details += house_info 113 | house_details += base_info 114 | # house_details += more_info 115 | house_details += broker_info 116 | 117 | self.save_page(house_details) 118 | 119 | def save_page(self, obj): 120 | # 得到页面信息 121 | # 保存 122 | # f = open(self.spath + '链家房源信息.txt', 'a+') 123 | # f.write(str(obj) + '\r\n') 124 | # f.close() 125 | 126 | csvfile = open(self.spath + 'lianjia.csv', 'a+') 127 | writer = csv.writer(csvfile) 128 | if self.frist_write: 129 | writer.writerow(['标题', '特色卖点', '关注人数', '看房人数', '售价', '平方单价', 130 | '小区名称', '二级区域', '三级区域', '四级区域', '看房时间', 131 | '链家编号', '房屋户型', '所在楼层', '建筑面积', '户型结构', 132 | '套内面积', '建筑类型', '房屋朝向', '建筑结构', '装修情况', 133 | '梯户比例', '供暖方式', '配备电梯', '产权年限', '挂牌时间', 134 | '交易权属', '上次交易', '房屋用途', '房屋年限', '产权所属', 135 | '抵押信息', '房本备件', '经纪人姓名', '经纪人评分', '评价人数', 136 | '经纪人电话']) 137 | self.frist_write = False 138 | writer.writerow(obj) 139 | csvfile.close() 140 | 141 | def get_next_page(self, obj): 142 | # 得到下一页信息 143 | if self.web_site == '': 144 | self.web_site = obj.find('a', string=self.search_name)['href'] 145 | self.page_num += 1 146 | next_page = self.baseurl + 'pg' + \ 147 | str(self.page_num) + 'rs' + self.url_name 148 | if self.web_site: 149 | print("本页房源探索完毕,进入第", self.page_num, "页继续进行探索...") 150 | return next_page 151 | 152 | 153 | if __name__ == '__main__': 154 | info = input("要搜索的内容:") 155 | url_name = request.quote(info) 156 | headinfo = { 157 | # 'Host': 'www.lagou.com', 158 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 159 | 'Referer': 'http://bj.lianjia.com/ershoufang/rs' + url_name + '/', 160 | 'Accept-Encoding': 'gzip, deflate', 161 | 'Accept-Language': 'zh-CN,zh;q=0.9', 162 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' 163 | } 164 | baseurl = 'http://bj.lianjia.com/ershoufang/' 165 | requrl = "http://bj.lianjia.com/ershoufang/rs" + url_name 166 | path = './lianjia/' 167 | webspider = WebSpider(path, baseurl, headinfo, info, url_name) 168 | webspider.start(requrl) 169 | -------------------------------------------------------------------------------- /PythonCode/Spider--Pic360.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from urllib import request 3 | import os 4 | from fake_useragent import FakeUserAgent 5 | 6 | 7 | class GetFakeAgent(object): 8 | """docstring for GetFakeAgent""" 9 | 10 | @staticmethod 11 | def get_agent(choice='random'): 12 | # 获取伪装Agent 13 | ua = FakeUserAgent() 14 | browser = {'safari': ua.safari, 15 | 'random': ua.random, 16 | 'chrome': ua.chrome, 17 | 'ie': ua.internetexplorer, 18 | 'opera': ua.opera, 19 | 'firefox': ua.firefox} 20 | return {'User-Agent': browser[choice]} 21 | 22 | 23 | class StartSpider(object): 24 | """docstring for StartSpider""" 25 | 26 | def __init__(self, info, spath='./360pic/', sn=0, size='small'): 27 | self.payload = {'q': info, 28 | 'correct': info, 29 | 'pn': 60, 30 | 'sn': sn, 31 | 'kn': 16, 32 | } 33 | self.requrl = 'http://image.so.com/j' 34 | self.picsize = size 35 | self.spath = spath 36 | 37 | def get_request(self): 38 | headers = GetFakeAgent.get_agent() 39 | req360 = requests.get(self.requrl, 40 | params=self.payload, 41 | headers=headers) 42 | if req360.status_code == 200: 43 | self.parse_json(req360) 44 | else: 45 | print("Status Code is not 200, please check it.") 46 | 47 | def parse_json(self, obj): 48 | image_list = obj.json()['list'] 49 | for pic in image_list: 50 | pic_url = pic['_thumb'] if self.picsize == 'small' else pic['img'] 51 | pic_name = pic['id'] + '.' + pic_url.rsplit('.', 1)[1] 52 | self.save_pic(pic_url, pic_name) 53 | 54 | def save_pic(self, url, name): 55 | if not os.path.exists(self.spath): 56 | os.mkdir(self.spath) 57 | print('Download: ', name) 58 | try: 59 | request.urlretrieve(url, self.spath + name) 60 | except Exception as e: 61 | print(e) 62 | 63 | 64 | if __name__ == '__main__': 65 | search_info = "大头照" 66 | start_num = 136 # 默认自起始值开始请求60页,但实际请求数量不确定 67 | picsize = 'small' # small为缩略图,large为原图 68 | spath = './360pic/' 69 | startspider = StartSpider(search_info, spath, start_num, picsize) 70 | startspider.get_request() 71 | -------------------------------------------------------------------------------- /PythonCode/Spider--Xiaoxiang.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import os 3 | from GetFakeUserAgent import GetFakeAgent 4 | from bs4 import BeautifulSoup 5 | 6 | 7 | class StartSpider(object): 8 | """docstring for StartSpider""" 9 | 10 | def __init__(self, base_url, save_path='./'): 11 | self.headers = GetFakeAgent.get_agent() 12 | self.base_url = base_url 13 | self.save_path = save_path 14 | self.book_name = '' 15 | 16 | def start_req(self, url): 17 | self.parse_page(url) 18 | 19 | def get_soup(self, url): 20 | req = requests.get(url, headers=self.headers) 21 | if req.status_code == 200: 22 | return BeautifulSoup(req.text, 'lxml') 23 | 24 | def parse_page(self, url): 25 | soup = self.get_soup(url) 26 | book_list = soup.find_all('h4') 27 | for book in book_list: 28 | self.book_name = book.a.text 29 | book_id = book.a['href'].replace('/info/', '').replace('.html', '') 30 | self.get_chapter(book_id) 31 | 32 | def get_chapter(self, book_id): 33 | url = "http://www.xxsy.net/partview/GetChapterList?bookid=" + \ 34 | book_id + "&noNeedBuy=1&special=0" 35 | soup = self.get_soup(url) 36 | chapter_list = soup.find_all('a') 37 | for chapter in chapter_list: 38 | chapter_url = chapter['href'] 39 | chapter_name = chapter.text 40 | self.get_chapter_text(chapter_url, chapter_name) 41 | 42 | def get_chapter_text(self, url, name): 43 | soup = self.get_soup(self.base_url + url) 44 | text_list = soup.select('.chapter-main p') 45 | self.save_text(text_list, name) 46 | 47 | def save_text(self, lines_list, name): 48 | book_path = self.save_path + self.book_name 49 | if not os.path.exists(book_path): 50 | os.mkdir(book_path) 51 | print('正在保存{}:{}'.format(self.save_path.rsplit('/', 1)[1], name)) 52 | with open(book_path + '/' + name + '.txt', 'w') as f: 53 | for line in lines_list: 54 | if '本书由潇湘书院首发,请勿转载' not in line.text: 55 | f.write(line.text + '\r\n') 56 | 57 | 58 | if __name__ == '__main__': 59 | book_url = 'http://www.xxsy.net/search?vip=0&sort=2' 60 | base_url = 'http://www.xxsy.net' 61 | save_path = './xiaoshuo/' 62 | startspider = StartSpider(base_url, save_path) 63 | startspider.start_req(book_url) 64 | -------------------------------------------------------------------------------- /Python知识点汇总: -------------------------------------------------------------------------------- 1 | # _*_ coding: utf-8 _*_ 2 | 3 | """类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算""" 4 | 5 | #-- 寻求帮助: 6 | dir(obj) # 简单的列出对象obj所包含的方法名称,返回一个字符串列表 7 | help(obj.func) # 查询obj.func的具体介绍和用法 8 | 9 | #-- 测试类型的三种方法,推荐第三种 10 | if type(L) == type([]): print("L is list") 11 | if type(L) == list: print("L is list") 12 | if isinstance(L, list): print("L is list") 13 | 14 | #-- Python数据类型:哈希类型、不可哈希类型 15 | # 哈希类型,即在原地不能改变的变量类型,不可变类型。可利用hash函数查看其hash值,也可以作为字典的key 16 | "数字类型:int, float, decimal.Decimal, fractions.Fraction, complex" 17 | "字符串类型:str, bytes" 18 | "元组:tuple" 19 | "冻结集合:frozenset" 20 | "布尔类型:True, False" 21 | "None" 22 | # 不可hash类型:原地可变类型:list、dict和set。它们不可以作为字典的key。 23 | 24 | #-- 数字常量 25 | 1234, -1234, 0, 999999999 # 整数 26 | 1.23, 1., 3.14e-10, 4E210, 4.0e+210 # 浮点数 27 | 0o177, 0x9ff, 0X9FF, 0b101010 # 八进制、十六进制、二进制数字 28 | 3+4j, 3.0+4.0j, 3J # 复数常量,也可以用complex(real, image)来创建 29 | hex(I), oct(I), bin(I) # 将十进制数转化为十六进制、八进制、二进制表示的“字符串” 30 | int(str, base) # 将字符串转化为整数,base为进制数 31 | # 2.x中,有两种整数类型:一般整数(32位)和长整数(无穷精度)。可以用l或L结尾,迫使一般整数成为长整数 32 | float('inf'), float('-inf'), float('nan') # 无穷大, 无穷小, 非数 33 | 34 | #-- 数字的表达式操作符 35 | yield x # 生成器函数发送协议 36 | lambda args: expression # 生成匿名函数 37 | x if y else z # 三元选择表达式 38 | x and y, x or y, not x # 逻辑与、逻辑或、逻辑非 39 | x in y, x not in y # 成员对象测试 40 | x is y, x is not y # 对象实体测试 41 | xy, x>=y, x==y, x!=y # 大小比较,集合子集或超集值相等性操作符 42 | 1 < a < 3 # Python中允许连续比较 43 | x|y, x&y, x^y # 位或、位与、位异或 44 | x<>y # 位操作:x左移、右移y位 45 | +, -, *, /, //, %, ** # 真除法、floor除法:返回不大于真除法结果的整数值、取余、幂运算 46 | -x, +x, ~x # 一元减法、识别、按位求补(取反) 47 | x[i], x[i:j:k], x(……) # 索引、分片、调用 48 | int(3.14), float(3) # 强制类型转换 49 | 50 | #-- 整数可以利用bit_length函数测试所占的位数 51 | a = 1; a.bit_length() # 1 52 | a = 1024; a.bit_length() # 11 53 | 54 | #-- repr和str显示格式的区别 55 | """ 56 | repr格式:默认的交互模式回显,产生的结果看起来它们就像是代码。 57 | str格式:打印语句,转化成一种对用户更加友好的格式。 58 | """ 59 | 60 | #-- 数字相关的模块 61 | # math模块 62 | # Decimal模块:小数模块 63 | import decimal 64 | from decimal import Decimal 65 | Decimal("0.01") + Decimal("0.02") # 返回Decimal("0.03") 66 | decimal.getcontext().prec = 4 # 设置全局精度为4 即小数点后边4位 67 | # Fraction模块:分数模块 68 | from fractions import Fraction 69 | x = Fraction(4, 6) # 分数类型 4/6 70 | x = Fraction("0.25") # 分数类型 1/4 接收字符串类型的参数 71 | 72 | #-- 集合set 73 | """ 74 | set是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素。 75 | set支持union(联合), intersection(交), difference(差)和sysmmetric difference(对称差集)等数学运算。 76 | set支持x in set, len(set), for x in set。 77 | set不记录元素位置或者插入点, 因此不支持indexing, slicing, 或其它类序列的操作 78 | """ 79 | s = set([3,5,9,10]) # 创建一个数值集合,返回{3, 5, 9, 10} 80 | t = set("Hello") # 创建一个唯一字符的集合返回{} 81 | a = t | s t.union(s) # t 和 s的并集 82 | b = t & s t.intersection(s) # t 和 s的交集 83 | c = t – s t.difference(s) # 求差集(项在t中, 但不在s中) 84 | d = t ^ s t.symmetric_difference(s) # 对称差集(项在t或s中, 但不会同时出现在二者中) 85 | t.add('x') t.remove('H') # 增加/删除一个item 86 | t.update([10,37,42]) # 利用[......]更新s集合 87 | x in s, x not in s # 集合中是否存在某个值 88 | s.issubset(t) s.issuperset(t) s.copy() s.discard(x) s.clear() 89 | {x**2 for x in [1, 2, 3, 4]} # 集合解析,结果:{16, 1, 4, 9} 90 | {x for x in 'spam'} # 集合解析,结果:{'a', 'p', 's', 'm'} 91 | 92 | #-- 集合frozenset,不可变对象 93 | """ 94 | set是可变对象,即不存在hash值,不能作为字典的键值。同样的还有list、tuple等 95 | frozenset是不可变对象,即存在hash值,可作为字典的键值 96 | frozenset对象没有add、remove等方法,但有union/intersection/difference等方法 97 | """ 98 | a = set([1, 2, 3]) 99 | b = set() 100 | b.add(a) # error: set是不可哈希类型 101 | b.add(frozenset(a)) # ok,将set变为frozenset,可哈希 102 | 103 | #-- 布尔类型bool 104 | type(True) # 返回 105 | isinstance(False, int) # bool类型属于整形,所以返回True 106 | True == 1, True is 1 # 输出(True, False) 107 | 108 | #-- 动态类型简介 109 | """ 110 | 变量名通过引用,指向对象。 111 | Python中的“类型”属于对象,而不是变量,每个对象都包含有头部信息,比如"类型标示符" "引用计数器"等 112 | """ 113 | #共享引用及在原处修改:对于可变对象,要注意尽量不要共享引用! 114 | #共享引用和相等测试: 115 | L = [1], M = [1], L is M # 返回False 116 | L = M = [1, 2, 3], L is M # 返回True,共享引用 117 | #增强赋值和共享引用:普通+号会生成新的对象,而增强赋值+=会在原处修改 118 | L = M = [1, 2] 119 | L = L + [3, 4] # L = [1, 2, 3, 4], M = [1, 2] 120 | L += [3, 4] # L = [1, 2, 3, 4], M = [1, 2, 3, 4] 121 | 122 | #-- 常见字符串常量和表达式 123 | S = '' # 空字符串 124 | S = "spam’s" # 双引号和单引号相同 125 | S = "s\np\ta\x00m" # 转义字符 126 | S = """spam""" # 三重引号字符串,一般用于函数说明 127 | S = r'\temp' # Raw字符串,不会进行转义,抑制转义 128 | S = b'Spam' # Python3中的字节字符串 129 | S = u'spam' # Python2.6中的Unicode字符串 130 | s1+s2, s1*3, s[i], s[i:j], len(s) # 字符串操作 131 | 'a %s parrot' % 'kind' # 字符串格式化表达式 132 | 'a {0} parrot'.format('kind') # 字符串格式化方法 133 | for x in s: print(x) # 字符串迭代,成员关系 134 | [x*2 for x in s] # 字符串列表解析 135 | ','.join(['a', 'b', 'c']) # 字符串输出,结果:a,b,c 136 | 137 | #-- 内置str处理函数: 138 | str.upper() str.lower() str.swapcase() str.capitalize() str.title() # 全部大写,全部小写、大小写转换,首字母大写,每个单词的首字母都大写 139 | str.ljust(width) # 获取固定长度,右对齐,左边不够用空格补齐 140 | str.rjust(width) # 获取固定长度,左对齐,右边不够用空格补齐 141 | str.center(width) # 获取固定长度,中间对齐,两边不够用空格补齐 142 | str.zfill(width) # 获取固定长度,右对齐,左边不足用0补齐 143 | str.find('t',start,end) # 查找字符串,可以指定起始及结束位置搜索 144 | str.rfind('t') # 从右边开始查找字符串 145 | str.count('t') # 查找字符串出现的次数 146 | #上面所有方法都可用index代替,不同的是使用index查找不到会抛异常,而find返回-1 147 | str.replace('old','new') # 替换函数,替换old为new,参数中可以指定maxReplaceTimes,即替换指定次数的old为new 148 | str.strip() str.lstrip() str.rstrip() str.strip('d') str.lstrip('d') str.rstrip('d') 149 | str.startswith('start') # 是否以start开头 150 | str.endswith('end') # 是否以end结尾 151 | str.isalnum() str.isalpha() str.isdigit() str.islower() str.isupper() # 判断字符串是否全为字符、数字、大写、小写 152 | 153 | #-- 三重引号编写多行字符串块,并且在代码折行处嵌入换行字符\n 154 | mantra = """hello world 155 | hello python 156 | hello my friend""" 157 | # mantra为"""hello world \n hello python \n hello my friend""" 158 | 159 | #-- 索引和分片: 160 | S[0], S[len(S) – 1], S[-1] # 索引 161 | S[1:3], S[1:], S[:-1], S[1:10:2] # 分片,第三个参数指定步长 162 | 163 | #-- 字符串转换工具: 164 | int('42'), str(42) # 返回(42, '42') 165 | float('4.13'), str(4.13) # 返回(4.13, '4.13') 166 | ord('s'), chr(115) # 返回(115, 's') 167 | int('1001', 2) # 将字符串作为二进制数字,转化为数字,返回13 168 | bin(13), oct(13), hex(13) # 将整数转化为二进制/八进制/十六进制字符串,返回('1001', '0o15', '0xd') 169 | 170 | #-- 另类字符串连接 171 | name = "wang" "hong" #单行,name = "wanghong" 172 | name = "wang" \ 173 | "hong" #多行,name = "wanghong" 174 | 175 | #-- Python中的字符串格式化实现1--字符串格式化表达式 176 | """ 177 | 基于C语言的'print'模型,并且在大多数的现有的语言中使用。 178 | 通用结构:%[(name)][flag][width].[precision]typecode 179 | """ 180 | "this is %d %s bird" % (1, 'dead') # 一般的格式化表达式 181 | "%s---%s---%s" % (42, 3.14, [1, 2, 3]) # 字符串输出:'42---3.14---[1, 2, 3]' 182 | "%d...%6d...%-6d...%06d" % (1234, 1234, 1234, 1234) # 对齐方式及填充:"1234... 1234...1234 ...001234" 183 | x = 1.23456789 184 | "%e | %f | %g" % (x, x, x) # 对齐方式:"1.234568e+00 | 1.234568 | 1.23457" 185 | "%6.2f*%-6.2f*%06.2f*%+6.2f" % (x, x, x, x) # 对齐方式:' 1.23*1.23 *001.23* +1.23' 186 | "%(name1)d---%(name2)s" % {"name1":23, "name2":"value2"} # 基于字典的格式化表达式 187 | "%(name)s is %(age)d" % vars() # vars()函数调用返回一个字典,包含了所有本函数调用时存在的变量 188 | 189 | #-- Python中的字符串格式化实现2--字符串格式化调用方法 190 | # 普通调用 191 | "{0}, {1} and {2}".format('spam', 'ham', 'eggs') # 基于位置的调用 192 | "{motto} and {pork}".format(motto = 'spam', pork = 'ham') # 基于Key的调用 193 | "{motto} and {0}".format(ham, motto = 'spam') # 混合调用 194 | # 添加键 属性 偏移量 (import sys) 195 | "my {1[spam]} runs {0.platform}".format(sys, {'spam':'laptop'}) # 基于位置的键和属性 196 | "{config[spam]} {sys.platform}".format(sys = sys, config = {'spam':'laptop'}) # 基于Key的键和属性 197 | "first = {0[0]}, second = {0[1]}".format(['A', 'B', 'C']) # 基于位置的偏移量 198 | # 具体格式化 199 | "{0:e}, {1:.3e}, {2:g}".format(3.14159, 3.14159, 3.14159) # 输出'3.141590e+00, 3.142e+00, 3.14159' 200 | "{fieldname:format_spec}".format(......) 201 | # 说明: 202 | """ 203 | fieldname是指定参数的一个数字或关键字, 后边可跟可选的".name"或"[index]"成分引用 204 | format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type] 205 | fill ::= #填充字符 206 | align ::= "<" | ">" | "=" | "^" #对齐方式 207 | sign ::= "+" | "-" | " " #符号说明 208 | width ::= integer #字符串宽度 209 | precision ::= integer #浮点数精度 210 | type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" 211 | """ 212 | # 例子: 213 | '={0:10} = {1:10}'.format('spam', 123.456) # 输出'=spam = 123.456' 214 | '={0:>10}='.format('test') # 输出'= test=' 215 | '={0:<10}='.format('test') # 输出'=test =' 216 | '={0:^10}='.format('test') # 输出'= test =' 217 | '{0:X}, {1:o}, {2:b}'.format(255, 255, 255) # 输出'FF, 377, 11111111' 218 | 'My name is {0:{1}}.'.format('Fred', 8) # 输出'My name is Fred .' 动态指定参数 219 | 220 | #-- 常用列表常量和操作 221 | L = [[1, 2], 'string', {}] # 嵌套列表 222 | L = list('spam') # 列表初始化 223 | L = list(range(0, 4)) # 列表初始化 224 | list(map(ord, 'spam')) # 列表解析 225 | len(L) # 求列表长度 226 | L.count(value) # 求列表中某个值的个数 227 | L.append(obj) # 向列表的尾部添加数据,比如append(2),添加元素2 228 | L.insert(index, obj) # 向列表的指定index位置添加数据,index及其之后的数据后移 229 | L.extend(interable) # 通过添加iterable中的元素来扩展列表,比如extend([2]),添加元素2,注意和append的区别 230 | L.index(value, [start, [stop]]) # 返回列表中值value的第一个索引 231 | L.pop([index]) # 删除并返回index处的元素,默认为删除并返回最后一个元素 232 | L.remove(value) # 删除列表中的value值,只删除第一次出现的value的值 233 | L.reverse() # 反转列表 234 | L.sort(cmp=None, key=None, reverse=False) # 排序列表 235 | a = [1, 2, 3], b = a[10:] # 注意,这里不会引发IndexError异常,只会返回一个空的列表[] 236 | a = [], a += [1] # 这里实在原有列表的基础上进行操作,即列表的id没有改变 237 | a = [], a = a + [1] # 这里最后的a要构建一个新的列表,即a的id发生了变化 238 | 239 | #-- 用切片来删除序列的某一段 240 | a = [1, 2, 3, 4, 5, 6, 7] 241 | a[1:4] = [] # a = [1, 5, 6, 7] 242 | a = [0, 1, 2, 3, 4, 5, 6, 7] 243 | del a[::2] # 去除偶数项(偶数索引的),a = [1, 3, 5, 7] 244 | 245 | #-- 常用字典常量和操作 246 | D = {} 247 | D = {'spam':2, 'tol':{'ham':1}} # 嵌套字典 248 | D = dict.fromkeys(['s', 'd'], 8) # {'d': 8, 's': 8} 249 | D = dict(name = 'tom', age = 12) # {'age': 12, 'name': 'tom'} 250 | D = dict([('name', 'tom'), ('age', 12)]) # {'age': 12, 'name': 'tom'} 251 | D = dict(zip(['name', 'age'], ['tom', 12])) # {'age': 12, 'name': 'tom'} 252 | D.keys() D.values() D.items() # 字典键、值以及键值对 253 | D.get(key, default) # get函数 254 | D.update(D_other) # 合并字典,如果存在相同的键值,D_other的数据会覆盖掉D的数据 255 | D.pop(key, [D]) # 删除字典中键值为key的项,返回键值为key的值,如果不存在,返回默认值D,否则异常 256 | D.popitem() # pop字典中的一项(一个键值对) 257 | D.setdefault(k[, d]) # 设置D中某一项的默认值。如果k存在,则返回D[k],否则设置D[k]=d,同时返回D[k]。 258 | del D # 删除字典 259 | del D['key'] # 删除字典的某一项 260 | if key in D: if key not in D: # 测试字典键是否存在 261 | # 字典注意事项:(1)对新索引赋值会添加一项(2)字典键不一定非得是字符串,也可以为任何的不可变对象 262 | 263 | #-- 字典解析 264 | D = {k:8 for k in ['s', 'd']} # {'d': 8, 's': 8} 265 | D = {k:v for (k, v) in zip(['name', 'age'], ['tom', 12])} 266 | 267 | #-- 字典的特殊方法__missing__:当查找找不到key时,会执行该方法 268 | class Dict(dict): 269 | def __missing__(self, key): 270 | self[key] = [] 271 | return self[key] 272 | dct = Dict() 273 | dct["foo"].append(1) # 这有点类似于collections.defalutdict 274 | dct["foo"] # [1] 275 | 276 | #-- 元组和列表的唯一区别在于元组是不可变对象,列表时可变对象 277 | a = [1, 2, 3] # a[1] = 0, OK 278 | a = (1, 2, 3) # a[1] = 0, Error 279 | a = ([1, 2]) # a[0][1] = 0, OK 280 | a = [(1, 2)] # a[0][1] = 0, Error 281 | 282 | #-- 元组的特殊语法: 逗号和圆括号 283 | D = (12) # 此时D为一个整数 即D = 12 284 | D = (12, ) # 此时D为一个元组 即D = (12, ) 285 | 286 | #-- 文件基本操作 287 | output = open(r'C:\spam', 'w') # 打开输出文件,用于写 288 | input = open('data', 'r') # 打开输入文件,用于读。打开的方式可以为'w', 'r', 'a', 'wb', 'rb', 'ab'等 289 | fp.read([size]) # size为读取的长度,以byte为单位 290 | fp.readline([size]) # 读一行,如果定义了size,有可能返回的只是一行的一部分 291 | fp.readlines([size]) # 把文件每一行作为一个list的一个成员,并返回这个list。其实它的内部是通过循环调用readline()来实现的。如果提供size参数,size是表示读取内容的总长。 292 | fp.readable() # 是否可读 293 | fp.write(str) # 把str写到文件中,write()并不会在str后加上一个换行符 294 | fp.writelines(seq) # 把seq的内容全部写到文件中(多行一次性写入) 295 | fp.writeable() # 是否可写 296 | fp.close() # 关闭文件。 297 | fp.flush() # 把缓冲区的内容写入硬盘 298 | fp.fileno() # 返回一个长整型的”文件标签“ 299 | fp.isatty() # 文件是否是一个终端设备文件(unix系统中的) 300 | fp.tell() # 返回文件操作标记的当前位置,以文件的开头为原点 301 | fp.next() # 返回下一行,并将文件操作标记位移到下一行。把一个file用于for … in file这样的语句时,就是调用next()函数来实现遍历的。 302 | fp.seek(offset[,whence]) # 将文件打操作标记移到offset的位置。whence可以为0表示从头开始计算,1表示以当前位置为原点计算。2表示以文件末尾为原点进行计算。 303 | fp.seekable() # 是否可以seek 304 | fp.truncate([size]) # 把文件裁成规定的大小,默认的是裁到当前文件操作标记的位置。 305 | for line in open('data'): 306 | print(line) # 使用for语句,比较适用于打开比较大的文件 307 | open('f.txt', encoding = 'latin-1') # Python3.x Unicode文本文件 308 | open('f.bin', 'rb') # Python3.x 二进制bytes文件 309 | # 文件对象还有相应的属性:buffer closed encoding errors line_buffering name newlines等 310 | 311 | #-- 其他 312 | # Python中的真假值含义:1. 数字如果非零,则为真,0为假。 2. 其他对象如果非空,则为真 313 | # 通常意义下的类型分类:1. 数字、序列、映射。 2. 可变类型和不可变类型 314 | 315 | 316 | """语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句----语法和语句""" 317 | 318 | #-- 赋值语句的形式 319 | spam = 'spam' # 基本形式 320 | spam, ham = 'spam', 'ham' # 元组赋值形式 321 | [spam, ham] = ['s', 'h'] # 列表赋值形式 322 | a, b, c, d = 'abcd' # 序列赋值形式 323 | a, *b, c = 'spam' # 序列解包形式(Python3.x中才有) 324 | spam = ham = 'no' # 多目标赋值运算,涉及到共享引用 325 | spam += 42 # 增强赋值,涉及到共享引用 326 | 327 | #-- 序列赋值 序列解包 328 | [a, b, c] = (1, 2, 3) # a = 1, b = 2, c = 3 329 | a, b, c, d = "spam" # a = 's', b = 'p' 330 | a, b, c = range(3) # a = 0, b = 1 331 | a, *b = [1, 2, 3, 4] # a = 1, b = [2, 3, 4] 332 | *a, b = [1, 2, 3, 4] # a = [1, 2, 3], b = 4 333 | a, *b, c = [1, 2, 3, 4] # a = 1, b = [2, 3], c = 4 334 | # 带有*时 会优先匹配*之外的变量 如 335 | a, *b, c = [1, 2] # a = 1, c = 2, b = [] 336 | 337 | #-- print函数原型 338 | print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) 339 | # 流的重定向 340 | print('hello world') # 等于sys.stdout.write('hello world') 341 | temp = sys.stdout # 原有流的保存 342 | sys.stdout = open('log.log', 'a') # 流的重定向 343 | print('hello world') # 写入到文件log.log 344 | sys.stdout.close() 345 | sys.stdout = temp # 原有流的复原 346 | 347 | #-- Python中and或or总是返回对象(左边的对象或右边的对象) 且具有短路求值的特性 348 | 1 or 2 or 3 # 返回 1 349 | 1 and 2 and 3 # 返回 3 350 | 351 | #-- if/else三元表达符(if语句在行内) 352 | A = 1 if X else 2 353 | A = 1 if X else (2 if Y else 3) 354 | # 也可以使用and-or语句(一条语句实现多个if-else) 355 | result = (a > 20 and "big than 20" or a > 10 and "big than 10" or a > 5 and "big than 5") 356 | 357 | #-- Python的while语句或者for语句可以带else语句 当然也可以带continue/break/pass语句 358 | while a > 1: 359 | ...... 360 | else: 361 | ...... 362 | # else语句会在循环结束后执行,除非在循环中执行了break,同样的还有for语句 363 | for i in range(5): 364 | ...... 365 | else: 366 | ...... 367 | 368 | #-- for循环的元组赋值 369 | for (a, b) in [(1, 2), (3, 4)]: # 最简单的赋值 370 | for ((a, b), c) in [((1, 2), 3), ((4, 5), 6)]: # 自动解包赋值 371 | for ((a, b), c) in [((1, 2), 3), ("XY", 6)]: # 自动解包 a = X, b = Y, c = 6 372 | for (a, *b) in [(1, 2, 3), (4, 5, 6)]: # 自动解包赋值 373 | 374 | #-- 列表解析语法 375 | M = [[1,2,3], [4,5,6], [7,8,9]] 376 | res = [sum(row) for row in M] # G = [6, 15, 24] 一般的列表解析 生成一个列表 377 | res = [c * 2 for c in 'spam'] # ['ss', 'pp', 'aa', 'mm'] 378 | res = [a * b for a in [1, 2] for b in [4, 5]] # 多解析过程 返回[4, 5, 8, 10] 379 | res = [a for a in [1, 2, 3] if a < 2] # 带判断条件的解析过程 380 | res = [a if a > 0 else 0 for a in [-1, 0, 1]] # 带判断条件的高级解析过程 381 | # 两个列表同时解析:使用zip函数 382 | for teama, teamb in zip(["Packers", "49ers"], ["Ravens", "Patriots"]): 383 | print(teama + " vs. " + teamb) 384 | # 带索引的列表解析:使用enumerate函数 385 | for index, team in enumerate(["Packers", "49ers", "Ravens", "Patriots"]): 386 | print(index, team) # 输出0, Packers \n 1, 49ers \n ...... 387 | 388 | #-- 生成器表达式 389 | G = (sum(row) for row in M) # 使用小括号可以创建所需结果的生成器generator object 390 | next(G), next(G), next(G) # 输出(6, 15, 24) 391 | G = {sum(row) for row in M} # G = {6, 15, 24} 解析语法还可以生成集合和字典 392 | G = {i:sum(M[i]) for i in range(3)} # G = {0: 6, 1: 15, 2: 24} 393 | 394 | #-- 文档字符串:出现在Module的开端以及其中函数或类的开端 使用三重引号字符串 395 | """ 396 | module document 397 | """ 398 | def func(): 399 | """ 400 | function document 401 | """ 402 | print() 403 | class Employee: 404 | """ 405 | class document 406 | """ 407 | print() 408 | print(func.__doc__) # 输出函数文档字符串 409 | print(Employee.__doc__) # 输出类的文档字符串 410 | 411 | #-- 命名惯例: 412 | """ 413 | 以单一下划线开头的变量名(_X)不会被from module import*等语句导入 414 | 前后有两个下划线的变量名(__X__)是系统定义的变量名,对解释器有特殊意义 415 | 以两个下划线开头但不以下划线结尾的变量名(__X)是类的本地(私有)变量 416 | """ 417 | 418 | #-- 列表解析 in成员关系测试 map sorted zip enumerate内置函数等都使用了迭代协议 419 | 'first line' in open('test.txt') # in测试 返回True或False 420 | list(map(str.upper, open('t'))) # map内置函数 421 | sorted(iter([2, 5, 8, 3, 1])) # sorted内置函数 422 | list(zip([1, 2], [3, 4])) # zip内置函数 [(1, 3), (2, 4)] 423 | 424 | #-- del语句: 手动删除某个变量 425 | del X 426 | 427 | #-- 获取列表的子表的方法: 428 | x = [1,2,3,4,5,6] 429 | x[:3] # 前3个[1,2,3] 430 | x[1:5] # 中间4个[2,3,4,5] 431 | x[-3:] # 最后3个[4,5,6] 432 | x[::2] # 奇数项[1,3,5] 433 | x[1::2] # 偶数项[2,4,6] 434 | 435 | #-- 手动迭代:iter和next 436 | L = [1, 2] 437 | I = iter(L) # I为L的迭代器 438 | I.next() # 返回1 439 | I.next() # 返回2 440 | I.next() # Error:StopIteration 441 | 442 | #-- Python中的可迭代对象 443 | """ 444 | 1.range迭代器 445 | 2.map、zip和filter迭代器 446 | 3.字典视图迭代器:D.keys()), D.items()等 447 | 4.文件类型 448 | """ 449 | 450 | 451 | """函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则----函数语法规则""" 452 | 453 | #-- 函数相关的语句和表达式 454 | myfunc('spam') # 函数调用 455 | def myfunc(): # 函数定义 456 | return None # 函数返回值 457 | global a # 全局变量 458 | nonlocal x # 在函数或其他作用域中使用外层(非全局)变量 459 | yield x # 生成器函数返回 460 | lambda # 匿名函数 461 | 462 | #-- Python函数变量名解析:LEGB原则,即: 463 | """ 464 | local(functin) --> encloseing function locals --> global(module) --> build-in(python) 465 | 说明:以下边的函数maker为例 则相对于action而言 X为Local N为Encloseing 466 | """ 467 | 468 | #-- 嵌套函数举例:工厂函数 469 | def maker(N): 470 | def action(X): 471 | return X ** N 472 | return action 473 | f = maker(2) # pass 2 to N 474 | f(3) # 9, pass 3 to X 475 | 476 | #-- 嵌套函数举例:lambda实例 477 | def maker(N): 478 | action = (lambda X: X**N) 479 | return action 480 | f = maker(2) # pass 2 to N 481 | f(3) # 9, pass 3 to X 482 | 483 | #-- nonlocal和global语句的区别 484 | # nonlocal应用于一个嵌套的函数的作用域中的一个名称 例如: 485 | start = 100 486 | def tester(start): 487 | def nested(label): 488 | nonlocal start # 指定start为tester函数内的local变量 而不是global变量start 489 | print(label, start) 490 | start += 3 491 | return nested 492 | # global为全局的变量 即def之外的变量 493 | def tester(start): 494 | def nested(label): 495 | global start # 指定start为global变量start 496 | print(label, start) 497 | start += 3 498 | return nested 499 | 500 | #-- 函数参数,不可变参数通过“值”传递,可变参数通过“引用”传递 501 | def f(a, b, c): print(a, b, c) 502 | f(1, 2, 3) # 参数位置匹配 503 | f(1, c = 3, b = 2) # 参数关键字匹配 504 | def f(a, b = 1, c = 2): print(a, b, c) 505 | f(1) # 默认参数匹配 506 | f(1, 2) # 默认参数匹配 507 | f(a = 1, c = 3) # 关键字参数和默认参数的混合 508 | # Keyword-Only参数:出现在*args之后 必须用关键字进行匹配 509 | def keyOnly(a, *b, c): print('') # c就为keyword-only匹配 必须使用关键字c = value匹配 510 | def keyOnly(a, *, b, c): ...... # b c为keyword-only匹配 必须使用关键字匹配 511 | def keyOnly(a, *, b = 1): ...... # b有默认值 或者省略 或者使用关键字参数b = value 512 | 513 | #-- 可变参数匹配: * 和 ** 514 | def f(*args): print(args) # 在元组中收集不匹配的位置参数 515 | f(1, 2, 3) # 输出(1, 2, 3) 516 | def f(**args): print(args) # 在字典中收集不匹配的关键字参数 517 | f(a = 1, b = 2) # 输出{'a':1, 'b':2} 518 | def f(a, *b **c): print(a, b, c) # 两者混合使用 519 | f(1, 2, 3, x = 4, y = 5) # 输出1, (2, 3), {'x':4, 'y':5} 520 | 521 | #-- 函数调用时的参数解包: * 和 ** 分别解包元组和字典 522 | func(1, *(2, 3)) <==> func(1, 2, 3) 523 | func(1, **{'c':3, 'b':2}) <==> func(1, b = 2, c = 3) 524 | func(1, *(2, 3), **{'c':3, 'b':2}) <==> func(1, 2, 3, b = 2, c = 3) 525 | 526 | #-- 函数属性:(自己定义的)函数可以添加属性 527 | def func():..... 528 | func.count = 1 # 自定义函数添加属性 529 | print.count = 1 # Error 内置函数不可以添加属性 530 | 531 | #-- 函数注解: 编写在def头部行 主要用于说明参数范围、参数类型、返回值类型等 532 | def func(a:'spam', b:(1, 10), c:float) -> int : 533 | print(a, b, c) 534 | func.__annotations__ # {'c':, 'b':(1, 10), 'a':'spam', 'return':} 535 | # 编写注解的同时 还是可以使用函数默认值 并且注解的位置位于=号的前边 536 | def func(a:'spam'='a', b:(1, 10)=2, c:float=3) -> int : 537 | print(a, b, c) 538 | 539 | #-- 匿名函数:lambda 540 | f = lambda x, y, z : x + y + z # 普通匿名函数,使用方法f(1, 2, 3) 541 | f = lambda x = 1, y = 1: x + y # 带默认参数的lambda函数 542 | def action(x): # 嵌套lambda函数 543 | return (lambda y : x + y) 544 | f = lambda: a if xxx() else b # 无参数的lambda函数,使用方法f() 545 | 546 | #-- lambda函数与map filter reduce函数的结合 547 | list(map((lambda x: x + 1), [1, 2, 3])) # [2, 3, 4] 548 | list(filter((lambda x: x > 0), range(-4, 5))) # [1, 2, 3, 4] 549 | functools.reduce((lambda x, y: x + y), [1, 2, 3]) # 6 550 | functools.reduce((lambda x, y: x * y), [2, 3, 4]) # 24 551 | 552 | #-- 生成器函数:yield VS return 553 | def gensquare(N): 554 | for i in range(N): 555 | yield i** 2 # 状态挂起 可以恢复到此时的状态 556 | for i in gensquare(5): # 使用方法 557 | print(i, end = ' ') # [0, 1, 4, 9, 16] 558 | x = gensquare(2) # x是一个生成对象 559 | next(x) # 等同于x.__next__() 返回0 560 | next(x) # 等同于x.__next__() 返回1 561 | next(x) # 等同于x.__next__() 抛出异常StopIteration 562 | 563 | #-- 生成器表达式:小括号进行列表解析 564 | G = (x ** 2 for x in range(3)) # 使用小括号可以创建所需结果的生成器generator object 565 | next(G), next(G), next(G) # 和上述中的生成器函数的返回值一致 566 | #(1)生成器(生成器函数/生成器表达式)是单个迭代对象 567 | G = (x ** 2 for x in range(4)) 568 | I1 = iter(G) # 这里实际上iter(G) = G 569 | next(I1) # 输出0 570 | next(G) # 输出1 571 | next(I1) # 输出4 572 | #(2)生成器不保留迭代后的结果 573 | gen = (i for i in range(4)) 574 | 2 in gen # 返回True 575 | 3 in gen # 返回True 576 | 1 in gen # 返回False,其实检测2的时候,1已经就不在生成器中了,即1已经被迭代过了,同理2、3也不在了 577 | 578 | #-- 本地变量是静态检测的 579 | X = 22 # 全局变量X的声明和定义 580 | def test(): 581 | print(X) # 如果没有下一语句 则该句合法 打印全局变量X 582 | X = 88 # 这一语句使得上一语句非法 因为它使得X变成了本地变量 上一句变成了打印一个未定义的本地变量(局部变量) 583 | if False: # 即使这样的语句 也会把print语句视为非法语句 因为: 584 | X = 88 # Python会无视if语句而仍然声明了局部变量X 585 | def test(): # 改进 586 | global X # 声明变量X为全局变量 587 | print(X) # 打印全局变量X 588 | X = 88 # 改变全局变量X 589 | 590 | #-- 函数的默认值是在函数定义的时候实例化的 而不是在调用的时候 例子: 591 | def foo(numbers=[]): # 这里的[]是可变的 592 | numbers.append(9) 593 | print(numbers) 594 | foo() # first time, like before, [9] 595 | foo() # second time, not like before, [9, 9] 596 | foo() # third time, not like before too, [9, 9, 9] 597 | # 改进: 598 | def foo(numbers=None): 599 | if numbers is None: numbers = [] 600 | numbers.append(9) 601 | print(numbers) 602 | # 另外一个例子 参数的默认值为不可变的: 603 | def foo(count=0): # 这里的0是数字, 是不可变的 604 | count += 1 605 | print(count) 606 | foo() # 输出1 607 | foo() # 还是输出1 608 | foo(3) # 输出4 609 | foo() # 还是输出1 610 | 611 | 612 | """函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子----函数例子""" 613 | 614 | """数学运算类""" 615 | abs(x) # 求绝对值,参数可以是整型,也可以是复数,若参数是复数,则返回复数的模 616 | complex([real[, imag]]) # 创建一个复数 617 | divmod(a, b) # 分别取商和余数,注意:整型、浮点型都可以 618 | float([x]) # 将一个字符串或数转换为浮点数。如果无参数将返回0.0 619 | int([x[, base]]) # 将一个字符串或浮点数转换为int类型,base表示进制 620 | long([x[, base]]) # 将一个字符串或浮点数转换为long类型 621 | pow(x, y) # 返回x的y次幂 622 | range([start], stop[, step]) # 产生一个序列,默认从0开始 623 | round(x[, n]) # 四舍五入 624 | sum(iterable[, start]) # 对集合求和 625 | oct(x) # 将一个数字转化为8进制字符串 626 | hex(x) # 将一个数字转换为16进制字符串 627 | chr(i) # 返回给定int类型对应的ASCII字符 628 | unichr(i) # 返回给定int类型的unicode 629 | ord(c) # 返回ASCII字符对应的整数 630 | bin(x) # 将整数x转换为二进制字符串 631 | bool([x]) # 将x转换为Boolean类型 632 | 633 | """集合类操作""" 634 | basestring() # str和unicode的超类,不能直接调用,可以用作isinstance判断 635 | format(value [, format_spec]) # 格式化输出字符串,格式化的参数顺序从0开始,如“I am {0},I like {1}” 636 | enumerate(sequence[, start=0]) # 返回一个可枚举的对象,注意它有第二个参数 637 | iter(obj[, sentinel]) # 生成一个对象的迭代器,第二个参数表示分隔符 638 | max(iterable[, args...][key]) # 返回集合中的最大值 639 | min(iterable[, args...][key]) # 返回集合中的最小值 640 | dict([arg]) # 创建数据字典 641 | list([iterable]) # 将一个集合类转换为另外一个集合类 642 | set() # set对象实例化 643 | frozenset([iterable]) # 产生一个不可变的set 644 | tuple([iterable]) # 生成一个tuple类型 645 | str([object]) # 转换为string类型 646 | sorted(iterable[, cmp[, key[, reverse]]]) # 集合排序 647 | L = [('b',2),('a',1),('c',3),('d',4)] 648 | sorted(L, key=lambda x: x[1]), reverse=True) # 使用Key参数和reverse参数 649 | sorted(L, key=lambda x: (x[0], x[1])) # 使用key参数进行多条件排序,即如果x[0]相同,则比较x[1] 650 | 651 | """逻辑判断""" 652 | all(iterable) # 集合中的元素都为真的时候为真,特别的,若为空串返回为True 653 | any(iterable) # 集合中的元素有一个为真的时候为真,特别的,若为空串返回为False 654 | cmp(x, y) # 如果x < y ,返回负数;x == y, 返回0;x > y,返回正数 655 | 656 | """IO操作""" 657 | file(filename [, mode [, bufsize]]) # file类型的构造函数。 658 | input([prompt]) # 获取用户输入,推荐使用raw_input,因为该函数将不会捕获用户的错误输入 659 | raw_input([prompt]) # 设置输入,输入都是作为字符串处理 660 | open(name[, mode[, buffering]]) # 打开文件,与file有什么不同?推荐使用open 661 | 662 | """其他""" 663 | callable(object) # 检查对象object是否可调用 664 | classmethod(func) # 用来说明这个func是个类方法 665 | staticmethod(func) # 用来说明这个func为静态方法 666 | dir([object]) # 不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。 667 | help(obj) # 返回obj的帮助信息 668 | eval(expression) # 计算表达式expression的值,并返回 669 | exec(str) # 将str作为Python语句执行 670 | execfile(filename) # 用法类似exec(),不同的是execfile的参数filename为文件名,而exec的参数为字符串。 671 | filter(function, iterable) # 构造一个序列,等价于[item for item in iterable if function(item)],function返回值为True或False的函数 672 | list(filter(bool, range(-3, 4)))# 返回[-3, -2, -1, 1, 2, 3], 没有0 673 | hasattr(object, name) # 判断对象object是否包含名为name的特性 674 | getattr(object, name [, defalut]) # 获取一个类的属性 675 | setattr(object, name, value) # 设置属性值 676 | delattr(object, name) # 删除object对象名为name的属性 677 | globals() # 返回一个描述当前全局符号表的字典 678 | hash(object) # 如果对象object为哈希表类型,返回对象object的哈希值 679 | id(object) # 返回对象的唯一标识,一串数字 680 | isinstance(object, classinfo) # 判断object是否是class的实例 681 | isinstance(1, int) # 判断是不是int类型 682 | isinstance(1, (int, float)) # isinstance的第二个参数接受一个元组类型 683 | issubclass(class, classinfo) # 判断class是否为classinfo的子类 684 | locals() # 返回当前的变量列表 685 | map(function, iterable, ...) # 遍历每个元素,执行function操作 686 | list(map(abs, range(-3, 4))) # 返回[3, 2, 1, 0, 1, 2, 3] 687 | next(iterator[, default]) # 类似于iterator.next() 688 | property([fget[, fset[, fdel[, doc]]]]) # 属性访问的包装类,设置后可以通过c.x=value等来访问setter和getter 689 | reduce(function, iterable[, initializer]) # 合并操作,从第一个开始是前两个参数,然后是前两个的结果与第三个合并进行处理,以此类推 690 | def add(x,y):return x + y 691 | reduce(add, range(1, 11)) # 返回55 (注:1+2+3+4+5+6+7+8+9+10 = 55) 692 | reduce(add, range(1, 11), 20) # 返回75 693 | reload(module) # 重新加载模块 694 | repr(object) # 将一个对象变幻为可打印的格式 695 | slice(start, stop[, step]) # 产生分片对象 696 | type(object) # 返回该object的类型 697 | vars([object]) # 返回对象的变量名、变量值得字典 698 | a = Class(); # Class为一个空类 699 | a.name = 'qi', a.age = 9 700 | vars(a) # {'name':'qi', 'age':9} 701 | zip([iterable, ...]) # 返回对应数组 702 | list(zip([1, 2, 3], [4, 5, 6])) # [(1, 4), (2, 5), (3, 6)] 703 | a = [1, 2, 3], b = ["a", "b", "c"] 704 | z = zip(a, b) # 压缩:[(1, "a"), (2, "b"), (3, "c")] 705 | zip(*z) # 解压缩:[(1, 2, 3), ("a", "b", "c")] 706 | unicode(string, encoding, errors) # 将字符串string转化为unicode形式,string为encoded string。 707 | 708 | 709 | """模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle----模块Moudle""" 710 | 711 | #-- Python模块搜索路径: 712 | """ 713 | (1)程序的主目录 (2)PYTHONPATH目录 (3)标准链接库目录 (4)任何.pth文件的内容 714 | """ 715 | 716 | #-- 查看全部的模块搜索路径 717 | import sys 718 | sys.path 719 | 720 | #-- 模块的使用代码 721 | import module1, module2 # 导入module1 使用module1.printer() 722 | from module1 import printer # 导入module1中的printer变量 使用printer() 723 | from module1 imoprt * # 导入module1中的全部变量 使用不必添加module1前缀 724 | 725 | #-- 重载模块reload: 这是一个内置函数 而不是一条语句 726 | from imp import reload 727 | reload(module) 728 | 729 | #-- 模块的包导入:使用点号(.)而不是路径(dir1\dir2)进行导入 730 | import dir1.dir2.mod # d导入包(目录)dir1中的包dir2中的mod模块 此时dir1必须在Python可搜索路径中 731 | from dir1.dir2.mod import * # from语法的包导入 732 | 733 | #-- __init__.py包文件:每个导入的包中都应该包含这么一个文件 734 | """ 735 | 该文件可以为空 736 | 首次进行包导入时 该文件会自动执行 737 | 高级功能:在该文件中使用__all__列表来定义包(目录)以from*的形式导入时 需要导入什么 738 | """ 739 | 740 | #-- 包相对导入:使用点号(.) 只能使用from语句 741 | from . import spam # 导入当前目录下的spam模块(错误: 当前目录下的模块, 直接导入即可) 742 | from .spam import name # 导入当前目录下的spam模块的name属性(错误: 当前目录下的模块, 直接导入即可,不用加.) 743 | from .. import spam # 导入当前目录的父目录下的spam模块 744 | 745 | #-- 包相对导入与普通导入的区别 746 | from string import * # 这里导入的string模块为sys.path路径上的 而不是本目录下的string模块(如果存在也不是) 747 | from .string import * # 这里导入的string模块为本目录下的(不存在则导入失败) 而不是sys.path路径上的 748 | 749 | #-- 模块数据隐藏:最小化from*的破坏 750 | _X # 变量名前加下划线可以防止from*导入时该变量名被复制出去 751 | __all__ = ['x', 'x1', 'x2'] # 使用__all__列表指定from*时复制出去的变量名(变量名在列表中为字符串形式) 752 | 753 | #-- 可以使用__name__进行模块的单元测试:当模块为顶层执行文件时值为'__main__' 当模块被导入时为模块名 754 | if __name__ == '__main__': 755 | doSomething 756 | # 模块属性中还有其他属性,例如: 757 | __doc__ # 模块的说明文档 758 | __file__ # 模块文件的文件名,包括全路径 759 | __name__ # 主文件或者被导入文件 760 | __package__ # 模块所在的包 761 | 762 | #-- import语句from语句的as扩展 763 | import modulename as name 764 | from modulename import attrname as name 765 | 766 | #-- 得到模块属性的几种方法 假设为了得到name属性的值 767 | M.name 768 | M.__dict__['name'] 769 | sys.modules['M'].name 770 | getattr(M, 'name') 771 | 772 | 773 | """类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象----类与面向对象""" 774 | 775 | #-- 最普通的类 776 | class C1(C2, C3): 777 | spam = 42 # 数据属性 778 | def __init__(self, name): # 函数属性:构造函数 779 | self.name = name 780 | def __del__(self): # 函数属性:析构函数 781 | print("goodbey ", self.name) 782 | I1 = C1('bob') 783 | 784 | #-- Python的类没有基于参数的函数重载 785 | class FirstClass: 786 | def test(self, string): 787 | print(string) 788 | def test(self): # 此时类中只有一个test函数 即后者test(self) 它覆盖掉前者带参数的test函数 789 | print("hello world") 790 | 791 | #-- 子类扩展超类: 尽量调用超类的方法 792 | class Manager(Person): 793 | def giveRaise(self, percent, bonus = .10): 794 | self.pay = int(self.pay*(1 + percent + bonus)) # 不好的方式 复制粘贴超类代码 795 | Person.giveRaise(self, percent + bonus) # 好的方式 尽量调用超类方法 796 | 797 | #-- 类内省工具 798 | bob = Person('bob') 799 | bob.__class__ # 800 | bob.__class__.__name__ # 'Person' 801 | bob.__dict__ # {'pay':0, 'name':'bob', 'job':'Manager'} 802 | 803 | #-- 返回1中 数据属性spam是属于类 而不是对象 804 | I1 = C1('bob'); I2 = C2('tom') # 此时I1和I2的spam都为42 但是都是返回的C1的spam属性 805 | C1.spam = 24 # 此时I1和I2的spam都为24 806 | I1.spam = 3 # 此时I1新增自有属性spam 值为2 I2和C1的spam还都为24 807 | 808 | #-- 类方法调用的两种方式 809 | instance.method(arg...) 810 | class.method(instance, arg...) 811 | 812 | #-- 抽象超类的实现方法 813 | # (1)某个函数中调用未定义的函数 子类中定义该函数 814 | def delegate(self): 815 | self.action() # 本类中不定义action函数 所以使用delegate函数时就会出错 816 | # (2)定义action函数 但是返回异常 817 | def action(self): 818 | raise NotImplementedError("action must be defined") 819 | # (3)上述的两种方法还都可以定义实例对象 实际上可以利用@装饰器语法生成不能定义的抽象超类 820 | from abc import ABCMeta, abstractmethod 821 | class Super(metaclass = ABCMeta): 822 | @abstractmethod 823 | def action(self): pass 824 | x = Super() # 返回 TypeError: Can't instantiate abstract class Super with abstract methods action 825 | 826 | #-- # OOP和继承: "is - a"的关系 827 | class A(B): 828 | pass 829 | a = A() 830 | isinstance(a, B) # 返回True, A是B的子类 a也是B的一种 831 | # OOP和组合: "has- a"的关系 832 | pass 833 | # OOP和委托: "包装"对象 在Python中委托通常是以"__getattr__"钩子方法实现的, 这个方法会拦截对不存在属性的读取 834 | # 包装类(或者称为代理类)可以使用__getattr__把任意读取转发给被包装的对象 835 | class wrapper: 836 | def __init__(self, object): 837 | self.wrapped = object 838 | def __getattr(self, attrname): 839 | print('Trace: ', attrname) 840 | return getattr(self.wrapped, attrname) 841 | # 注:这里使用getattr(X, N)内置函数以变量名字符串N从包装对象X中取出属性 类似于X.__dict__[N] 842 | x = wrapper([1, 2, 3]) 843 | x.append(4) # 返回 "Trace: append" [1, 2, 3, 4] 844 | x = wrapper({'a':1, 'b':2}) 845 | list(x.keys()) # 返回 "Trace: keys" ['a', 'b'] 846 | 847 | #-- 类的伪私有属性:使用__attr 848 | class C1: 849 | def __init__(self, name): 850 | self.__name = name # 此时类的__name属性为伪私有属性 原理 它会自动变成self._C1__name = name 851 | def __str__(self): 852 | return 'self.name = %s' % self.__name 853 | I = C1('tom') 854 | print(I) # 返回 self.name = tom 855 | I.__name = 'jeey' # 这里无法访问 __name为伪私有属性 856 | I._C1__name = 'jeey' # 这里可以修改成功 self.name = jeey 857 | 858 | #-- 类方法是对象:无绑定类方法对象 / 绑定实例方法对象 859 | class Spam: 860 | def doit(self, message): 861 | print(message) 862 | def selfless(message) 863 | print(message) 864 | obj = Spam() 865 | x = obj.doit # 类的绑定方法对象 实例 + 函数 866 | x('hello world') 867 | x = Spam.doit # 类的无绑定方法对象 类名 + 函数 868 | x(obj, 'hello world') 869 | x = Spam.selfless # 类的无绑定方法是函数 在3.0之前无效 870 | x('hello world') 871 | 872 | #-- 获取对象信息: 属性和方法 873 | a = MyObject() 874 | dir(a) # 使用dir函数 875 | hasattr(a, 'x') # 测试是否有x属性或方法 即a.x是否已经存在 876 | setattr(a, 'y', 19) # 设置属性或方法 等同于a.y = 19 877 | getattr(a, 'z', 0) # 获取属性或方法 如果属性不存在 则返回默认值0 878 | #这里有个小技巧,setattr可以设置一个不能访问到的属性,即只能用getattr获取 879 | setattr(a, "can't touch", 100) # 这里的属性名带有空格,不能直接访问 880 | getattr(a, "can't touch", 0) # 但是可以用getattr获取 881 | 882 | #-- 为类动态绑定属性或方法: MethodType方法 883 | # 一般创建了一个class的实例后, 可以给该实例绑定任何属性和方法, 这就是动态语言的灵活性 884 | class Student(object): 885 | pass 886 | s = Student() 887 | s.name = 'Michael' # 动态给实例绑定一个属性 888 | def set_age(self, age): # 定义一个函数作为实例方法 889 | self.age = age 890 | from types import MethodType 891 | s.set_age = MethodType(set_age, s) # 给实例绑定一个方法 类的其他实例不受此影响 892 | s.set_age(25) # 调用实例方法 893 | Student.set_age = MethodType(set_age, Student) # 为类绑定一个方法 类的所有实例都拥有该方法 894 | 895 | 896 | """类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题""" 897 | 898 | #-- 多重继承: "混合类", 搜索方式"从下到上 从左到右 广度优先" 899 | class A(B, C): 900 | pass 901 | 902 | #-- 类的继承和子类的初始化 903 | # 1.子类定义了__init__方法时,若未显示调用基类__init__方法,python不会帮你调用。 904 | # 2.子类未定义__init__方法时,python会自动帮你调用首个基类的__init__方法,注意是首个。 905 | # 3.子类显示调用基类的初始化函数: 906 | class FooParent(object): 907 | def __init__(self, a): 908 | self.parent = 'I\'m the Parent.' 909 | print('Parent:a=' + str(a)) 910 | def bar(self, message): 911 | print(message + ' from Parent') 912 | class FooChild(FooParent): 913 | def __init__(self, a): 914 | FooParent.__init__(self, a) 915 | print('Child:a=' + str(a)) 916 | def bar(self, message): 917 | FooParent.bar(self, message) 918 | print(message + ' from Child') 919 | fooChild = FooChild(10) 920 | fooChild.bar('HelloWorld') 921 | 922 | #-- #实例方法 / 静态方法 / 类方法 923 | class Methods: 924 | def imeth(self, x): print(self, x) # 实例方法:传入的是实例和数据,操作的是实例的属性 925 | def smeth(x): print(x) # 静态方法:只传入数据 不传入实例,操作的是类的属性而不是实例的属性 926 | def cmeth(cls, x): print(cls, x) # 类方法:传入的是类对象和数据 927 | smeth = staticmethod(smeth) # 调用内置函数,也可以使用@staticmethod 928 | cmeth = classmethod(cmeth) # 调用内置函数,也可以使用@classmethod 929 | obj = Methods() 930 | obj.imeth(1) # 实例方法调用 <__main__.Methods object...> 1 931 | Methods.imeth(obj, 2) # <__main__.Methods object...> 2 932 | Methods.smeth(3) # 静态方法调用 3 933 | obj.smeth(4) # 这里可以使用实例进行调用 934 | Methods.cmeth(5) # 类方法调用 5 935 | obj.cmeth(6) # 6 936 | 937 | #-- 函数装饰器:是它后边的函数的运行时的声明 由@符号以及后边紧跟的"元函数"(metafunction)组成 938 | @staticmethod 939 | def smeth(x): print(x) 940 | # 等同于: 941 | def smeth(x): print(x) 942 | smeth = staticmethod(smeth) 943 | # 同理 944 | @classmethod 945 | def cmeth(cls, x): print(x) 946 | # 等同于 947 | def cmeth(cls, x): print(x) 948 | cmeth = classmethod(cmeth) 949 | 950 | #-- 类修饰器:是它后边的类的运行时的声明 由@符号以及后边紧跟的"元函数"(metafunction)组成 951 | def decorator(aClass):..... 952 | @decorator 953 | class C:.... 954 | # 等同于: 955 | class C:.... 956 | C = decorator(C) 957 | 958 | #-- 限制class属性: __slots__属性 959 | class Student: 960 | __slots__ = ('name', 'age') # 限制Student及其实例只能拥有name和age属性 961 | # __slots__属性只对当前类起作用, 对其子类不起作用 962 | # __slots__属性能够节省内存 963 | # __slots__属性可以为列表list,或者元组tuple 964 | 965 | #-- 类属性高级话题: @property 966 | # 假设定义了一个类:C,该类必须继承自object类,有一私有变量_x 967 | class C(object): 968 | def __init__(self): 969 | self.__x = None 970 | # 第一种使用属性的方法 971 | def getx(self): 972 | return self.__x 973 | def setx(self, value): 974 | self.__x = value 975 | def delx(self): 976 | del self.__x 977 | x = property(getx, setx, delx, '') 978 | # property函数原型为property(fget=None,fset=None,fdel=None,doc=None) 979 | # 使用 980 | c = C() 981 | c.x = 100 # 自动调用setx方法 982 | y = c.x # 自动调用getx方法 983 | del c.x # 自动调用delx方法 984 | # 第二种方法使用属性的方法 985 | @property 986 | def x(self): 987 | return self.__x 988 | @x.setter 989 | def x(self, value): 990 | self.__x = value 991 | @x.deleter 992 | def x(self): 993 | del self.__x 994 | # 使用 995 | c = C() 996 | c.x = 100 # 自动调用setter方法 997 | y = c.x # 自动调用x方法 998 | del c.x # 自动调用deleter方法 999 | 1000 | #-- 定制类: 重写类的方法 1001 | # (1)__str__方法、__repr__方法: 定制类的输出字符串 1002 | # (2)__iter__方法、next方法: 定制类的可迭代性 1003 | class Fib(object): 1004 | def __init__(self): 1005 | self.a, self.b = 0, 1 # 初始化两个计数器a,b 1006 | def __iter__(self): 1007 | return self # 实例本身就是迭代对象,故返回自己 1008 | def next(self): 1009 | self.a, self.b = self.b, self.a + self.b 1010 | if self.a > 100000: # 退出循环的条件 1011 | raise StopIteration() 1012 | return self.a # 返回下一个值 1013 | for n in Fib(): 1014 | print(n) # 使用 1015 | # (3)__getitem__方法、__setitem__方法: 定制类的下标操作[] 或者切片操作slice 1016 | class Indexer(object): 1017 | def __init__(self): 1018 | self.data = {} 1019 | def __getitem__(self, n): # 定义getitem方法 1020 | print('getitem:', n) 1021 | return self.data[n] 1022 | def __setitem__(self, key, value): # 定义setitem方法 1023 | print('setitem:key = {0}, value = {1}'.format(key, value)) 1024 | self.data[key] = value 1025 | test = Indexer() 1026 | test[0] = 1; test[3] = '3' # 调用setitem方法 1027 | print(test[0]) # 调用getitem方法 1028 | # (4)__getattr__方法: 定制类的属性操作 1029 | class Student(object): 1030 | def __getattr__(self, attr): # 定义当获取类的属性时的返回值 1031 | if attr=='age': 1032 | return 25 # 当获取age属性时返回25 1033 | raise AttributeError('object has no attribute: %s' % attr) 1034 | # 注意: 只有当属性不存在时 才会调用该方法 且该方法默认返回None 需要在函数最后引发异常 1035 | s = Student() 1036 | s.age # s中age属性不存在 故调用__getattr__方法 返回25 1037 | # (5)__call__方法: 定制类的'可调用'性 1038 | class Student(object): 1039 | def __call__(self): # 也可以带参数 1040 | print('Calling......') 1041 | s = Student() 1042 | s() # s变成了可调用的 也可以带参数 1043 | callable(s) # 测试s的可调用性 返回True 1044 | # (6)__len__方法:求类的长度 1045 | def __len__(self): 1046 | return len(self.data) 1047 | 1048 | #-- 动态创建类type() 1049 | # 一般创建类 需要在代码中提前定义 1050 | class Hello(object): 1051 | def hello(self, name='world'): 1052 | print('Hello, %s.' % name) 1053 | h = Hello() 1054 | h.hello() # Hello, world 1055 | type(Hello) # Hello是一个type类型 返回 1056 | type(h) # h是一个Hello类型 返回 1057 | # 动态类型语言中 类可以动态创建 type函数可用于创建新类型 1058 | def fn(self, name='world'): # 先定义函数 1059 | print('Hello, %s.' % name) 1060 | Hello = type('Hello', (object,), dict(hello=fn)) 1061 | # 创建Hello类 type原型: type(name, bases, dict) 1062 | h = Hello() # 此时的h和上边的h一致 1063 | 1064 | 1065 | """异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关""" 1066 | 1067 | #-- #捕获异常: 1068 | try: 1069 | except: # 捕获所有的异常 等同于except Exception: 1070 | except name: # 捕获指定的异常 1071 | except name, value: # 捕获指定的异常和额外的数据(实例) 1072 | except (name1, name2): 1073 | except (name1, name2), value: 1074 | except name4 as X: 1075 | else: # 如果没有发生异常 1076 | finally: # 总会执行的部分 1077 | # 引发异常: raise子句(raise IndexError) 1078 | raise # raise instance of a class, raise IndexError() 1079 | raise # make and raise instance of a class, raise IndexError 1080 | raise # reraise the most recent exception 1081 | 1082 | #-- Python3.x中的异常链: raise exception from otherException 1083 | except Exception as X: 1084 | raise IndexError('Bad') from X 1085 | 1086 | #-- assert子句: assert , 1087 | assert x < 0, 'x must be negative' 1088 | 1089 | #-- with/as环境管理器:作为常见的try/finally用法模式的替代方案 1090 | with expression [as variable], expression [as variable]: 1091 | # 例子: 1092 | with open('test.txt') as myfile: 1093 | for line in myfile: print(line) 1094 | # 等同于: 1095 | myfile = open('test.txt') 1096 | try: 1097 | for line in myfile: print(line) 1098 | finally: 1099 | myfile.close() 1100 | 1101 | #-- 用户自定义异常: class Bad(Exception):..... 1102 | """ 1103 | Exception超类 / except基类即可捕获到其所有子类 1104 | Exception超类有默认的打印消息和状态 当然也可以定制打印显示: 1105 | """ 1106 | class MyBad(Exception): 1107 | def __str__(self): 1108 | return '定制的打印消息' 1109 | try: 1110 | MyBad() 1111 | except MyBad as x: 1112 | print(x) 1113 | 1114 | #-- 用户定制异常数据 1115 | class FormatError(Exception): 1116 | def __init__(self, line ,file): 1117 | self.line = line 1118 | self.file = file 1119 | try: 1120 | raise FormatError(42, 'test.py') 1121 | except FormatError as X: 1122 | print('Error at ', X.file, X.line) 1123 | # 用户定制异常行为(方法):以记录日志为例 1124 | class FormatError(Exception): 1125 | logfile = 'formaterror.txt' 1126 | def __init__(self, line ,file): 1127 | self.line = line 1128 | self.file = file 1129 | def logger(self): 1130 | open(self.logfile, 'a').write('Error at ', self.file, self.line) 1131 | try: 1132 | raise FormatError(42, 'test.py') 1133 | except FormatError as X: 1134 | X.logger() 1135 | 1136 | #-- 关于sys.exc_info:允许一个异常处理器获取对最近引发的异常的访问 1137 | try: 1138 | ...... 1139 | except: 1140 | # 此时sys.exc_info()返回一个元组(type, value, traceback) 1141 | # type:正在处理的异常的异常类型 1142 | # value:引发的异常的实例 1143 | # traceback:堆栈信息 1144 | 1145 | #-- 异常层次 1146 | BaseException 1147 | +-- SystemExit 1148 | +-- KeyboardInterrupt 1149 | +-- GeneratorExit 1150 | +-- Exception 1151 | +-- StopIteration 1152 | +-- ArithmeticError 1153 | +-- AssertionError 1154 | +-- AttributeError 1155 | +-- BufferError 1156 | +-- EOFError 1157 | +-- ImportError 1158 | +-- LookupError 1159 | +-- MemoryError 1160 | +-- NameError 1161 | +-- OSError 1162 | +-- ReferenceError 1163 | +-- RuntimeError 1164 | +-- SyntaxError 1165 | +-- SystemError 1166 | +-- TypeError 1167 | +-- ValueError 1168 | +-- Warning 1169 | 1170 | 1171 | """Unicode和字节字符串---Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串""" 1172 | 1173 | #-- Python的字符串类型 1174 | """Python2.x""" 1175 | # 1.str表示8位文本和二进制数据 1176 | # 2.unicode表示宽字符Unicode文本 1177 | """Python3.x""" 1178 | # 1.str表示Unicode文本(8位或者更宽) 1179 | # 2.bytes表示不可变的二进制数据 1180 | # 3.bytearray是一种可变的bytes类型 1181 | 1182 | #-- 字符编码方法 1183 | """ASCII""" # 一个字节,只包含英文字符,0到127,共128个字符,利用函数可以进行字符和数字的相互转换 1184 | ord('a') # 字符a的ASCII码为97,所以这里返回97 1185 | chr(97) # 和上边的过程相反,返回字符'a' 1186 | """Latin-1""" # 一个字节,包含特殊字符,0到255,共256个字符,相当于对ASCII码的扩展 1187 | chr(196) # 返回一个特殊字符:Ä 1188 | """Unicode""" # 宽字符,一个字符包含多个字节,一般用于亚洲的字符集,比如中文有好几万字 1189 | """UTF-8""" # 可变字节数,小于128的字符表示为单个字节,128到0X7FF之间的代码转换为两个字节,0X7FF以上的代码转换为3或4个字节 1190 | # 注意:可以看出来,ASCII码是Latin-1和UTF-8的一个子集 1191 | # 注意:utf-8是unicode的一种实现方式,unicode、gbk、gb2312是编码字符集 1192 | 1193 | #-- 查看Python中的字符串编码名称,查看系统的编码 1194 | import encodings 1195 | help(encoding) 1196 | import sys 1197 | sys.platform # 'win64' 1198 | sys.getdefaultencoding() # 'utf-8' 1199 | sys.getdefaultencoding() # 返回当前系统平台的编码类型 1200 | sys.getsizeof(object) # 返回object占有的bytes的大小 1201 | 1202 | #-- 源文件字符集编码声明: 添加注释来指定想要的编码形式 从而改变默认值 注释必须出现在脚本的第一行或者第二行 1203 | """说明:其实这里只会检查#和coding:utf-8,其余的字符都是为了美观加上的""" 1204 | # _*_ coding: utf-8 _*_ 1205 | # coding = utf-8 1206 | 1207 | #-- #编码: 字符串 --> 原始字节 #解码: 原始字节 --> 字符串 1208 | 1209 | #-- Python3.x中的字符串应用 1210 | s = '...' # 构建一个str对象,不可变对象 1211 | b = b'...' # 构建一个bytes对象,不可变对象 1212 | s[0], b[0] # 返回('.', 113) 1213 | s[1:], b[1:] # 返回('..', b'..') 1214 | B = B""" 1215 | xxxx 1216 | yyyy 1217 | """ 1218 | # B = b'\nxxxx\nyyyy\n' 1219 | # 编码,将str字符串转化为其raw bytes形式: 1220 | str.encode(encoding = 'utf-8', errors = 'strict') 1221 | bytes(str, encoding) 1222 | # 编码例子: 1223 | S = 'egg' 1224 | S.encode() # b'egg' 1225 | bytes(S, encoding = 'ascii') # b'egg' 1226 | # 解码,将raw bytes字符串转化为str形式: 1227 | bytes.decode(encoding = 'utf-8', errors = 'strict') 1228 | str(bytes_or_buffer[, encoding[, errors]]) 1229 | # 解码例子: 1230 | B = b'spam' 1231 | B.decode() # 'spam' 1232 | str(B) # "b'spam'",不带编码的str调用,结果为打印该bytes对象 1233 | str(B, encoding = 'ascii')# 'spam',带编码的str调用,结果为转化该bytes对象 1234 | 1235 | #-- Python2.x的编码问题 1236 | u = u'汉' 1237 | print repr(u) # u'\xba\xba' 1238 | s = u.encode('UTF-8') 1239 | print repr(s) # '\xc2\xba\xc2\xba' 1240 | u2 = s.decode('UTF-8') 1241 | print repr(u2) # u'\xba\xba' 1242 | # 对unicode进行解码是错误的 1243 | s2 = u.decode('UTF-8') # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128) 1244 | # 同样,对str进行编码也是错误的 1245 | u2 = s.encode('UTF-8') # UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128) 1246 | 1247 | #-- bytes对象 1248 | B = b'abc' 1249 | B = bytes('abc', 'ascii') 1250 | B = bytes([97, 98, 99]) 1251 | B = 'abc'.encode() 1252 | # bytes对象的方法调用基本和str类型一致 但:B[0]返回的是ASCII码值97, 而不是b'a' 1253 | 1254 | #-- #文本文件: 根据Unicode编码来解释文件内容,要么是平台的默认编码,要么是指定的编码类型 1255 | # 二进制文件:表示字节值的整数的一个序列 open('bin.txt', 'rb') 1256 | 1257 | #-- Unicode文件 1258 | s = 'A\xc4B\xe8C' # s = 'A?BèC' len(s) = 5 1259 | #手动编码 1260 | l = s.encode('latin-1') # l = b'A\xc4B\xe8C' len(l) = 5 1261 | u = s.encode('utf-8') # u = b'A\xc3\x84B\xc3\xa8C' len(u) = 7 1262 | #文件输出编码 1263 | open('latindata', 'w', encoding = 'latin-1').write(s) 1264 | l = open('latindata', 'rb').read() # l = b'A\xc4B\xe8C' len(l) = 5 1265 | open('uft8data', 'w', encoding = 'utf-8').write(s) 1266 | u = open('uft8data', 'rb').read() # u = b'A\xc3\x84B\xc3\xa8C' len(u) = 7 1267 | #文件输入编码 1268 | s = open('latindata', 'r', encoding = 'latin-1').read() # s = 'A?BèC' len(s) = 5 1269 | s = open('latindata', 'rb').read().decode('latin-1') # s = 'A?BèC' len(s) = 5 1270 | s = open('utf8data', 'r', encoding = 'utf-8').read() # s = 'A?BèC' len(s) = 5 1271 | s = open('utf8data', 'rb').read().decode('utf-8') # s = 'A?BèC' len(s) = 5 1272 | 1273 | 1274 | """其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他""" 1275 | 1276 | #-- 60个字符解决FizzBuzz: 1277 | """写一个程序, 打印数字1到100, 3的倍数打印“Fizz”来替换这个数, 5的倍数打印“Buzz”, 既是3又是5的倍数的打印“FizzBuzz”""" 1278 | for x in range(101): 1279 | print("fizz"[x%3*4::]+"buzz"[x%5*4::] or x) # 解释:最主要用到列表(字符串)的子表 1280 | 1281 | #-- Python实现任意深度的赋值 例如a[0] = 'value1'; a[1][2] = 'value2'; a[3][4][5] = 'value3' 1282 | class MyDict(dict): 1283 | def __setitem__(self, key, value): # 该函数不做任何改动 这里只是为了输出 1284 | print('setitem:', key, value, self) 1285 | super().__setitem__(key, value) 1286 | def __getitem__(self, item): # 主要技巧在该函数 1287 | print('getitem:', item, self) # 输出信息 1288 | # 基本思路: a[1][2]赋值时 需要先取出a[1] 然后给a[1]的[2]赋值 1289 | if item not in self: # 如果a[1]不存在 则需要新建一个dict 并使得a[1] = dict 1290 | temp = MyDict() # 新建的dict: temp 1291 | super().__setitem__(item, temp) # 赋值a[1] = temp 1292 | return temp # 返回temp 使得temp[2] = value有效 1293 | return super().__getitem__(item) # 如果a[1]存在 则直接返回a[1] 1294 | # 例子: 1295 | test = MyDict() 1296 | test[0] = 'test' 1297 | print(test[0]) 1298 | test[1][2] = 'test1' 1299 | print(test[1][2]) 1300 | test[1][3] = 'test2' 1301 | print(test[1][3]) 1302 | 1303 | #-- Python中的多维数组 1304 | lists = [0] * 3 # 扩展list,结果为[0, 0, 0] 1305 | lists = [[]] * 3 # 多维数组,结果为[[], [], []],但有问题,往下看 1306 | lists[0].append(3) # 期望看到的结果[[3], [], []],实际结果[[3], [3], [3]],原因:list*n操作,是浅拷贝,如何避免?往下看 1307 | lists = [[] for i in range(3)] # 多维数组,结果为[[], [], []] 1308 | lists[0].append(3) # 结果为[[3], [], []] 1309 | lists[1].append(6) # 结果为[[3], [6], []] 1310 | lists[2].append(9) # 结果为[[3], [6], [9]] 1311 | lists = [[[] for j in range(4)] for i in range(3)] 1312 | lists # 3行4列,且每一个元素为[] 1313 | -------------------------------------------------------------------------------- /Python面试题.md: -------------------------------------------------------------------------------- 1 | 1. 简单谈一下你对Python这门语言的理解 2 | 3 | ``` 4 | 设计哲学:强调代码的可读性和简洁的语法 5 | 动态解释型语言,灵活,包容 6 | 强类型语言, '鸭子模型' 7 | 应用领域:Web,爬虫,大数据,云计算,AI 8 | 跨平台-真正做到一处编写,到处执行 9 | 与Java、C、Go等语言对比优势和劣势 10 | ``` 11 | 12 | 13 | 14 | #### 2. Python2中文编码问题 15 | 16 | ``` 17 | Python2使用 ASCII 作为默认编码方式(历史原因) 18 | Python3使用Unicode作为默认编码,str和bytes 19 | ``` 20 | 21 | 22 | 23 | #### 3. 谈一下List、Tuple、Set的区别和联系 24 | 25 | ``` 26 | 都是可迭代集合对象,List、Tuple可以互相转换 27 | List、Set可变,Tuple不可变 28 | Set内对象不重复,可以用于语言级排重 29 | Tuple性能略好 30 | ``` 31 | 32 | 33 | 34 | #### 4. 谈一下进程和线程的关系,什么时候用进程,什么时候用线程? 35 | 36 | ``` 37 | IO密集型 – 线程 38 | CPU密集型 – 进程 39 | ``` 40 | 41 | 42 | 43 | #### 5. Python多线程编程 44 | 45 | ```python 46 | threading模块 47 | 最基础的是start、join两个方法 48 | 49 | 50 | import threading, time 51 | 52 | def doWaiting(): 53 | print("start waiting", time.strftime("%H:%M:%S")) 54 | time.sleep(3) 55 | print("stop waiting", time.strftime("%H:%M:%S")) 56 | thread1 = threading.Thread(target = doWaiting) 57 | thread1.start() 58 | time.sleep(1) # 确保thread1已经启动 59 | print("start join") 60 | thread1.join() # 将一直阻塞,直到thread1运行结束 61 | print("end join") 62 | ``` 63 | 64 | 65 | 66 | 67 | 68 | #### 8. 迭代器(Iterator),生成器(Generator),可迭代对象(Iterables) 69 | 70 | ``` 71 | 完全理解Python迭代对象、迭代器、生成器 - FooFish-Python之禅 72 | https://foofish.net/iterators-vs-generators.html 73 | ``` 74 | 75 | 76 | 77 | #### 9. yield和return区别 78 | 79 | ``` 80 | yield是记录上一次运行的位置,下次执行函数通过上一次的状态得到下一次的值 81 | 而return直接结束程序,下次执行函数重新执行 82 | ``` 83 | 84 | 85 | 86 | #### 10. range和xrange区别 87 | 88 | ``` 89 | range直接返回一个列表 90 | xrange返回一个xrange对象,类似于生成器,每次返回一个值,性能较好 91 | 如果数据量较小,两者并无明显差别 92 | ``` 93 | 94 | 95 | 96 | #### 11. 值传递、引用传递 97 | 98 | ```python 99 | 常见于笔试题, 可变对象与不可变对象的效果不同 100 | 101 | def test(a): 102 | a += 1 103 | 104 | b = 2 105 | test(b) 106 | # 此时b仍然为2, b为不可变对象,不会改变原始值 107 | 108 | def test2(a): 109 | a.append(1) 110 | 111 | c = [0] 112 | test2(c) 113 | # 此时c为 [0, 1] 114 | ``` 115 | 116 | 117 | 118 | #### 12. 小整数内存复用 119 | 120 | ``` 121 | (-5:256] 122 | ``` 123 | 124 | 125 | 126 | #### 13. Python中如何实现匿名函数? 什么是lambda表达式? 127 | 128 | ``` 129 | 常见搭配于map、filter 130 | 简单的使用某个功能但不想单独创建一个函数的时候可以使用lambda匿名函数 131 | ``` 132 | 133 | 134 | 135 | #### 14. Python中有三目运算符吗? 136 | 137 | ``` 138 | C 语言中 表达式 ? 表达式真 : 表达式假 139 | Python中 表达式真 if 表达式 else 表达式假 140 | ``` 141 | 142 | 143 | 144 | #### 15. 如何将一个列表逆序? 145 | 146 | ```python 147 | a = [1, 2, 3] 148 | a[::-1] 149 | # >>> [3, 2, 1] 150 | # a >>> [1, 2, 3] 151 | a.reverse() 152 | # >>> [3, 2, 1] 153 | # a >>> [3, 2, 1] 154 | ``` 155 | 156 | 157 | 158 | #### 16. 如何删除列表中的重复元素? 159 | 160 | ``` 161 | 一定不要使用遍历list过程中remove 162 | 定义新的list逐个append 163 | 使用set排重 164 | ``` 165 | 166 | 167 | 168 | #### 17. Python正则表达式相关 169 | 170 | ``` 171 | RE库 172 | match与search的区别: match从头开始搜索, search从任意位置搜索 173 | group分组,findall 174 | 175 | 正则表达式30分钟入门教程 176 | https://deerchao.net/tutorials/regex/regex.htm 177 | ``` 178 | 179 | 180 | 181 | #### 18. 平时写单元测试吗? Python单元测试如何写? Django呢? 182 | 183 | ``` 184 | Python使用自带unittest库,可以用nosetest跑 185 | Django中使用django.test模块,是对unittest的封装,常用于对数据库的测试 186 | 断言assert模式 187 | ``` 188 | 189 | 190 | 191 | #### 19. Python常用的单元测试库? 192 | 193 | ```python 194 | mock \ httpretty \ fakeredis \ mixer \ coverage 195 | # mock 生成虚假返回数据,例如调用send_sms方法,使用mock,则系统认为假设返回为真 196 | # httpretty 生成假的返回值,直接截获系统的HTTP请求,并返回预设值 197 | # fakeredis 构造假redis 198 | # mixer 构造随机假数据 199 | # coverage 代码覆盖率 200 | ``` 201 | 202 | 203 | 204 | #### 20. 谈谈你对Python装饰器的理解并实现简单装饰 205 | 206 | ```python 207 | 装饰器本质就是一个函数,是一个设计模式 208 | 从函数定义入口,传入一个函数,并且返回一个函数 209 | 是一种python "语法糖" 210 | 211 | # 实现一个能够方便打印函数的运行时间的装饰器,装饰器要有参数控制输出时间单位是s还是ms 212 | def timer(time_type='s'): 213 | def outer(func): 214 | from functools import wraps 215 | @wraps(func) 216 | def decor(*args): 217 | import time 218 | start_time = time.time() 219 | func(*args) 220 | end_time = time.time() 221 | d_time = end_time - start_time 222 | if time_type == 's': 223 | print("run the func use : %s sec" % round(d_time, 2)) 224 | if time_type == 'ms': 225 | print("run the func use : %s ms" % int(d_time*1000)) 226 | return decor 227 | return outer 228 | ``` 229 | 230 | 231 | 232 | #### 21. Staticmethod、 Classmethod、 Instance method三者的区别和联系? 233 | 234 | ```python 235 | Staticmethod # 不传值, 就是与类一起使用的, 明确代码使用位置 236 | Classmethod # 传cls 237 | Instance method # 传self 238 | ``` 239 | 240 | 241 | 242 | #### 22. 什么是协程? 跟进程和线程有什么区别? 243 | 244 | ``` 245 | 进程和线程都面临着内核态和用户态的切换,耗费大量时间 246 | 系统控制的内容在内核态,用户代码的执行在用户态 247 | 协程都在用户态执行,由用户控制,不需要操作系统参与,避免了用户态和内核态的切换 248 | Python协程通过yield关键字实现 249 | ``` 250 | 251 | 252 | 253 | #### 23. 发散性问题,考察软技能 254 | 255 | ``` 256 | 1. 知道PEP8吗? 简单说几条PEP8的规范 257 | 2. 用过哪些Python库? 258 | 自带库:datetime,re,threading, multiprocessing … 259 | 第三方库:requests,MySQL-python,redis,Django,celery … 260 | 单元测试的库 261 | ``` 262 | 263 | 264 | 265 | #### 24. 数据库事务的特性,什么场景下要使用事务? 266 | 267 | ``` 268 | 原子性(Atomicity) - 事务中的所有操作要么全部执行,要么都不执行 269 | 一致性(Consistency) - 事务执行之前和执行之后都必须处于一致性状态 270 | 隔离性(Isolation) - 多个并发事务之间要相互隔离(后面专门会讲) 271 | 持久性(Durability) - 事务一旦被提交了,那么对数据库中的数据的改变就是永久性的 272 | 273 | 使用场景:1)原子性操作; 274 | 2)并发访问控制(和锁配合) 275 | ``` 276 | 277 | 278 | 279 | #### 25. MySQL事务和锁的关系 280 | 281 | ``` 282 | 二者不是一个维度的概念:事务是原子操作和访问隔离,锁是数据访问控制 283 | 二者经常一起出现:锁(select_for_update)要在事务中才能生效 284 | 事务中不一定要有锁 285 | ``` 286 | 287 | 288 | 289 | #### 26. MySQL InnoDB引擎的事务隔离级别 290 | 291 | ``` 292 | Innodb四个事务隔离级别,MySQL默认使用RR级别 293 | 脏读 – 读到了数据库中未提交的数据 294 | 不可重复读 – 一个事务内多次查询结果不一致 295 | 幻读 – 读到了之前不存在的新纪录(insert) 296 | ``` 297 | 298 | ![](https://github.com/JiaxingZhao/Python--Antic/blob/master/img/1534302969970.png) 299 | 300 | 301 | 302 | #### 27. Innodb索引、联合索引,卡丁值(Cardinality) 303 | 304 | ``` 305 | 索引的意义在于提高查询效率,会大幅影响写入速度 306 | Innodb索引存储结构:B+树。由计算机的内存-机械硬盘两层存储结构决定 307 | 可以使用索引的情况: 308 | where 条件中 309 | order by 310 | group by 311 | 卡丁值太低不要加索引,区分度太低。比如性别、状态 312 | 联合索引符合最左前缀原则 313 | ``` 314 | 315 | ![](https://github.com/JiaxingZhao/Python--Antic/blob/master/img/1534303067466.png) 316 | 317 | 318 | 319 | #### 28. Redis支持事务吗? 320 | 321 | ``` 322 | 支持,但是和数据库的事务概念不完全一致 323 | 坑!非原子性,不支持回滚:Redis在事务失败时不进行回滚,而是继续执行余下的命令 324 | 不回滚的原因:1.只有语法错误会失败,开发阶段就应该发现 325 | 2.不回滚保持Redis简单 326 | MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务的基础 327 | 也可以用Pipeline实现批量提交命令(非事务) 328 | ``` 329 | 330 | 331 | 332 | #### 29. Redis高可用方案? 333 | 334 | ``` 335 | master-slave 336 | sentinel自动flavor 337 | 集群:Redis Cluster(官方)、Codis (豌豆荚) 338 | ``` 339 | 340 | 341 | 342 | #### 30. 数组、链表、Hash表/字典区别,并举例说明各自的应用场景 343 | 344 | ``` 345 | 数组 – 连续空间; 随机访问O(1); 插入、删除元素O(n)。储存一个月每天的温度 346 | 链表 - 非连续空间;随机访问O(n);插入、删除元素O(1)。储存行程计划 347 | Hash表/字典 - 非连续空间;随机访问O(n);插入、删除O(1);不重复。储存班级每人成绩 348 | ``` 349 | 350 | 351 | 352 | #### 31. 栈、队列的区别,举例各自的应用场景 353 | 354 | ``` 355 | 栈 – 先进后出;支持push、pop、top操作。函数的调用关系 356 | 队列 – 先进先出。按顺序执行的消息队列 357 | 双端队列 – 两端都可以进出。既可当栈使用,也可当队列使用 358 | ``` 359 | 360 | 361 | 362 | #### 32. 常见排序算法实现,稳定性,及其时间复杂度、空间复杂度 363 | 364 | ![](https://github.com/JiaxingZhao/Python--Antic/blob/master/img/1534314173618.png) 365 | 366 | 367 | 368 | #### 33. 谈谈你对几种不同Python web框架的认识和理解 369 | 370 | ``` 371 | Django、Tornado、Flask、Bottle 372 | ``` 373 | 374 | 375 | 376 | #### 34. Django中间件相关 377 | 378 | ``` 379 | 什么是Django中间件? 380 | 什么场景下使用Django中间件? 381 | 实现一个中间件主要实现的两个方法:process_request和process_response 382 | Django中间件请求阶段和响应阶段的执行顺序? 383 | ``` 384 | 385 | ![](https://github.com/JiaxingZhao/Python--Antic/blob/master/img/1534314262045.png) 386 | 387 | 388 | 389 | #### 35. Django的session模块 390 | 391 | ``` 392 | Django session通过客户端cookie存放sessionid + 服务端序列化存储实现 393 | 使用: django.contrib.sessions INSTALLED_APPS + SessionMiddleware MIDDLEWARE 394 | Django session支持多种存储引擎:db,cache,cached_db,file,cookie 395 | Django session 有domain限制。.example.com sub.example.com 396 | 可以在request.session直接读取 397 | ``` 398 | 399 | 400 | 401 | #### 36. Django的Auth模块 402 | 403 | ``` 404 | User、Permissions、Groups、password、login 405 | 使用:django.contrib.auth INSTALLED_APPS + AuthenticationMiddleware MIDDLEWARE 406 | 依赖session模块 407 | 最佳实践:基于AbstractUser实现自己的User类 408 | 如何安全的存储密码? Hash + Salt 409 | ``` 410 | 411 | 412 | 413 | #### 37. 谈一下Django中的安全机制 414 | 415 | ``` 416 | XSS (跨域脚本攻击) - 模板转义 ( 直接写script脚本 ) 417 | CSRF(跨站提交请求) - CsrfViewMiddleware 418 | 常量密码验证时间 419 | ``` 420 | 421 | 422 | 423 | #### 38. Django的缓存机制 424 | 425 | ``` 426 | 为什么要使用cache? 427 | cache抽象成基本操作:get、set、delete、expire 428 | backend:支持memcached、db、file、local-memory 429 | 使用:1)通过settings.py中的CACHE配置; 430 | 2)from django.core.cache import cache 431 | ``` 432 | 433 | 434 | 435 | #### 39. Django如何实现RESTful接口 436 | 437 | ``` 438 | class-based view 439 | 理解RESTful架构 - 阮一峰的网络日志 440 | http://www.ruanyifeng.com/blog/2011/09/restful.html 441 | RESTful API 设计指南 - 阮一峰的网络日志 442 | http://www.ruanyifeng.com/blog/2014/05/restful_api.html 443 | ``` 444 | 445 | ![](https://github.com/JiaxingZhao/Python--Antic/blob/master/img/1534314401023.png) 446 | 447 | ![](https://github.com/JiaxingZhao/Python--Antic/blob/master/img/1534314404356.png) 448 | 449 | 450 | 451 | #### 40. 简述HTTP协议的特点,列举几个常见的HTTP HEAD 452 | 453 | ``` 454 | HTTP(超文本传输协议)是一个基于请求与响应模式的、无状态的、应用层协议,基于TCP连接 455 | Context-type 456 | Cookie 457 | Accept-Language 458 | Referer 459 | Cache-Control 460 | If-Modified-Since、Last-Modified 461 | 462 | 五层: 应用层、网络层、传输层、数据链路层、物理层 463 | ``` 464 | 465 | 466 | 467 | #### 41.HTTP请求报文的三部分,HTTP响应报文的三部分 468 | 469 | ``` 470 | 请求报文三部分:请求行、消息报头、请求正文 471 | 响应报文三部分:状态行、消息报头、响应正文 472 | ``` 473 | 474 | ![](https://github.com/JiaxingZhao/Python--Antic/blob/master/img/412b4451-2738-3ebc-b1f6-a0cc13b9697b.jpg) 475 | 476 | ![](https://github.com/JiaxingZhao/Python--Antic/blob/master/img/bddb00b6-a3e1-3112-a4f4-4b3cb8687c70.jpg) 477 | 478 | 479 | 480 | #### 42. HTTP错误码的划分,说出几个常见的错误码 481 | 482 | | 状态码 | 定义 | 483 | | -------------- | ----------------------------------------------- | 484 | | 1xx 报告 | 接收到请求,继续进程 | 485 | | 2xx 成功 | 步骤成功接收,被理解,并被接受 (200) | 486 | | 3xx 重定向 | 为了完成请求,必须采取进一步措施 (301、302、304) | 487 | | 4xx 客户端出错 | 请求包括错的顺序或不能完成 (400、403、404、405) | 488 | | 5xx 服务器出错 | 服务器无法完成显然有效的请求(500、502、504) | 489 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python-Antic 2 | 一点python的小技巧 3 | -------------------------------------------------------------------------------- /img/1534302969970.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaxingZhao/Python--Antic/d67b8783a4845fe97d2c065cccc7324edd592573/img/1534302969970.png -------------------------------------------------------------------------------- /img/1534303067466.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaxingZhao/Python--Antic/d67b8783a4845fe97d2c065cccc7324edd592573/img/1534303067466.png -------------------------------------------------------------------------------- /img/1534314173618.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaxingZhao/Python--Antic/d67b8783a4845fe97d2c065cccc7324edd592573/img/1534314173618.png -------------------------------------------------------------------------------- /img/1534314262045.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaxingZhao/Python--Antic/d67b8783a4845fe97d2c065cccc7324edd592573/img/1534314262045.png -------------------------------------------------------------------------------- /img/1534314401023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaxingZhao/Python--Antic/d67b8783a4845fe97d2c065cccc7324edd592573/img/1534314401023.png -------------------------------------------------------------------------------- /img/1534314404356.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaxingZhao/Python--Antic/d67b8783a4845fe97d2c065cccc7324edd592573/img/1534314404356.png -------------------------------------------------------------------------------- /img/412b4451-2738-3ebc-b1f6-a0cc13b9697b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaxingZhao/Python--Antic/d67b8783a4845fe97d2c065cccc7324edd592573/img/412b4451-2738-3ebc-b1f6-a0cc13b9697b.jpg -------------------------------------------------------------------------------- /img/bddb00b6-a3e1-3112-a4f4-4b3cb8687c70.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiaxingZhao/Python--Antic/d67b8783a4845fe97d2c065cccc7324edd592573/img/bddb00b6-a3e1-3112-a4f4-4b3cb8687c70.jpg -------------------------------------------------------------------------------- /使用Python 发送SMTP协议电子邮件.md: -------------------------------------------------------------------------------- 1 | #### 使用Python 发送SMTP协议电子邮件 2 | 3 | ```python 4 | import smtplib 5 | from email.mime.text import MIMEText 6 | 7 | msg_from='username@163.com' 8 | passwd = 'password' 9 | msg_to = 'username@163.com' 10 | 11 | subject = 'python email test' 12 | content = 'this is content' 13 | msg = MIMEText(content) 14 | msg['subject'] = subject 15 | msg['From'] = msg_from 16 | msg['To'] = msg_to 17 | 18 | try: 19 | s = smtplib.SMTP_SSL('smtp.163.com',465) 20 | s.login(msg_from, passwd) 21 | s.sendmail(msg_from, msg_to, msg.as_string()) 22 | print('Send Success') 23 | except Exception as e: 24 | print('Send Failed') 25 | finally: 26 | s.quit() 27 | ``` 28 | 29 | -------------------------------------------------------------------------------- /八大排序算法.md: -------------------------------------------------------------------------------- 1 | ## 八大排序算法 2 | 3 | > 文章摘自jobbole,代码内注释为JiaxingZhao自行添加 4 | 5 | [原文地址]: http://python.jobbole.com/82270/ 6 | 7 | 8 | 9 | #### 1、插入排序 10 | 11 | ##### **描述** 12 | 13 | ​ 插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。 14 | 15 | ##### **代码实现** 16 | 17 | ```python 18 | # 插入排序 19 | def insert_sort(lists): 20 | # 将list的长度赋值给count 21 | count = len(lists) 22 | # 从1开始遍历list 23 | for i in range(1, count): 24 | # 将当前遍历的项的值赋值给key 25 | key = lists[i] 26 | # 将i-1的值赋值给j 27 | j = i - 1 28 | # 使用while循环,当j>=0时执行,即j的位置在list中执行 29 | while j >= 0: 30 | # 第一次进入时,因i=1,j=0,j为列表第一位,i为列表第二位,如果第一位大于第二位,让这两个数值交换位置, 31 | if lists[j] > key: 32 | lists[j + 1], lists[j] = lists[j], key 33 | #交换位置后让j-=1,等于是交换后的数值再与其前一位做判断 34 | j -= 1 35 | # 将最后的lists返回出去 36 | return lists 37 | ``` 38 | 39 | 40 | 41 | #### 2、希尔排序 42 | 43 | ##### **描述** 44 | 45 | 希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。 46 | 47 | ##### **代码实现** 48 | 49 | ```python 50 | # 希尔排序 51 | def shell_sort(lists): 52 | count = len(lists) 53 | step = 2 54 | group = count / step 55 | while group > 0: 56 | for i in range(0, group): 57 | j = i + group 58 | while j < count: 59 | k = j - group 60 | key = lists[j] 61 | while k >= 0: 62 | if lists[k] > key: 63 | lists[k + group] = lists[k] 64 | lists[k] = key 65 | k -= group 66 | j += group 67 | group /= step 68 | return lists 69 | ``` 70 | 71 | 72 | 73 | #### 3、冒泡排序 74 | 75 | ##### **描述** 76 | 77 | 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。 78 | 79 | ##### **代码实现** 80 | 81 | ```python 82 | # 冒泡排序 83 | def bubble_sort(lists): 84 | # 将lists列表长度赋值给count 85 | count = len(lists) 86 | # 遍历lists中每一个位置 87 | for i in range(0, count): 88 | # 遍历当前项的下一项 89 | for j in range(i + 1, count): 90 | # 如果当前项的值小于下一项的值,则交换位置 91 | if lists[i] > lists[j]: 92 | lists[i], lists[j] = lists[j], lists[i] 93 | # 将排序后的列表返回 94 | return lists 95 | ``` 96 | 97 | 98 | 99 | #### 4、快速排序 100 | 101 | ##### **描述** 102 | 103 | 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。 104 | 105 | **代码实现** 106 | 107 | ```python 108 | # 第一种实现方式 109 | def quicksort(arr, left, right): 110 | # 只有left < right 排序 111 | if left < right: 112 | pivot_index = partition(arr, left, right) 113 | quicksort(arr, left, pivot_index -1) 114 | quicksort(arr, pivot_index + 1, right) 115 | 116 | def partition(arr, left, right): 117 | """找到基准位置, 并返回""" 118 | pivot_index = left 119 | pivot = arr[left] 120 | 121 | for i in range(left + 1, right + 1): 122 | if arr[i] < pivot: 123 | # 如果此处索引的值小于基准值, 基准值的位置后移一位 124 | # 并将后移一位的值和这个值交换, 让基准位置及之前的始终小于基准值 125 | pivot_index += 1 126 | if pivot_index != i: 127 | arr[pivot_index], arr[i] = arr[i], arr[pivot_index] 128 | # 将基准值移动到正确的位置 129 | arr[left], arr[pivot_index] = arr[pivot_index], arr[left] 130 | return pivot_index 131 | 132 | if __name__ == '__main__': 133 | arr = [1,3,2,4,5,7,6,8] 134 | print (arr) 135 | quicksort(arr, 0, len(arr)-1) 136 | print (arr) 137 | 138 | 139 | # 第二种实现方式 140 | def quick_sort(list): 141 | if not list: 142 | return [] 143 | pivot = list[0] 144 | less = [x for x in list[1:] if x <= pivot] 145 | bigger = [x for x in list[1:] if x >= pivot] 146 | return quick_sort(less) + [pivot] + quick_sort(bigger) 147 | 148 | a = [1,3,2,4,5,7,6,8] 149 | print(quick_sort(a)) 150 | 151 | 152 | # 第三种实现方式 153 | def quick_sort(list): 154 | return [] if list == [] else quick_sort([x for x in list[1:] if x <= list[0]]) \ 155 | + [list[0]] + quick_sort([x for x in list[1:] if x >= list[0]]) 156 | 157 | a = [1, 3, 2, 4, 5, 7, 6, 8] 158 | print(quick_sort(a)) 159 | ``` 160 | 161 | 162 | 163 | #### 5、直接选择排序 164 | 165 | ##### **描述** 166 | 167 | 基本思想:第1趟,在待排序记录r1 ~ r[n]中选出最小的记录,将它与r1交换;第2趟,在待排序记录r2 ~ r[n]中选出最小的记录,将它与r2交换;以此类推,第i趟在待排序记录r[i] ~ r[n]中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完毕。 168 | 169 | ##### **代码实现** 170 | 171 | ```python 172 | def select_sort(lists): 173 | # 选择排序 174 | count = len(lists) 175 | for i in range(0, count): 176 | min = i 177 | for j in range(i + 1, count): 178 | if lists[min] > lists[j]: 179 | min = j 180 | lists[min], lists[i] = lists[i], lists[min] 181 | return lists 182 | ``` 183 | 184 | 185 | 186 | #### 6、堆排序 187 | 188 | ##### **描述** 189 | 190 | 堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。 191 | 192 | ##### **代码实现** 193 | 194 | ```python 195 | def adjust_heap(lists, i, size): 196 | lchild = 2 * i + 1 197 | rchild = 2 * i + 2 198 | max = i 199 | if i < size / 2: 200 | if lchild < size and lists[lchild] > lists[max]: 201 | max = lchild 202 | if rchild < size and lists[rchild] > lists[max]: 203 | max = rchild 204 | if max != i: 205 | lists[max], lists[i] = lists[i], lists[max] 206 | adjust_heap(lists, max, size) 207 | 208 | def build_heap(lists, size): 209 | for i in range(0, (size/2))[::-1]: 210 | adjust_heap(lists, i, size) 211 | 212 | def heap_sort(lists): 213 | size = len(lists) 214 | build_heap(lists, size) 215 | for i in range(0, size)[::-1]: 216 | lists[0], lists[i] = lists[i], lists[0] 217 | adjust_heap(lists, 0, i) 218 | ``` 219 | 220 | 221 | 222 | #### 7、归并排序 223 | 224 | ##### **描述** 225 | 226 | 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 227 | 228 | 归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。 229 | 230 | ##### **代码实现** 231 | 232 | ```python 233 | def merge(left, right): 234 | i, j = 0, 0 235 | result = [] 236 | while i < len(left) and j < len(right): 237 | if left[i] <= right[j]: 238 | result.append(left[i]) 239 | i += 1 240 | else: 241 | result.append(right[j]) 242 | j += 1 243 | result += left[i:] 244 | result += right[j:] 245 | return result 246 | 247 | def merge_sort(lists): 248 | # 归并排序 249 | if len(lists) <= 1: 250 | return lists 251 | num = len(lists) / 2 252 | left = merge_sort(lists[:num]) 253 | right = merge_sort(lists[num:]) 254 | return merge(left, right) 255 | ``` 256 | 257 | 258 | 259 | #### 8、基数排序 260 | 261 | ##### **描述** 262 | 263 | 基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。 264 | 265 | ##### **代码实现** 266 | 267 | ```python 268 | import math 269 | def radix_sort(lists, radix=10): 270 | k = int(math.ceil(math.log(max(lists), radix))) 271 | bucket = [[] for i in range(radix)] 272 | for i in range(1, k+1): 273 | for j in lists: 274 | bucket[j/(radix**(i-1)) % (radix**i)].append(j) 275 | del lists[:] 276 | for z in bucket: 277 | lists += z 278 | del z[:] 279 | return lists 280 | ``` 281 | 282 | 283 | 284 | 285 | 286 | #### 附加内容: 287 | 288 | ##### 计数排序: 289 | 290 | 时间复杂度O(N),建立N个桶,将对应数值的数据放入桶中,依次倒出,倒出的顺序就是排序的顺序 291 | 292 | 293 | 294 | ##### 空间复杂度: 295 | 296 | O(1)​: 297 | 298 | ​ 插入排序、选择排序、冒泡排序、堆排序(用递归实现的话空间复杂度为$$O(logN)$$)、希尔排序 299 | 300 | O(logN) - O(N): 301 | 302 | ​ 快速排序 303 | 304 | O(N): 305 | 306 | ​ 归并排序 307 | 308 | O(M): 309 | 310 | ​ 计数排序、基数排序 311 | 312 | 313 | 314 | ##### 时间复杂度: 315 | 316 | O(N):计数排序、基数排序 317 | 318 | O(N^2) : 冒泡排序、选择排序、插入排序 319 | 320 | O(N*logN) :快速排序、归并排序 321 | 322 | O(N*logK) :堆排序 323 | 324 | 325 | 326 | ##### 稳定的排序算法: 327 | 328 | ​ 冒泡排序、插入排序、归并排序、计数排序、基数排序、桶排序 329 | 330 | ##### 不稳定的排序算法: 331 | 332 | ​ 选择排序、快速排序、希尔排序、堆排序 333 | 334 | -------------------------------------------------------------------------------- /关于OOP.md: -------------------------------------------------------------------------------- 1 | > 引用自Python学习手册第四版 2 | 3 | #### OOP: 4 | 5 | ##### 代码重用: 6 | 7 | ​ 通过支持继承,类允许通过定制来编程,而不是每次都从头开始一个项目。 8 | 9 | 10 | 11 | ##### 封装: 12 | 13 | ​ 在对象接口后包装其实现的细节,从而隔离了代码的修改对用户产生的影响。 14 | 15 | 16 | 17 | ##### 结构: 18 | 19 | ​ 类提供了一个新的本地作用域,最小化了变量名冲突,还提供了一种编写和查找实现代码,以及去管理对象状态的自然场所。 20 | 21 | 22 | 23 | ##### 维护性: 24 | 25 | ​ 类自然而然地促进了代码的分解,减少了冗余,有了支持类的结构以及代码重用,每次只需要修改代码中的一个拷贝就可以了。 26 | 27 | 28 | 29 | ##### 一致性: 30 | 31 | ​ 类和继承可以实现通用的接口,这样代码有了统一的外表和观感,也简化了代码的调试、理解以及维护。 32 | 33 | 34 | 35 | ##### 多态: 36 | 37 | ​ 通过广泛的支持代码,多态让代码更灵活和更广泛的适用性,有了更好的可重用性。 -------------------------------------------------------------------------------- /列表推导式.md: -------------------------------------------------------------------------------- 1 | ## 列表推导式: 2 | 3 | 一个列表推导式包含以下几个部分: 4 | 5 | - 一个输入序列 6 | - 一个表示输入序列成员的变量 7 | - 一个可选的断言表达式 8 | - 一个将输入序列中满足断言表达式的成员变换成输出列表成员的输出表达式 9 | 10 | ```python 11 | num = [1, 4, -5, 10, -7, 2, 3, -1] 12 | list = [ x**2 for x in num if x > 0 ] 13 | print list 14 | 15 | num = 20 16 | list = [ num for x in range(3) ] 17 | print list 18 | 19 | # [1, 16, 100, 4, 9] 20 | # [20, 20, 20] 21 | ``` 22 | 23 | ![img](http://jbcdn2.b0.upaiyun.com/2014/02/8db6c2a8d716d7788d0e526c921cc504.jpg) 24 | 25 | 生成器表达式同列表推导式有着几乎相同的语法结构,区别在于生成器表达式是被圆括号包围,而不是方括号: 26 | 27 | ```python 28 | num = [1, 4, -5, 10, -7, 2, 3, -1] 29 | filtered_and_squared = ( x**2 for x in num if x > 0 ) 30 | print filtered_and_squared 31 | 32 | for item in filtered_and_squared: 33 | print item 34 | 35 | # 1, 16, 100 4,9 36 | ``` 37 | 38 | 使用zip()函数一次处理两个或多个列表中的元素: 39 | 40 | ```python 41 | alist = ['a1', 'a2', 'a3'] 42 | blist = ['1', '2', '3'] 43 | 44 | for a, b in zip(alist, blist): 45 | print a, b 46 | 47 | # a1 1 48 | # a2 2 49 | # a3 3 50 | ``` 51 | 52 | 通过两阶列表推导式遍历目录: 53 | ```python 54 | import os 55 | def tree(top): 56 | for path, names, fnames in os.walk(top): 57 | for fname in fnames: 58 | yield os.path.join(path, fname) 59 | 60 | for name in tree('C:\Users\XXX\Downloads\Test'): 61 | print name 62 | ``` 63 | -------------------------------------------------------------------------------- /微信itchat 图灵api.md: -------------------------------------------------------------------------------- 1 | #### 微信itchat 图灵api 2 | 3 | ```python 4 | #coding=utf8 5 | import requests 6 | import itchat 7 | 8 | KEY = 'tuling key' 9 | 10 | def get_response(msg): 11 | apiUrl = 'http://www.tuling123.com/openapi/api' 12 | data = { 13 | 'key' : KEY, 14 | 'info' : msg, 15 | 'userid' : 'wechat-robot', 16 | } 17 | try: 18 | r = requests.post(apiUrl, data=data).json() 19 | # 字典的get方法在字典没有'text'值的时候会返回None而不会抛出异常 20 | return r.get('text') 21 | print(r) 22 | # 为了防止服务器没有正常响应导致程序异常退出,这里用try-except捕获了异常 23 | # 如果服务器没能正常交互(返回非json或无法连接),那么就会进入下面的return 24 | except: 25 | # 将会返回一个None 26 | return 27 | 28 | # 这里是我们在“1. 实现微信消息的获取”中已经用到过的同样的注册方法 29 | @itchat.msg_register(itchat.content.TEXT) 30 | def tuling_reply(msg): 31 | # 为了保证在图灵Key出现问题的时候仍旧可以回复,这里设置一个默认回复 32 | defaultReply = '佳星说: ' + msg['Text'] 33 | # 如果图灵Key出现问题,那么reply将会是None 34 | reply = get_response(msg['Text']) 35 | # a or b的意思是,如果a有内容,那么返回a,否则返回b 36 | # 有内容一般就是指非空或者非None,你可以用`if a: print('True')`来测试 37 | return reply or defaultReply 38 | 39 | # 为了让实验过程更加方便(修改程序不用多次扫码),我们使用热启动 40 | itchat.auto_login(hotReload=True) 41 | itchat.run() 42 | ``` 43 | 44 | --------------------------------------------------------------------------------