(整活向)史上最复杂的Hello Python World!
本帖最后由 hrh123 于 2023-6-30 18:05 编辑`print("Hello, World!")`,恐怕是每个人学Python的第一个程序,这几天心血来潮,看到HelloWorld就让我想到我初学编程时的样貌,于是打算简单地给它"重构"下,先亮代码:
```python
import re
import tkinter as tk
import asyncio
class HelloWorldGUI:
def __init__(self, master):
self.master = master
self.label = tk.Label(self.master)
self.label.pack()
self.hello_world_generator = self.hello_world()
def hello_world(self):
while True:
yield "Hello, World!"
def update_label(self):
try:
message = next(self.hello_world_generator)
except StopIteration:
self.hello_world_generator = self.hello_world()
message = next(self.hello_world_generator)
self.label["text"] = message
def start(self):
self.master.after(0, self.update_label)
self.master.mainloop()
def coroutine_decorator(func):
def wrapper(*args, **kwargs):
coro = func(*args, **kwargs)
next(coro)
return coro
return wrapper
@coroutine_decorator
def regex_coroutine(regex, target):
while True:
text = yield
matches = re.findall(regex, text)
for match in matches:
target.send(match)
def main():
root = tk.Tk()
gui = HelloWorldGUI(root)
regex = r"Hello, World!"
@coroutine_decorator
def print_match():
while True:
match = yield
print(f"Match found: '{match}'")
regex_coro = regex_coroutine(regex, print_match())
loop = asyncio.get_event_loop()
def schedule_regex_coroutine():
text = gui.label["text"]
regex_coro.send(text)
loop.call_later(1, schedule_regex_coroutine)
loop.call_soon(schedule_regex_coroutine)
gui.start()
if __name__ == "__main__":
main()
```
现在来详细分析下具体原理(结合代码看效果更佳):
1. 导入必要的库,不多说了
2. 定义一个HelloWorldGUI类,用来封装GUI
3. 在类的初始化方法中,创建一个master属性,用于存储tkinter的根窗口对象;创建一个label属性,用于存储tkinter的标签对象,并将其添加到master中;创建一个hello_world_generator属性,用于存储一个生成器对象,该生成器可以不断产生“Hello, World!”字符串
4. 定义一个hello_world方法,该方法使用一个while循环.不断地yield“Hello,World!”字符串,用于创建上述生成器对象
5. 定义一个update_label方法,用于更新label的文本内容.该方法使用try-except语句,尝试从hello_world_generator中获取下一个字符串,并赋值给message变量.如果遇到StopIteration异常.说明生成器已经耗尽,那么重新创建一个新的生成器对象.并从中获取下一个字符串.然后将message变量赋值给label的text属性
6. 定义一个start方法,用于启动GUI的主循环.该方法使用master的after方法,在0毫秒后调用update_label方法;然后使用master的mainloop方法,进入GUI的事件循环
7. 定义一个coroutine_decorator函数,用于装饰协程函数.该函数接受一个函数作为参数,并返回一个包装函数.包装函数会调用原函数,并获取返回的协程对象.然后使用next函数预激活协程对象,并返回它
8. 使用coroutine_decorator装饰一个regex_coroutine函数,用于创建一个协程对象,该协程可以接收文本,并使用正则表达式查找匹配结果,并将其发送给另一个目标协程.该函数接受两个参数:regex和target.regex是一个正则表达式字符串,target是另一个协程对象.该函数使用一个while循环,不断地yield等待接收文本,并使用re模块的findall函数查找匹配结果.然后使用for循环遍历匹配结果,并将其发送给target协程
9. 定义一个main函数,用于执行主要逻辑
10. 在main函数中,创建一个tkinter的根窗口对象,并赋值给root变量;创建一个HelloWorldGUI对象,并传入root作为参数,并赋值给gui变量
11. 定义一个regex变量,赋值为r"Hello, World!",表示要查找的正则表达式
12. 使用coroutine_decorator装饰一个print_match函数,用于创建一个协程对象,该协程可以接收匹配结果,并打印出来.该函数使用一个while循环,不断地yield等待接收匹配结果,并赋值给match变量.然后使用print函数打印出匹配结果
13. 创建一个print_match协程对象,并赋值给print_match变量;创建一个regex_coroutine协程对象,并传入regex和print_match作为参数并赋值给regex_coro变量
14. 使用asyncio模块的get_event_loop函数获取当前事件循环对象,并赋值给loop变量
15. 定义一个schedule_regex_coroutine函数,用于定时调度regex_coro协程.该函数首先获取label的text属性,并赋值给text变量;然后使用regex_coro的send方法发送text给协程;最后使用loop的call_later方法,在1秒后再次调用schedule_regex_coroutine函数
16. 使用loop的call_soon方法,尽快调用schedule_regex_coroutine函数
17. 使用gui的start方法,启动GUI的主循环
18. 代码的最后,使用if语句判断是否为主模块,如果是,则调用main函数
最终效果:生成一个GUI,中间有一个标签,显示Hello, World!的文本
* * *
更新:相信大家已经学会了上面的基本代码,现在继续来上强度:
```python
import asyncio
import re
import tkinter as tk
class MyDescriptor:
def __get__(self, obj, objtype):
print(f"Getting attribute '{self.name}'")
return obj.__dict__
def __set__(self, obj, value):
print(f"Setting attribute '{self.name}' to '{value}'")
obj.__dict__ = value
def __set_name__(self, owner, name):
self.name = name
class MyMeta(type):
def __new__(cls, name, bases, attrs):
print(f"Creating class '{name}' with bases '{bases}' and attributes '{attrs}'")
new_attrs = {}
for attr_name, attr_value in attrs.items():
if isinstance(attr_value, MyDescriptor):
attr_value.name = attr_name
new_attrs = attr_value
return super().__new__(cls, name, bases, new_attrs)
class HelloWorldGUI(metaclass=MyMeta):
label = MyDescriptor()
def __init__(self, master):
self.master = master
self.label = tk.Label(self.master)
self.label.pack()
self.hello_world_generator = self.hello_world()
def hello_world(self):
while True:
yield "Hello, World!"
def update_label(self):
try:
message = next(self.hello_world_generator)
except StopIteration:
self.hello_world_generator = self.hello_world()
message = next(self.hello_world_generator)
self.label["text"] = message
def start(self):
self.master.after(0, self.update_label)
self.master.mainloop()
def coroutine_decorator(func):
def wrapper(*args, **kwargs):
coro = func(*args, **kwargs)
next(coro)
return coro
return wrapper
@coroutine_decorator
def regex_coroutine(regex, target):
while True:
text = yield
matches = re.findall(regex, text)
for match in matches:
target.send(match)
def main():
root = tk.Tk()
gui = HelloWorldGUI(root)
regex = r"Hello, World!"
@coroutine_decorator
def print_match():
while True:
match = yield
print(f"Match found: '{match}'")
regex_coro = regex_coroutine(regex, print_match())
loop = asyncio.get_event_loop()
def schedule_regex_coroutine():
text = gui.label["text"]
regex_coro.send(text)
loop.call_later(1, schedule_regex_coroutine)
loop.call_soon(schedule_regex_coroutine)
gui.start()
if __name__ == "__main__":
main()
```
代码逻辑分析:
1. 定义了一个自定义描述符类`MyDescriptor`,它重写了`__get__`,`__set__`和`__set_name__`方法,用于在获取或设置属性时打印一些信息,并将属性名和值存储在对象的`__dict__`中
2. 定义了一个自定义元类`MyMeta`,它重写了`__new__`方法,用于在创建类时打印一些信息,并将描述符对象的名字设置为属性名
3. 定义了一个GUI类`HelloWorldGUI`,它使用了自定义元类,并定义了一个描述符属性`label`.它的初始化方法中,创建了一个tkinter标签对象,并将其赋值给描述符属性.它还定义了一个生成器方法`hello_world`,用于不断地生成"Hello,World!"字符串.它还定义了一个更新标签文本的方法`update_label`,用于从生成器中获取下一个字符串,并将其设置为标签的文本.最后,它定义了一个启动GUI的方法`start`,用于调用tkinter的定时器和主循环
4. 定义了一个协程装饰器函数`coroutine_decorator`,用于在调用协程函数时自动执行一次next操作,以便激活协程
5. 定义了一个正则匹配协程函数`regex_coroutine`,它接受一个正则表达式和一个目标协程作为参数.它不断地从外部接收文本,并使用正则表达式在文本中查找匹配结果.对于每个匹配结果,它将其发送给目标协程
6. 在主函数中,创建了一个tkinter根窗口对象,并传递给GUI类的实例.然后定义了一个正则表达式字符串"Hello, World!",用于匹配"Hello, World!"中的"Hello, World!".然后定义了一个打印匹配结果的协程函数`print_match`,并使用协程装饰器装饰.然后创建了一个正则匹配协程对象,并将正则表达式和打印匹配结果的协程作为参数传递.然后获取了asyncio模块的事件循环对象,并定义了一个调度正则匹配协程的函数`schedule_regex_coroutine`.这个函数会获取当前标签的文本,并将其发送给正则匹配协程.然后使用事件循环的定时器,在一秒后再次调用这个函数.最后,使用事件循环的启动函数,在尽快执行一次调度正则匹配协程的函数之后,启动GUI
最终效果:依然是生成一个GUI,中间有一个标签,显示Hello, World!的文本 本帖最后由 hrh123 于 2023-6-30 18:06 编辑
最终版代码,这次就不分析了,感兴趣的自己看看:
```python
import asyncio
import re
import tkinter as tk
class MyDescriptor:
def __get__(self, obj, objtype):
print(f"Getting attribute '{self.name}'")
return obj.__dict__
def __set__(self, obj, value):
print(f"Setting attribute '{self.name}' to '{value}'")
obj.__dict__ = value
def __set_name__(self, owner, name):
self.name = name
class MyMeta(type):
def __new__(cls, name, bases, attrs):
print(f"Creating class '{name}' with bases '{bases}' and attributes '{attrs}'")
new_attrs = {}
for attr_name, attr_value in attrs.items():
if isinstance(attr_value, MyDescriptor):
attr_value.name = attr_name
new_attrs = attr_value
return super().__new__(cls, name, bases, new_attrs)
class HelloWorldGUI(metaclass=MyMeta):
label = MyDescriptor()
def __init__(self, master):
self.master = master
self.label = tk.Label(self.master)
self.label.pack()
self.hello_world_generator = self.hello_world()
def hello_world(self):
while True:
yield "Hello, World!"
def update_label(self):
try:
message = next(self.hello_world_generator)
except StopIteration:
self.hello_world_generator = self.hello_world()
message = next(self.hello_world_generator)
self.label["text"] = message
def start(self):
self.master.after(0, self.update_label)
self.master.mainloop()
class coroutine_decorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
coro = self.func(*args, **kwargs)
next(coro)
return coro
def find_matches(text, regex):
return re.finditer(regex, text)
def regex_coroutine(regex, target):
while True:
text = yield
matches = find_matches(text, regex)
for match in matches:
target.send(match)
def main():
root = tk.Tk()
gui = HelloWorldGUI(root)
regex = r"Hello, World!"
@coroutine_decorator
def print_match():
while True:
match = yield
print(f"Match found: '{match}'")
regex_coro = regex_coroutine(regex, print_match())
loop = asyncio.get_event_loop()
def schedule_regex_coroutine():
text = gui.label["text"]
for match in regex_coro:
regex_coro.send(text)
loop.call_later(1, schedule_regex_coroutine)
loop.call_soon(schedule_regex_coroutine)
gui.start()
if __name__ == "__main__":
main()
``` 直接复制粘贴了一个行内注释代码版
```
# coding:utf-8
"""最终效果:生成一个GUI,中间有一个标签,显示Hello,World!的文本
"""
import re
import tkinter as tk
import asyncio
class HelloWorldGUI:
"""定义一个HelloWorldGUI类,用来封装GUI"""
def __init__(self, master):
"""
在类的初始化方法中,创建一个master属性,用于存储tkinter的根窗口对象;
创建一个label属性,用于存储tkinter的标签对象,并将其添加到master中;
创建一个hello_world_generator属性,用于存储一个生成器对象,该生成器可以不断产生“Hello,World!”字符串
"""
self.master = master
self.label = tk.Label(self.master)
self.label.pack()
self.hello_world_generator = self.hello_world()
def hello_world(self):
"""定义一个hello_world方法,该方法使用一个while循环.不断地yield“Hello,World!”字符串,用于创建上述生成器对象"""
while True:
yield "Hello, World!"
def update_label(self):
"""定义一个update_label方法,用于更新label的文本内容.
该方法使用try-except语句,尝试从hello_world_generator中获取下一个字符串,并赋值给message变量.
如果遇到StopIteration异常.说明生成器已经耗尽,
那么重新创建一个新的生成器对象.并从中获取下一个字符串.然后将message变量赋值给label的text属性
"""
try:
message = next(self.hello_world_generator)
except StopIteration:
self.hello_world_generator = self.hello_world()
message = next(self.hello_world_generator)
self.label["text"] = message
def start(self):
"""定义一个start方法,用于启动GUI的主循环.该方法使用master的after方法,在0毫秒后调用update_label方法;
然后使用master的mainloop方法,进入GUI的事件循环"""
self.master.after(0, self.update_label)
self.master.mainloop()
def coroutine_decorator(func):
"""
定义一个coroutine_decorator函数,用于装饰协程函数.该函数接受一个函数作为参数,并返回一个包装函数.
包装函数会调用原函数,并获取返回的协程对象.然后使用next函数预激活协程对象,并返回它
"""
def wrapper(*args, **kwargs):
coro = func(*args, **kwargs)
next(coro)
return coro
return wrapper
@coroutine_decorator
def regex_coroutine(regex, target):
"""使用coroutine_decorator装饰一个regex_coroutine函数,用于创建一个协程对象,
该协程可以接收文本,并使用正则表达式查找匹配结果,并将其发送给另一个目标协程.
该函数接受两个参数:regex和target.
regex是一个正则表达式字符串,target是另一个协程对象.该函数使用一个while循环,不断地yield等待接收文本,并使用re模块的findall函数查找匹配结果.然后使用for循环遍历匹配结果,并将其发送给target协程
"""
while True:
text = yield
matches = re.findall(regex, text)
for match in matches:
target.send(match)
def main():
"""定义一个main函数,用于执行主要逻辑"""
root = tk.Tk()
"""在main函数中,创建一个tkinter的根窗口对象,并赋值给root变量;"""
gui = HelloWorldGUI(root)
"""创建一个HelloWorldGUI对象,并传入root作为参数,并赋值给gui变量"""
regex = r"lo"
"""定义一个regex变量,赋值为r"lo",表示要查找的正则表达式"""
@coroutine_decorator
def print_match():
"""使用coroutine_decorator装饰一个print_match函数,用于创建一个协程对象,
该协程可以接收匹配结果,并打印出来.该函数使用一个while循环,不断地yield等待接收匹配结果,并赋值给match变量.然后使用print函数打印出匹配结果"""
while True:
match = yield
print(f"Match found: '{match}'")
regex_coro = regex_coroutine(regex, print_match())
"""创建一个print_match协程对象,并赋值给print_match变量;创建一个regex_coroutine协程对象,并传入regex和print_match作为参数并赋值给regex_coro变量"""
loop = asyncio.get_event_loop()
"""使用asyncio模块的get_event_loop函数获取当前事件循环对象,并赋值给loop变量"""
def schedule_regex_coroutine():
"""
定义一个schedule_regex_coroutine函数,用于定时调度regex_coro协程.
该函数首先获取label的text属性,并赋值给text变量;
然后使用regex_coro的send方法发送text给协程;
最后使用loop的call_later方法,在1秒后再次调用schedule_regex_coroutine函数
"""
text = gui.label["text"]
regex_coro.send(text)
loop.call_later(1, schedule_regex_coroutine)
loop.call_soon(schedule_regex_coroutine)
"""使用loop的call_soon方法,尽快调用schedule_regex_coroutine函数"""
gui.start()
"""使用gui的start方法,启动GUI的主循环"""
if __name__ == "__main__":
"""代码的最后,使用if语句判断是否为主模块,如果是,则调用main函数"""
main()
``` 向大佬学习 狠人,事件循环用select或者epoll自己写一个{:1_918:} asyncio 是 Python 标准库中提供的一个异步编程框架。它允许您使用协程编写并发代码,通过多路复用 I/O 访问和运行网络客户端和服务器。
通过使用 asyncio,您可以编写比传统同步编程更高效和可扩展的异步代码。它使用事件循环来管理多个任务的并发执行,使您能够异步执行 I/O 操作,而不会阻塞其他任务的执行。
要使用 asyncio,通常需要使用 async 关键字将函数定义为协程,在其中等待异步操作。事件循环负责管理这些协程,安排它们的执行,并在它们等待 I/O 或其他非阻塞操作时进行切换。 牛人教我学编程 第一次见到python版的复杂hello world 记得第一次用Python编的“Hello World”是:
printf("Hello World")
运行:NameError: name 'printf' is not defined
{:301_1001:} 有点复杂,膜拜下 大佬,带带我