Python能做大项目(8) - Need for Speed! 高效编码之一

1. AI赋能的代码编写

传统上,IDE的重要功能之一,就是代码自动完成、语法高亮、文档提示、错误诊断等等。随着人类进入深度学习时代,AI辅助编码则让程序员如虎添翼。

我们首先介绍几个AI辅助编码的工具,然后再介绍常规的语法高亮、文档提示等功能。

1.1. github copilot

github copilot是github官方出品的AI辅助编码工具。它是基于大规模语料、超大规模的深度学习模型,结合了大量的编程经验,为开发者提供代码补全、代码片段联想、代码推荐等功能。copilot可以根据用户输入的一行注释,自动生成代码片段甚至整个函数,功能十分强大。

在这里插入图片描述

比如,我们写一段注释如下:

# create a fibonacci series up to nth term

然后回车,copilot就会写出下面的代码:

def fibonacci(n):
    if n <= 1:
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)

这个函数还有一个尾递归版本,当然copilot也能提供。一般情况下,copilot能提供10个以内的备选答案。

我们再举一个例子,如果有以下注释:

设置npm中国加速镜像

你会立即得到以下代码:

npm install -g cnpm --registry=https://registry.npm.taobao.org

再也不用记忆这些奇怪的设置了!

我们再试一个例子:

# 读取csv文件,并返回一个数组对象
def read_csv(filename):
    with open(filename, 'r') as f:
        reader = csv.reader(f)
        return list(reader)

# 将数组对象转换为json字符串
def to_json(data):
    return json.dumps(data)

# 将json发送到github
def send_json(json_data):
    url = 'https://api.github.com/repos/udacity/ud120-projects/issues'
    headers = {
        'Authorization': ''  # 请填写你的token
    }
    r = requests.post(url, json_data, headers=headers)

def main():
    data = read_csv('foo.csv')
    json_data = to_json(data)
    send_json(json_data)

在上述例子中,我们只写了三行注释,copilot自动帮我们填充了代码。在send_json那个方法里,copilot在headers中提示输入’Authorization’字段,并提示这里要给出token,这个填充很有意思,它因为github这个API正好是通过token认证的。当然,由于信息过少,它给的url几乎肯定是错的,这也在情理之中。

比较有意思的是main函数。我只定义了main()方法的函数头,copilot居然自动完成了所有功能的串联,而且应该说,符合预期。

如果上面的例子过于简单,你可以写一些注释,请求copilot为你抓取加密货币价格,通过正则表达式判断是否是有效的邮箱地址,或者压缩、解压缩文件等等。你会发现,copilot的能力是非常强大的。

copilot的神奇之处,绝不只限于上面的举例。作者在实践中确实体验过它的超常能力,比如在单元测试中,自动生成数据序列,或者在生成的代码中,它的错误处理方案会比你自己能写出来的更细腻,等等。但是,要演示那样复杂的功能,已经超出了一本书所以展现的范围了。

这是一些使用者的感言:

在这里插入图片描述

所以,Don’t fly solo!(copilot广告语),如果有可能,当你在代码的世界里遨游时,还是让copilot来伴飞吧。当然,copilot也有其不足,其中最重要的一点是,不能免费使用(学生除外),而且每个月10美金的费用对中国程序员来讲可能并不便宜。不仅如此,目前它只接受信用卡和paypal付款,因此在支付上也不够方便。

1.2. tabnine

另一个选项是tabnine,与copilot一样,它也提供了从自然语言到代码的转换,以及整段函数的生成等功能。一些评论认为,它比copilot多出的一个功能是,它能基于语法规则在一行还未结束时就给出代码提示,而copilot只能在一行结束后给出整段代码,即copilot需要更多的上下文信息。

tabnine与copilot的值得一提的区别是它的付费模式。tabnine提供了基础版和专业版两个版本,而copilot只能付费使用。tabnine的专业版还有一个特色,就是你可以基于自己的代码训练自己的私有AI模型,从而得到更为个性化的代码完成服务。这个功能对于一些大型公司来说,可能是一个很好的选择。它的另一个优势就是,它在训练自己时只使用实行宽松开源许可证模式的代码,因此,你的代码不会因为使用了tabnine生成的代码,就必须开源出去。

GPT code clippy是Github copilot的开源替代品,如果既不能用copilot,也不能使用tabnine,也可以试试这个。不过在我们成文的时候,它还没有提供一个发行版的vscode扩展,只能通过源码安装。

!!!Info
说到AI辅助编码,不能不提到这一行的先驱 - Kite。Kite成立于2014年,致力于AI辅助编程,于2021年11月关闭。由于切入市场过早,kite的技术路线也必然相对落后一些,其AI辅助功能主要是基于关键词联想代码片段的模式。等到2020年github的copilot横空出世时,基于大规模语料、超大规模的深度学习模型被证明才是最有希望的技术路线。而此时kite多年以来的投入和技术积累,不仅不再是有效资产,反而成为了历史包袱。往新的技术路线上的切换的代价往往是巨大的 – 用户体验也难免改变,而且新的模型所需要的钞能力,kite也并不具备。

2021年11月16日,创始人Adam Smith发表了一篇告别演说,对kite为什么没有成功进行了反思,指出尽管Kite每个月有超过50万月活跃用户,但这么多月活跃用户基本不付费,这最终压垮了kite。当然,终端用户其实也没有错,毕竟copilot的付费模式能够行得通。人们不为kite付费,也确实是因为kite还不够好。
属于kite的时代已经过去了,但正如Adam Smith所说,未来是光明的。AI必将引发一场编程革命。kite的试验失败了,但催生这场AI试验的所有人:投资人,开发团队以及最终用户,他们的勇气和贡献都值得被铭记。
作为一个曾经使用过kite,也欠Kite一个会员的使用者,我也在此道声感谢与珍重!

尽管AI辅助编程的功能很好用,但仍然有一些场景,我们需要借助传统的工具,比如pylance。pylance是微软官方出品的扩展。vscode本身只是一个通用的IDE框架,对具体某个语言的开发支持(编辑、语法高亮、语法检查、调试等),都是由该语言的扩展及语言服务器(对python而言,有jedi和pylance两个实现)来实现的,因此,pylance是我们在vscode中开发python项目时,必须安装的一个扩展。

它可以随用户输入时,提示函数的签名、文档和进行参数的类型提示,如下图所示:

Pylance在上面提到的代码自动完成之外,还能实现依赖自动导入。此外,由于它脱胎于语法静态检查器,所以它还能提示代码中的错误并显示,这正是到目前为止,像copilot这样的人工智能还做不太好的地方。源码级的查错,使得我们可以尽早修正这些错误,这也正是静态语言程序员认为Python做不到的地方。

在这里插入图片描述

2. Type Hint (Type Annotations)

很多人谈到Python时,会觉得它作为一种动态语言,是没有类型检查能力的。这种说法并不准确,Python是弱类型语言,变量可以改变类型,但在运行时,仍然会有类型检查,类型检查失败,就会抛出TypeError:

下面的例子演示了Python中变量是如何改变类型的,以及类型检查只在运行时进行的这一特点:

>>> one = 1
... if False:
...     one + "two" # 这一行不会执行,所以不会抛出TypeError
... else:
...     one + 2
...
3

>>> one + "two"     # 运行到此处时,将进行类型检查,抛出TypeError
TypeError: unsupported operand type(s) for +: 'int' and 'str'
... one = "one "    # 变量可以通过赋值改变类型
... one + "two"     # 现在类型检查没有问题
one two

但Python曾经确实缺少静态类型检查的能力,这是Python一直以来为人诟病的地方。毕竟,错误发现的越早,修复成本就越低。但这正在成为历史。

类型注解从python 3.0(2006年,PEP 3107,当时还叫function annotations)时被引入,但它的用法和语义并没有得到清晰定义,也没有引起广泛关注和运用。数年之后,PEP 484(type hints including generics)被提出,定义了如何给python代码加上类型提示,这样,type annotation就成为实现type hint的主要手段。因此,当今天人们提到type annotation和type hint时,两者基本上是同一含义。

PEP 484是类型检查的奠基石。但是,仍然有一些问题没有得到解决,比如如何对变量进行类型注解?比如下面的语法在当时还是不支持的:

class Node:
        left: str

2016年8月,PEP 526(syntax for variable annotations)提出,从此,像上文中的注解也是允许的了。

在这里插入图片描述

PEP 563 (Postponed Evaluation of Annotations) 解决了循环引用的问题。在这个提案之后,我们可以这样写代码:

from typing import Optional

class Node:
    #left: Optional[Node]  # 这会引起循环引用
    left:   Optional["Node"]
    right:  Optional["Node"]

注意到我们在类型Node还没有完成其定义时,就要使用它(即要使用Node来定义自己的一个成员变量的类型),这将引起循环引用。PEP 563的语法,通过在注释中使用字符串,而不是类型本身,解决了这个问题。

在这几个重要的PEP之后,随着Python 3.7的正式发布,社区也开始围绕Type Hint去构建一套生态体系,一些非常流行的python库开始补齐类型注解,在类型检查工具方面,除了最早的mypy之外,一些大公司也跟进开发,比如微软推出了pyright(现在是pylance的核心)来给vscode提供类型检查功能。google推出了pytype,facebook则推出了pyre。在类型注解的基础上,代码自动完成的功能也因此变得更容易、准确,推断速度也更快了。代码重构也因此变得更加容易。

类型检查功能将对Python的未来发展起到深远的影响,可能足够与typescript对js的影响类比。围绕类型检查,除了上面提到的几个最重要的PEP之外,还有:

  1. PEP 483(解释了python中类型系统的设计原理,非常值得一读)
  2. PEP 544 (定义了对结构类型系统的支持)
  3. PEP 591 (提出了final限定符)
    以及PEP 561等另外18个PEP。此外,还有PEP 692等5个PEP目前还未被正式接受。

Python的类型检查可能最早由Jukka Lehtosalo推动,Guido,Łukasz Langa和Ivan Levkivskyi也是最重要的几个贡献者之一。Jukka Lehtosalo出生和成长于芬兰,当他在剑桥大学计算机攻读博士时,在他的博士论文中,他提出了一种名为“类型注解”(Type Annotations)的语法,从而一统静态语言和动态语言。最初的实验是在一种名为Alore的语言上实现的,然后移植到Python上,开发了mypy的最初几个版本。不过很快,他的工作重心就完全转移到Python上面来,毕竟,Python庞大的用户群和开源库才能提供丰富的案例以供实践。

2013年,在圣克拉拉举行的PyCon会议上,他公布了这个项目,并且得到了与Guido交谈的机会。Guido说服他放弃之前的自定义语法,完全遵循Python 3的语法,即PEP 3107提出的函数注解)。在随后他与Guido进行了大量的邮件讨论,并提出了通过注释来对变量进行注解的方案(不过后来的PEP 526提出了更好的方案)。

在Jukka Lehtosalo从剑桥毕业后,受Guido邀请,加入了Dropbox,领导了mypy的开发工作。

这里也可以看出顶尖大学对待学术研究上的开放和不拘一格。大概在2016年前后,我看到斯坦福的网络公开课上还有讲授ios编程的课,当时也是同样的震撼。一是感叹他们选课之新,二是感叹这种应用型的课程,在国内的顶尖大学里,一般是不会开设的,因为大家会觉得顶尖的学术殿堂,不应该有这么“low”的东西。

在有了类型注解之后,现在我们应该这样定义一个函数:

def foo(name: str) -> int:
    score = 20
    return score

foo(10)

foo函数要求传入字符串,但我们在调用时,错误地传入了一个整数。这在运行时并不会出错,但pylance将会发现这个错误,并且给出警告,当我们把鼠标移动到出错位置,就会出现如下提示:

下面,我们简要地介绍一下type hint的一些常见用法:

# 声明变量的类型
age: int = 1

# 声明变量类型时,并非一定要初始化它
child: bool

# 如果一个变量可以是任何类型,也最好声明它为Any。zen of python: explicit is better than implicit
dummy: Any = 1
dummy = "hello"

# 如果一个变量可以是多种类型,可以使用Union
dx: Union[int, str]
# 从python 3.10起,也可以使用下面的语法
dx: int | str

# 如果一个变量可以为None,可以使用Optional
dy: Optional[int]

# 对python builtin类型,可以直接使用类型的名字,比如int, float, bool, str, bytes等。
x: int = 1
y: float = 1.0
z: bytes = b"test"

# 对collections类型,如果是python 3.9以上类型,仍然直接使用其名字:
h: list[int] = [1]
i: dict[str, int] = {"a": 1}
j: tuple[int, str] = (1, "a")
k: set[int] = {1}

# 注意上面的list[], dict[]这样的表达方式。如果我们使用list(),则这将变成一个函数调用,而不是类型声明。

# 但如果是python 3.8及以下版本,需要使用typing模块中的类型:
from typing import List, Set, Dict, Tuple
h: List[int] = [1]
i: Dict[str, int] = {"a": 1}
j: Tuple[int, str] = (1, "a")
k: Set[int] = {1}

# 如果你要写一些decorator,或者是公共库的作者,则可能会常用到下面这些类型
from typing import Callable, Generator, Coroutine, Awaitable, AsyncIterable, AsyncIterator

def foo(x:int)->str:
    return str(x)

# Callable语法中,第一个参数为函数的参数类型,因此它是一个列表,第二个参数为函数的返回值类型
f: Callable[[int], str] = foo

def bar() -> Generator[int, None, str]:
    res = yield
    while res:
        res = yield round(res)
    return 'OK'
    
g: Generator[int, None, str] = bar

# 我们也可以将上述函数返回值仅仅声明为Iterator:
def bar() -> Iterator[str]:
    res = yield
    while res:
        res = yield round(res)
    return 'OK'

def op() -> Awaitable[str]:
    if cond:
        return spam(42)
    else:
        return asyncio.Future(...)

h: Awaitable[str] = op()

# 上述针对变量的类型定义,也一样可以用在函数的参数及返回值类型声明上,比如:
def stringify(num: int) -> str:
    return str(num)

# 如果函数没有返回值,请声明为返回None
def show(value: str) -> None:
    print(value)

# 你可以给原有类型起一个别名
Url = str
def retry(url: Url, retry_count: int) ->None:
    pass

此外,type hint还支持一些高级用法,比如TypeVar, Generics, Covariance和contravariance等,这些概念在PEP484中有定义,另外,PEP483和understanding typing可以帮助读者更好地理解类型提示,建议感兴趣的读者深入研读。

如果您的代码都做好了type hint,那么IDE基本上能够提供和强类型语言类似的重构能力。需要强调的是,在重构之前,你应该先进行单元测试、代码lint和format,在没有错误之后,再进行重构。如此一来,如果重构之后,单元测试仍然能够通过,则基本表明重构是成功的。

3. PEP8 - python代码风格指南

PEP8是2001年由Guido等人拟定的关于python代码风格的一份提案。PEP8的目的是为了提高python代码的可读性,使得python代码在不同的开发者之间保持一致的风格。PEP8的内容包括:代码布局,命名规范,代码注释,编码规范等。PEP8的内容非常多,在实践中,我们不需要专门去记忆它的规则,只要用对正确的代码格式化工具,最终呈现的代码就一定是符合PEP8标准的。在后面的小节里,我们会介绍这一工具 – black,因此,我们不打算在此处过多着墨。


本文摘录自《Python能做大项目》(暂定名),全书已送审,将由机械工业出版社出版。全文已发表在大富翁官网,您也可以前往提前阅读。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/277061.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[HUBUCTF 2022 新生赛]checkin

[HUBUCTF 2022 新生赛]checkin wp 进入页面&#xff0c;代码如下&#xff1a; <?php show_source(__FILE__); $username "this_is_secret"; $password "this_is_not_known_to_you"; include("flag.php");//here I changed those two…

基于Java+SpringBoot+vue实现图书借阅管理系统

基于JavaSpringBootvue实现图书借阅和销售商城一体化系统 &#x1f345; 作者主页 程序设计 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; 文章目录 基于JavaSpringBootvue实现图书借阅和销售商城一体化…

TikTok年度回顾:2023年的亮点时刻

2023年&#xff0c;TikTok再次成为全球关注的焦点&#xff0c;不仅延续了其独特的社交媒体魅力&#xff0c;还在创新、文化影响力等方面取得了一系列令人瞩目的亮点时刻。本文将深入探讨TikTok在2023年的重要事件、创新举措以及对社会的深远影响。 创新功能引领社交潮流 TikTok…

python使用xpath解析html

一、安装包 pip install lxml二、读取 1、读取解析出来多条 from lxml import etree# HTML 或 XML 文档示例 html_content <html><body><div><p>Paragraph 1</p><a href"#">Link 1</a></div><div><p&…

2023-12-29 服务器开发-Centos部署LNMP环境

摘要: 2023-12-29 服务器开发-Centos部署LNMP环境 centos7.2搭建LNMP具体步骤 1.配置防火墙 CentOS 7.0以上的系统默认使用的是firewall作为防火墙&#xff0c; 关闭firewall&#xff1a; systemctl stop firewalld.service #停止firewall systemctl disable fire…

python读取eps矢量图片

再利用Image读取时&#xff0c;提示报错&#xff1a; OSError: Unable to locate Ghostscript on paths 解决办法&#xff1a; 首先要安裝ghostscript软件&#xff1a;Ghostscript : Downloads 安装后记住安装路径&#xff0c;并找到bin的文件夹 之后在使用时&#xff0c;在代…

linux SHELL语句

shell编程 shell编程 一、初识shell 程序 语言 编程语言 自然语言 汉语 英语 计算机语言 c语言cjava php python go shell 编译型语言 c c java解释型语言 php python bash (不能闭源&#xff0c;开发难度低) 编译型语言:运行编译型语言是相对于解释型语言存在的&#xff…

TVS 管选型与 ESD 防护设计

文章目录 ESD 防护设计 TVS管的基础特性 TVS管的选型方法 TVS管布局细节 参考文献 ESD 防护设计 静电防护设计是让电路板外接的各类金属按钮开关在接触到外界空气放电或接触放电时&#xff0c;在这种瞬间出现的大能量注入到电路板后&#xff0c;能够通过某种设计好的通道泄…

Springboot整合Elastic-job

一 概述 Elastic-Job 最开始只有一个 elastic-job-core 的项目&#xff0c;定位轻量级、无中心化&#xff0c;最核心的服务就是支持弹性扩容和数据分片&#xff01;从 2.X 版本以后&#xff0c;主要分为 Elastic-Job-Lite 和 Elastic-Job-Cloud 两个子项目。esjbo官网地址 Ela…

【满分】【华为OD机试真题2023CD卷 JAVAJS】API集群负载统计

华为OD2023(C&D卷)机试题库全覆盖,刷题指南点这里 API集群负载统计 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 某个产品的RESTful API集合部署在服务器集群的多个节点上,近期对客户端访问日志进行了采集,需要统计各个API的访问频次,根据热点信息在服务…

CRM诞生到现在历经了哪些发展阶段?CRM系统的五个关键节点

CRM管理系统从被发明到现在&#xff0c;历经多次迭代已经成为一个相对成熟的系统。企业可以靠它管理客户信息&#xff0c;提升盈利能力。今天就来介绍一下CRM的发展历程。 一、CRM系统的雏形 广义上的CRM系统其实可以追溯到古希腊时期。当时的商人靠书写记录自己与客户和合作…

亚马逊SEO是什么意思?亚马逊标题的SEO方法是什么?-站斧浏览器

亚马逊SEO是什么意思&#xff1f; 亚马逊SEO主要包括了对标题、描述、五点简介等元素的优化&#xff0c;以及评价和评论的管理等方面。下面将详细分析亚马逊SEO的相关内容&#xff0c;帮助卖家更好地理解和应用。 在亚马逊平台上进行SEO优化需要考虑以下几个方面&#xff1a;…

iPortal内置Elasticsearch启动失败的几种情况——Linux

作者&#xff1a;yx 文章目录 前言一、端口占用二、ES启动过慢三、磁盘占用过高&#xff0c;导致ES变为只读模式 前言 在Linux环境启动iPortal后有时会出现搜索异常的情况&#xff0c;如下截图&#xff0c;这是因为Elasticsearch&#xff08;以下简称“ES”&#xff09;没启动…

elasticsearch安装教程(超详细)

1.1 创建网络&#xff08;单点部署&#xff09; 因为我们还需要部署 kibana 容器&#xff0c;因此需要让 es 和 kibana 容器互联&#xff0c;所有先创建一个网络&#xff1a; docker network create es-net 1.2.加载镜像 采用的版本为 7.12.1 的 elasticsearch&#xff1b;…

日常知识点记录

1、Maven 中的dependencyManagement和dependency的区别 首先maven可以通过子模块依赖父模块的方式获得父模块的所有依赖&#xff0c;极大便利的提供了对项目以来的管理&#xff0c;但是在使用这种方式实现对依赖的管理时&#xff0c;子模块不可避免的会引入父模块中存在&#…

前端性能优化 将资源放到 linux 服务器上 提升访问效率

我们先远端连接服务器 然后服务器终端输入 mkdir 目录路径建出一个新的文件路径 回到我们自己的电脑 然后 在要缓存到服务器的文件目录下打开终端 输入 scp -r ./xidis.hdr 用户名 如果没设置用户名就是root服务器公网IP:/root/xhdr例如 scp -r ./xidis.hdr root1.113.266…

SpringBoot+AOP+Redis 防止重复请求提交

本文项目基于以下教程的代码版本&#xff1a; https://javaxbfs.blog.csdn.net/article/details/135224261 代码仓库: springboot一些案例的整合_1: springboot一些案例的整合 1、实现步骤 2.引入依赖 我们需要redis、aop的依赖。 <dependency><groupId>org.spr…

Docker - 镜像 | 容器 | 数据卷 日常开发常用指令 + 演示(一文通关)

目录 Docker 开发常用指令汇总 辅助命令 docker version docker info docker --help 镜像命令 查看镜像信息 下载镜像 搜索镜像 删除镜像 容器命令 查看运行中的容器 运行容器 停止、启动、重启、暂停、恢复容器 杀死容器 删除容器 查看容器日志 进入容器内部…

记一次修复外网无法访问vmware里面的虚拟机的网络端口的问题

发现一个奇怪的网络问题&#xff0c;vmware里一个程序的端口通过vmnat穿透出来&#xff0c;然后这个端口就能够通过局域网被其他机器访问&#xff0c;但是另一个网段就没法访问这个端口。使用主机上的其他程序使用开启同样的端口&#xff0c;另一个网段的机器却可以访问。我想不…

idea 如何快速拉取新分支

方式1 &#xff08;快捷键&#xff1a;CtrlShift~&#xff09; 方式2:&#xff08;快捷键&#xff1a;Alt9&#xff09;