近期由于工作原因,开始了解vue3
的内容。vue3
相对于vue2
采用了组合式的描述,原来的写法是:
1 | export default { |
而到了vue3
,提倡的写法变成了:
近期由于工作原因,开始了解vue3
的内容。vue3
相对于vue2
采用了组合式的描述,原来的写法是:
1 | export default { |
而到了vue3
,提倡的写法变成了:
近期准备开始做electron
相关的开发工作,因此借着这个机会就再去了解下electron
。在很久以前的文章中有稍微玩过electron+react+antd
的脚手架,但也只限于快速开发electron
应用,并没有去剖析整个项目结构。因此这次,还是得深入一下。
先前一段时间特别喜欢用开源的Motrix下载器,就是基于electron+vue+aria2
去实现的,所以索性就把源码给clone
了下来。本文就从最基础的开始,以Motrix
的启动逻辑为入口,来研究下一个electron
应用是如何打开的。
首先看一下Motrix
的目录结构,源码基本在src
下,呈现这样的层级关系:
正则表达式是文本处理中的重要部分,通过匹配特定的正则表达式,能够很方便地编写提取特定文本的代码。在python
中,同样也已经拥有了正则表达式库re
,为各位开发者提供了正则表达式的支持。
在python
官方文档中,已经对正则表达式模块接口、词法和用法做了详细的介绍:
re
——正则表达式操作正则表达式常见的用法如下:
1 | import re |
test_pattern
中,compile
了一个只匹配2~3个数字字符的正则对象,test_matches
中,则匹配了数字+小写字母+数字的正则对象,并且用括号分了三个组。两个函数打印出来的结果是:
1 | None |
接下来我们就深入其中,看下源码怎么实现的。
python
的字符串实质到底是什么类型的数据,这个可是困扰着很多编程者的话题。在python2
我们已经被中文编码相关的问题折磨的不轻,那到了python3
之后为什么又解决了这个问题呢?今天这篇文章就带大家详细剖析python3
的字符串实现。
我们首先看一段代码:
1 | def test_str_basic(): |
这段代码打印了一个字符串对象的类型,其结果为<class 'str'>
。str
类型从哪里来?从C源码中我们可以搜索到,其来源于unicodeobject.c
的PyUnicode_Type
在上篇文章里说完了日志实例Logger
和日志管理Manager
,现在该提到Handler
了。Handler
是日志信息的消费者,单个Logger
实例注册多个Handler
,每生成一个LogRecord
,就会被合法的Handler
消费,在不同地方打印出日志信息。
要研究Handler
,首先需要看下基类的实现:
1 | class Handler(Filterer): |
Handler
会通过自带的重入锁限制日志记录被串行处理。Handler
也是继承Filterer
,首先会通过filter
过滤日志是否满足Handler
的要求,如果合法,然后调用emit
方法处理日志。
emit
方法在基类是NotImplemented
,需要子类加以实现。因此接下来我们具体抽几个例子来看。
python语言内置了一个强大的日志模块logging
,也是python内部最为复杂的功能模块之一,通过这个模块我们能够实现不同样式的日志打印。关于logging
模块的官方文档也非常完备:
为此,本文起我们对python的logging
模块进行深入剖析,从而让大家能够更好地掌握python的logging
模块。
在游戏自动化测试领域,行为树由于其强大的描述玩家(Agent)行为逻辑的功能,在很多场景的自动化测试都能得到应用。但是,如果对行为树的作用认识不足,很容易导致整一个自动化测试项目出现难以维护的窘境。因此,这篇文章谈一谈在游戏自动化测试里,用行为树做测试的一些误区。
除了通过引用计数直接销毁对象之外,python
还是拥有内在GC
机制的,并且也有完整的一套流程。
如果只有通过引用计数销毁对象这种机制,那么随便构造一个循环引用就会造成内存泄漏,比如下面的代码:
1 | def _dump_gc(): |
打印出来的结果是:
1 | 13707 |
很显然,当退出_test_internal
作用域时,gc
对象的数量没有变化,这就说明在_test_internal
里创建的a、b
两个对象没有被立即释放掉。如果注释掉两个append
行,就能看到打印结果第三行变成了13707
,说明a、b
在退出函数时就被销毁了。
所以首先,我们从循环引用入手,来研究一下python
的gc
机制(好巧不巧的是,python
的gc
也是专门为循环引用而设置的)。调用gc.collect
触发gc
之后,会跑到gc_collect_main
触发完整的gc
流程。gc_collect_main
是python
整个gc
流程的主入口,我们来看其中的代码:
对于编程语言runtime来说,建立起良好运转GC机制是非常必要的,像Java
和Go
,其GC机制都经历了复杂的演化,当然同时也为编程语言带来了更好的性能,这也是为什么这两门语言能成为主流服务端语言的原因之一。
相对于Java
和Go
,python
的GC机制是相对简约的,其中最基础的机制之一就是引用计数。当对象生成时引用计数为1;对象被其它对象引用时引用计数增加1;对象没有被引用,又退出作用域的话,引用计数归0;引用计数归0后,对象被销毁。
我们可以通过一个例子对引用计数机制进行研究:
1 | def test_ref(): |
其反编译的结果是:
说完了asyncio
事件循环是如何运行异步任务的,接下来back to basic,我们一起看看async
和await
两个原语具体代表了什么含义。
首先是async
,async
通常用来修饰一个函数,表示这个函数会返回一个协程。比如说:
1 | async def _coro_maker(i): |
对_coro_maker
进行反编译,得到这样的结果: