先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Python全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Python知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024c (备注Python)
正文
variable=self._show_status)
helpmenu=Menu(self,tearoff=False)
helpmenu.add_command(label="关于",command=self.about)
helpmenu.add_command(label="反馈",command=self.feedback)
menu.add_cascade(label="文件",menu=filemenu)
menu.add_cascade(label="编辑",menu=self.editmenu)
menu.add_cascade(label="查看",menu=view)
menu.add_cascade(label="帮助",menu=helpmenu)
# 创建弹出在self.txt\_decoded和self.hexdata的菜单
popup1=Menu(self.txt_decoded,tearoff=False)
def \_cut():
self.txt_decoded.event_generate("<<Cut>>")
self._edit_decoded_event()
def \_paste():
self.txt_decoded.event_generate("<<Paste>>")
self._edit_decoded_event()
popup1.add_command(label="剪切",command=_cut)
popup1.add_command(
label="复制",command=lambda:self.txt_decoded.event_generate("<<Copy>>"))
popup1.add_command(label="粘贴",command=_paste)
popup2=Menu(self.hexdata,tearoff=False)
popup2.add_command(
label="复制",command=lambda:self.hexdata.event_generate("<<Copy>>"))
self.txt_decoded.bind("<Button-3>",
lambda event:popup1.post(event.x_root,event.y_root))
self.txt_decoded.bind("<Key>",self._edit_decoded_event)
self.hexdata.bind("<Button-3>",
lambda event:popup2.post(event.x_root,event.y_root))
# 显示菜单
self.config(menu=menu)
def create\_binarytools(self): # 用于二进制文件
if self.isbinary: # self.txt\_decoded 用于显示解码的转义字符
self.txt_decoded.pack(side=LEFT,expand=True,fill=BOTH)
self.hexdata.pack(fill=Y) # hexdata 用于显示转义字符的十六进制
self.status.pack_forget()
self.status.pack(fill=X)
self.editmenu.entryconfig(8,state=NORMAL)
else: # 隐藏工具
if self.txt_decoded:
self.txt_decoded.pack_forget()
if self.hexdata:
self.hexdata.pack_forget()
self.status.pack(side=RIGHT)
self.editmenu.entryconfig(8,state=DISABLED) # 禁止插入
以下是部分控件事件的处理, 包含了实现快捷键、改变字体和显示/隐藏状态栏功能:
def \_get\_fontname(self):
font=' '.join(self.contents["font"].split(' ')[:-2])
# tkinter会将带空格的字体名称用{}括起来
if '{' in font:
font = font[1:-1]
return font
def set\_fontsize(self,index):
newsize=self.FONTSIZES[index]
fontname = self._get_fontname()
self.contents["font"]=(fontname,newsize,"normal")
def choose\_font(self):
def ok():
self.contents["font"]=[opt.get()] + \
self.contents["font"].split(' ')[-2:] # 保留原先大小、样式
dialog.destroy()
dialog = Toplevel(self)
dialog.title('选择字体')
dialog.resizable(False,False)
dialog.attributes('-toolwindow',True)
opt = ttk.Combobox(dialog)
# tkinter.font.families() 获取所有字体名称, 注意root参数
opt['values']=sorted(font.families(root=self))
opt.grid(row=0,column=0,columnspan=2,padx=15,pady=20)
ttk.Button(dialog,text='确定',command=ok).grid(row=1,column=0)
ttk.Button(dialog,text='取消',command=dialog.destroy).grid(row=1,column=1)
oldfont = self._get_fontname()
opt.set(oldfont)
dialog.grab_set() # 对话框打开时, 不允许用户操作主窗口
dialog.focus_force()
def increase\_font(self):
# 增大字体
fontsize=int(self.contents["font"].split(' ')[1])
index=self.FONTSIZES.index(fontsize)+1
if 0<=index<len(self.FONTSIZES): self.set_fontsize(index)
def decrease\_font(self):
# 减小字体
fontsize=int(self.contents["font"].split(' ')[1])
index=self.FONTSIZES.index(fontsize)-1
if 0<=index<len(self.FONTSIZES): self.set_fontsize(index)
def set\_wrap(self):
if self.is_autowrap.get():
self.contents['wrap'] = CHAR
else:
self.contents['wrap'] = NONE
# 注意:由于tkinter会自动设置菜单复选框的变量, 所以不需要此行代码
self.is_autowrap.set(int(not self.is_autowrap.get()))
def show\_statusbar(self):
if self._show_status.get():
if self.isbinary:
self.statusbar.pack(side=BOTTOM,fill=X)
else:
self.statusbar.pack(side=BOTTOM,fill=X)
else:
self.statusbar.pack_forget()
def window\_onkey(self,event):
# 实现快捷键的部分
# 如果按下Ctrl键
if event.state in (4,6,12,14,36,38,44,46): # 适应多种按键情况(Num,Caps,Scroll)
key=event.keysym.lower()
if key=='o':#按下Ctrl+O键
self.open()
elif key=='s':#Ctrl+S键
self.save()
elif key=='n':
self.new()
elif key=='f':
self.show_dialog(SearchDialog)
elif key=='h':
self.show_dialog(ReplaceDialog)
elif key=='equal':#Ctrl+ "+" 增大字体
self.increase_font()
elif key=='minus':#Ctrl+ "-" 减小字体
self.decrease_font()
elif event.keysym.lower()=='f3':
self.findnext()
elif event.keycode == 93: # 按下了菜单键
self.editmenu.post(self.winfo_x()+self.winfo_width(),
self.winfo_y()+self.winfo_height())
def about(self):
msgbox.showinfo("关于","版本: %s\n作者: %s"%(__version__, __author__), parent=self)
## 2.文本打开, 保存
打开文件有两种方法, 一种是在当前窗口中打开, 第二种是新建一个`Editor`实例, 在新窗口中打开。这里在新窗口中打开文件。
`ask_for_save()`的部分有一些复杂, 需要多次判断, 如判断用户是否取消操作、询问打开文件前是否需要保存等。
如: 用户在"是否保存"中选择了"是", 但在输入文件名的对话框中点击了取消, 应该如何处理?具体可看注释。
关于使用`chardet`库自动检测编码:
`chardet.detect()`函数返回一个字典, 包含检测结果。其中`encoding`键即为检测到的编码。
在之前的**Editor类中**加入以下代码:
def new(self): # 新建一个Editor实例
try:self.saveconfig() # 保存配置,使新的窗口加载修改后的配置
except OSError:pass # 忽略写入文件可能产生的异常
window=Editor()
window.focus_force()
return window
def new\_binary(self): # 创建新二进制文件
try:self.saveconfig()
except OSError:pass
window=Editor()
window.isbinary=True
window.create_binarytools()
window.change_title()
window.change_mode()
window.contents.edit_reset()
window.focus_force()
return window
def open(self):
#加载一个文件
filename=filediag.askopenfilename(master=self,title='打开',
initialdir=os.path.split(self.filename)[0],
filetypes=self.FILETYPES)
if not filename:return
if not self.filename and not self.file_modified: # 如果是刚新建的, 在当前窗口中打开
self.load(filename)
else:self.new().load(filename)
def open\_as\_binary(self):
filename=filediag.askopenfilename(master=self,title='打开二进制文件',
initialdir=os.path.split(self.filename)[0],
filetypes=self.FILETYPES)
if not filename:return
if not self.filename and not self.file_modified: # 如果是刚新建的
self.load(filename,binary=True)
else:self.new().load(filename,binary=True)
def load(self,filename,binary=False):
# 加载文件
self.isbinary=binary
try:
data=self._load_data(filename)
if data==0:return
self.filename=filename
self.contents.delete('1.0', END)
if self.isbinary:
self.contents.insert(INSERT,data)
else:
for char in data:
try:
self.contents.insert(INSERT,char)
except TclError:self.contents.insert(INSERT,' ')
self.contents.mark_set(INSERT,"1.0")
self.create_binarytools()
self.file_modified=False
self.change_title()
self.change_mode()
self.contents.edit_reset() # 重置文本框的撤销功能
self.contents.focus_force()
except Exception as err:handle(err,parent=self)
def \_load\_data(self,filename):
# 从文件加载数据
f=open(filename,"rb")
if self.isbinary:
data=to_escape_str(f.read())
return data
else:
try:
#读取文件,并对文件内容进行编码
raw=f.read()
if self.coding.get()=="自动":
# 调用chardet库
encoding=chardet.detect(raw[:100000])['encoding']
if encoding is None:
encoding='utf-8'
self.coding.set(encoding)
data=str(raw,encoding=self.coding.get())
except UnicodeDecodeError:
f.seek(0)
result=msgbox.askyesnocancel("PyNotepad","""%s编码无法解码此文件,
是否使用二进制模式打开?“”“%self.coding.get(),parent=self)
if result:
self.isbinary=True
data=to_escape_str(f.read())
elif result is not None:
self.isbinary=False
data=str(f.read(),encoding=self.coding.get(),errors=“replace”)
else:
return 0 # 表示取消
return data
def ask_for_save(self,quit=True):
my_ret=None
if self.file_modified:
retval=msgbox.askyesnocancel(“文件尚未保存”,
“是否保存{}的更改?”.format(
os.path.split(self.filename)[1] or “当前文件”)
,parent=self)
# retval 为 None表示取消, False为否, True为是
if not retval is None:
if retvalTrue:
# 是
ret=self.save()
# 在保存对话框中取消
if ret0:
my_ret=0;quit=False
# 否
else:
# 取消
my_ret=0;quit=False # 0表示cancel
if quit:
Editor.windows.remove(self)
try:self.saveconfig() # 保存配置, 见附
except OSError:pass
self.destroy() # tkinter不会自动关闭窗口, 需调用函数手动关闭
return my_ret
def save(self):
#保存文件
if not self.filename:
self.filename=filediag.asksaveasfilename(master=self,
initialdir=os.path.split(self.filename)[0],
filetypes=self.FILETYPES)
filename=self.filename
if filename.strip():
text=self.contents.get(‘1.0’, END)[:-1] # [:-1]: 去除末尾换行符
if self.isbinary:
data=to_bytes(text)
else:
data=bytes(text,encoding=self.coding.get(),errors=‘replace’)
# Text文本框的bug:避免多余的\r换行符
# 如:输入文字foobar, data中变成\rfoobar
# -感谢文章末尾用户评论的反馈-
data=data.replace(b’\r’,b’')
with open(filename, ‘wb’) as f:
f.write(data)
self.filename=filename
self.file_modified=False
self.change_title()
self.change_mode()
else:
return 0 # 0表示cancel
def save_as(self):
filename=filediag.asksaveasfilename(master=self,
initialdir=os.path.split(self.filename)[0],
filetypes=self.FILETYPES)
if filename: # 如果未选择取消
self.filename=filename
self.save()
def change_title(self):
file = os.path.split(self.filename)[1] or “未命名”
newtitle=“PyNotepad - “+ file +
(” (二进制模式)” if self.isbinary else ‘’)
if self.file_modified:
newtitle=”*%s*"%newtitle
self.title(newtitle)
## 3.文本编辑
其中, `text_change()`在文本被修改时调用, `update_status()`和`update_offset()`用于更新状态栏中的数据。
在二进制模式中, update\_status获取用户选择的文本, 更新解码的数据和十六进制值。update\_offset更新偏移量。在文本模式中, update\_offset更新当前的行数和列数。
在ScrolledText控件中,
获取选择的文本: `text.get(SEL_FIRST,SEL_LAST)`
获取当前光标位置: `text.index(INSERT)`
在之前的**Editor类中**加入以下代码:
def text\_change(self,event=None):
self.file_modified=True
self.update_status();self.change_title()
def update\_status(self,event=None):
if not self._show_status.get():return
if self.isbinary:
# 用于二进制文件
try:
selected=self.contents.get(SEL_FIRST,SEL_LAST) # 获取从开头到光标处的文本
raw=to_bytes(selected)
coding=self.coding.get()
# 调用chardet库
if coding=="自动":
coding=chardet.detect(raw[:100000])['encoding']
if coding is None:coding='utf-8'
try:text=str(raw,encoding=coding,
errors="backslashreplace")
except TypeError:
# 修复Python 3.4中的bug: don't know how to handle
# UnicodeDecodeError in error callback
text=str(raw,encoding=coding,
errors="replace")
except LookupError as err: # 未知编码
handle(err,parent=self);return
self.txt_decoded.delete("1.0",END)
self.txt_decoded.insert(INSERT,text)
self.hexdata.delete("1.0",END)
self.hexdata.insert(INSERT,view_hex(raw))
self.status["text"]="选区长度: %d (Bytes)"%len(raw)
except (TclError,SyntaxError): #忽略未选取内容, 或格式不正确
self.txt_decoded.delete("1.0",END)
self.hexdata.delete("1.0",END)
self.update_offset()
else:self.update_offset()
def update\_offset(self,event=None):
if self.isbinary:
prev=self.contents.get("1.0",INSERT) # 获取从开头到光标处的文本
try:
data=to_bytes(prev)
except SyntaxError:
sep='\\'
prev=sep.join(prev.split(sep)[0:-1])
try:data=to_bytes(prev)
except SyntaxError:data=None
if data is not None:
self.status["text"]="偏移量: {} ({})"\
.format(len(data),hex(len(data)))
else:
offset=self.contents.index(INSERT).split('.') # 不能用CURRENT
self.status["text"]="Ln: {} Col: {}".format(\*offset)
## 4.编辑二进制文件
在Python中, bytes数据可用转义序列形式表示, 如\x00\x01\x02\n属于转义序列,
可通过`repr(bytes)[2:-1]`,`eval('b"""'+str+'"""')` 实现转义序列与bytes类型的转换。
这次, 在**Editor类外部**加入以下代码:
def to_escape_str(byte):
# 将字节(bytes)转换为转义字符串
str=‘’;length=1024
for i in range(0,len(byte),length):
str+=repr( byte[i: i+length] ) [2:-1]
str+=‘\n’
return str
def to_bytes(escape_str):
# 将转义字符串转换为字节
# -*****- 1.2.5版更新: 忽略二进制模式中文字的换行符
escape_str=escape_str.replace(‘\n’,‘’)
escape_str=escape_str.replace(‘“”"’,‘\“\”\"’) # 避免引号导致的SyntaxError
escape_str=escape_str.replace(“‘’'”,“\‘\’\'”)
try:
return eval(‘b"“”’+escape_str+‘“”"’)
except SyntaxError:
return eval(“b’‘’”+escape_str+“‘’'”)
以下代码用于兼容WinHex等软件的十六进制数据, 使用`bytes`对象的`fromhex`、`hex`方法。
知识点: `bytes`对象有`fromhex()`和`hex()`方法, 可实现十六进制数据和`bytes`对象之间的**相互转换**。`fromhex()`方法会忽略参数中的空格, 换行符等字符。
在Editor类外部加入以下代码:
def view_hex(byte):
result=‘’
for i in range(0,len(byte)):
result+= byte[i:i+1].hex().zfill(2) + ’ ’
if (i+1) % 4 == 0:result+=‘\n’
return result
在**Editor类中**加入以下代码:
def insert\_hex(self):
hex = simpledialog.askstring('',
"输入WinHex十六进制数据(如:00 1a 3d ff) :",parent=self)
if hex is None:return
try:
data=bytes.fromhex(hex)
self.contents.insert('insert',to_escape_str(data))
except Exception as err:
handle(err,parent=self)
# 以下代码用于直接在self.txt\_decoded中编辑数据
def \_edit\_decoded\_event(self,event=None):
self.after(20,self.edit_decoded) # 如果不使用after(),self.txt\_decoded.get不会返回最新的值
def edit\_decoded(self):
range_=self.contents.tag_ranges(SEL) # 获取选区
if range_:
start,end=range_[0].string,range_[1].string # 转换为字符串
else:start=self.contents.index(INSERT);end=None
try:
coding=self.coding.get()
if coding=="自动":
msgbox.showinfo('','不支持自动编码, 请选择或输入其他编码',parent=self)
return
byte = self.txt_decoded.get('1.0',END)[:-1].encode(coding)
esc_char = to_escape_str(byte,linesep=False)
self.file_modified=True;self.change_title()
if range_:
self.contents.delete(start,end)
self.contents.insert(start,esc_char)
end = '%s+%dc'%(start, len(esc_char))
self.contents.tag_add(SEL,start,end)
except Exception as err:handle(err,parent=self)
## 5.查找、替换对话框
这里主要用到文本框Text的`search`方法,
该函数接收2个必选参数, 分别是pattern和index, index为起始索引, search 方法返回起始索引处或之后的第一个匹配项的索引。
search方法还有一些可选参数:
`regexp`: 是否使用正则表达式查找 (比自己编写代码查找要快)。
`nocase`: 是否不区分大小写。
显示对话框时, 还需调用Tk,Toplevel的focus方法, 用于使对象获得焦点。
注意: 创建`IntVar()`, `StringVar()`时, 需指定参数`master`, 避免创建的变量无法使用。
\* 使对话框跟随父窗口最小化、恢复显示的方法: 调用`transient()`方法。
在**Editor类外部**加入以下代码:
class SearchDialog(Toplevel):
#查找对话框
def __init__(self,master):
self.master=master
self.coding=self.master.coding.get()
def init_window(self,title=“查找”):
Toplevel.init(self,self.master)
self.title(title)
self.attributes(“-toolwindow”,True)
self.attributes(“-topmost”,True)
# 当父窗口隐藏后,窗口也跟随父窗口隐藏
self.transient(self.master)
self.wm_protocol(“WM_DELETE_WINDOW”,self.onquit)
def show(self):
self.init_window()
frame=Frame(self)
ttk.Button(frame,text=“查找下一个”,command=self.search).pack()
ttk.Button(frame,text=“退出”,command=self.onquit).pack()
frame.pack(side=RIGHT,fill=Y)
inputbox=Frame(self)
Label(inputbox,text=“查找内容:”).pack(side=LEFT)
self.keyword=StringVar(self.master)
keyword=ttk.Entry(inputbox,textvariable=self.keyword)
keyword.pack(side=LEFT,expand=True,fill=X)
keyword.bind(“”,self.search)
keyword.focus_force()
inputbox.pack(fill=X)
options=Frame(self)
self.create_options(options)
options.pack(fill=X)
def create_options(self,master):
Label(master,text="选项: ").pack(side=LEFT)
self.use_regexpr=IntVar(self.master)
ttk.Checkbutton(master,text=“使用正则表达式”,variable=self.use_regexpr)
.pack(side=LEFT)
self.match_case=IntVar(self.master)
ttk.Checkbutton(master,text=“区分大小写”,variable=self.match_case)
.pack(side=LEFT)
self.use_escape_char=IntVar(self.master)
self.use_escape_char.set(self.master.isbinary)
ttk.Checkbutton(master,text=“使用转义字符”,variable=self.use_escape_char)
.pack(side=LEFT)
def search(self,event=None,mark=True,bell=True):
text=self.master.contents
key=self.keyword.get()
if not key:return
# 验证用户输入是否正常
if self.use_escape_char.get():
try:key=str(to_bytes(key),encoding=self.coding)
except Exception as err:
handle(err,parent=self);return
if self.use_regexpr.get():
try:re.compile(key)
except re.error as err:
handle(err,parent=self);return
# 默认从当前光标位置开始查找
pos=text.search(key,INSERT,'end-1c',# end-1c:忽略末尾换行符
regexp=self.use_regexpr.get(),
nocase=not self.match_case.get())
if not pos:
# 尝试从开头循环查找
pos=text.search(key,'1.0','end-1c',
regexp=self.use_regexpr.get(),
nocase=not self.match_case.get())
if pos:
if self.use_regexpr.get(): # 获取正则表达式匹配的字符串长度
text_after = text.get(pos,END)
flag = re.IGNORECASE if not self.match_case.get() else 0
length = re.match(key,text_after,flag).span()[1]
else:
length = len(key)
newpos="%s+%dc"%(pos,length)
text.mark_set(INSERT,newpos)
if mark:self.mark_text(pos,newpos)
return pos,newpos
elif bell: # 未找到,返回None
bell_(widget=self)
def findnext(self,cursor_pos='end',mark=True,bell=True):
# cursor\_pos:标记文本后将光标放在找到文本开头还是末尾
# 因为search()默认从当前光标位置开始查找
# end 用于查找下一个操作, start 用于替换操作
result=self.search(mark=mark,bell=bell)
if not result:return
if cursor_pos=='end':
self.master.contents.mark_set('insert',result[1])
elif cursor_pos=='start':
self.master.contents.mark_set('insert',result[0])
return result
def mark\_text(self,start_pos,end_pos):
text=self.master.contents
text.tag_remove("sel","1.0",END) # 移除旧的tag
# 已知问题: 代码高亮显示时, 无法突出显示找到的文字
text.tag_add("sel", start_pos,end_pos) # 添加新的tag
lines=text.get('1.0',END)[:-1].count(os.linesep) + 1
lineno=int(start_pos.split('.')[0])
# 滚动文本框, 使被找到的内容显示 ( 由于只判断行数, 已知有bug); 另外, text['height']不会随文本框缩放而变化
text.yview('moveto', str((lineno-text['height'])/lines))
text.focus_force()
self.master.update_status()
def onquit(self):
self.withdraw()
class ReplaceDialog(SearchDialog):
#替换对话框
def show(self):
self.init_window(title=“替换”)
frame=Frame(self)
ttk.Button(frame,text=“查找下一个”, command=self._findnext).pack()
ttk.Button(frame,text=“替换”, command=self.replace).pack()
ttk.Button(frame,text=“全部替换”, command=self.replace_all).pack()
ttk.Button(frame,text=“退出”, command=self.onquit).pack()
frame.pack(side=RIGHT,fill=Y)
inputbox=Frame(self)
Label(inputbox,text="查找内容:").pack(side=LEFT)
self.keyword=StringVar(self.master)
keyword=ttk.Entry(inputbox,textvariable=self.keyword)
keyword.pack(side=LEFT,expand=True,fill=X)
keyword.focus_force()
inputbox.pack(fill=X)
replace=Frame(self)
Label(replace,text="替换为: ").pack(side=LEFT)
self.text_to_replace=StringVar(self.master)
replace_text=ttk.Entry(replace,textvariable=self.text_to_replace)
replace_text.pack(side=LEFT,expand=True,fill=X)
replace_text.bind("<Key-Return>",self.replace)
replace.pack(fill=X)
options=Frame(self)
self.create_options(options)
options.pack(fill=X)
def \_findnext(self):# 仅用于"查找下一个"按钮功能
text=self.master.contents
sel_range=text.tag_ranges('sel') # 获得选区的起点和终点
if sel_range:
selectarea = sel_range[0].string, sel_range[1].string
result = self.findnext('start')
if result is None:return
if result[0] == selectarea[0]: # 若仍停留在原位置
text.mark_set('insert',result[1])# 从选区终点继续查找
self.findnext('start')
else:
self.findnext('start')
def replace(self,bell=True,mark=True):
text=self.master.contents
result=self.search(mark=False,bell=bell)
if not result:return # 标志已无文本可替换
self.master.text_change()
pos,newpos=result
newtext=self.text_to_replace.get()
try:
if self.use_escape_char.get():
newtext=to_bytes(newtext).decode(self.master.coding.get())
if self.use_regexpr.get():
old=text.get(pos,newpos)
newtext=re.sub(self.keyword.get(),newtext,old)
except Exception as err:
handle(err,parent=self);return
text.delete(pos,newpos)
text.insert(pos,newtext)
end_pos="%s+%dc"%(pos,len(newtext))
if mark:self.mark_text(pos,end_pos)
return pos,end_pos
def replace\_all(self):
self.master.contents.mark_set("insert","1.0") # 将光标移到开头
flag=False # 标志是否已有文字被替换
# 以下代码会导致无限替换, 使程序卡死, 新的代码修复了该bug
#while self.replace(bell=False)!=-1:
# flag=True
last = (0,0)
while True:
result=self.replace(bell=False,mark=False)
if result is None:break
flag = True
result = self.findnext('start',bell=False,mark=False)
if result is None:return
ln,col = result[0].split('.')
ln = int(ln);col = int(col)
# 判断新的偏移量是增加还是减小
if ln < last[0] or (ln==last[0] and col<last[1]):
self.mark_text(\*result) # 已完成一轮替换
break
last=ln,col
if not flag:bell_()
在**Editor类内部**加入以下代码:
def findnext(self):
fd = self._dialogs.get(SearchDialog,None)
if fd:
if fd.findnext():return
rd = self._dialogs.get(ReplaceDialog,None)
if rd:
rd.findnext()
def show\_dialog(self,dialog_type):
# dialog\_type是对话框的类型
if dialog_type in self._dialogs:
# 不再显示新的对话框
d=self._dialogs[dialog_type]
(1)Python所有方向的学习路线(新版)
这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
最近我才对这些路线做了一下新的更新,知识体系更全面了。
(2)Python学习视频
包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。
(3)100多个练手项目
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注python)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
n/1f807758e039481fa866130abf71d796.png#pic_center)
(2)Python学习视频
包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。
(3)100多个练手项目
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注python)
[外链图片转存中…(img-jDdMpUzJ-1713336663583)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!