百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

后端编程Python3-高级程序设计(过程型程序-上)

off999 2024-10-19 07:15 13 浏览 0 评论

本节是第五讲的第十五小节上,本节主要介绍过程型程序设计技巧(使用字典进行分支、生成器表达式与函数、动态代码执行与动态导入)。

高级程序设计技术(Advanced Programming Techniques)

本章的第1节更深入地讲解了Python的过程型程序设计功能。首先展示了如何以 一种新的方式使用前面已讲过的内容,之后回到前面只是略有提及的生成器主题。 该节之后介绍了动态程序设计——根据运行时名称加载模块,并在运行时执行任意代码。之后回到关于本地(嵌套的)函数的主题,但添加了关键字nonlocal与递归函数的使用。早前,我们学习了如何使用Python的预定义修饰器——这一节中,我们将学习如何创建自己的修饰器。最后,该节以讲述函数注释来结束。

第2节讲述的都是与面向对象程序设计相关的新内容。该节从介绍__slots__开始, 这是一种可以将每个对象使用内存最小化的机制,之后展示了如何在不使用特性的情况下对属性进行存取。该节还介绍了函子(functors)(可以像函数一样调用的对象)以及上下文管理器——这些是与with关键字一起使用的,很多情况下(比如,文件处理)可用于将try ... Except... Finally这种语句结构替换为更简单的try ... except语句结构。该节还展示了如何创建自定义的上下文管理器,并介绍了一些附加的高级面向对象程序设计功能,包括类修饰器、抽象基类、多继承以及元类等内容。

第3节介绍了函数型程序设计的一些基本概念,并介绍了 functools.itertools与 operator等模块中一些有用的函数,此外,该节还展示了如何使用偏序函数应用程序来简化代码。

前面所有章节内容一起构成了 “标准Python工具箱”,本章将吸取前面讲述的所有相关内容,并将其转换为“豪华版Python工具箱”,包括所有原始的工具(技术与语法),以及很多可以使得我们的程序更简洁、更短小、更有效的新内容。有些工具可以交替使用,比如,有些任务可以使用类修饰器完成,也可以使用元类完成,其他一 些技术,比如描述符,可以以多种方式使用来达到不同的效果。这里展示的有些工具,比如上下文管理器,我们将一直使用,其他一些工具则作为备用,在那些使用其更合适的特定场合才实际使用。

过程型程序设计进阶(Further Procedural Programming)

本节大部分篇幅用于介绍与过程型程序设计与函数相关的一些附加工具,但第一小节不同,因为其中将给出一种有用的程序设计技术,这种技术是以我们讲过的内容为基础的,没有使用任何新语法。

使用字典进行分支(Branching Using Dictionaries)

前面已经说过,与Python中任何其他对象一样,函数本身也是对象,函数名就是对函数的对象引用。如果我们写下一个函数名,其后没有使用圆括号,Python就知道我们是将其当作对象引用,我们可以将这样的对象引用进行传递,就像任何其他对象引用一样。根据这一事实,我们可以使用单一的函数调用来对包含大量elif分支的if语句进行替换。

后面将展示一个名为dvds-dbm.py的交互式控制台程序,该程序有如下 一些菜单:

(A)dd (E)dit (L)ist (R)emove (l)mport e(X)port (Q)uit

该程序有一个获取用户选择的函数,该函数将只返回一个有效的选择,这里是“a"、“e”、“1”、“r”、“i"、“x"与“q"中的一个。下面给出的是基于用户的选择来调用相关函数的两个等价的代码段:

用户所做的选择被当作一个单字符的字符串存放在变量action中,要使用的数据库则存放在变量db中,import_()的函数名以下划线结尾,以便区别于内置的import 语句

右面的代码段中,我们创建了一个字典,其键为有效的菜单选项,其值则为函数引用。第2条语句中,我们取回与给定操作对应的函数引用,并使用调用操作符()调用被引用的函数,并且传递参数db。与左边的代码相比,右边的代码不但更短,而且 可以在扩展(有更多的字典项)的同时不影响其性能,左边代码的速度则依赖于必须执行多少条elif分支语句(以便发现合适的函数进行调用)。

if action = "a":

add_dvd(db)

elif action == "e":

edit_dvd(db)

elif action == "I":

list_dvds(db)

elif action ==“r”:

remove_dvd(db)

elif action == "i":

import_(db)

elif action == "x":

export(db)

elif action == "q":

quit(db)

functions=dict(a=add_dvd,b=edit_dvd,c=list_dvds,r=remove_dvd,i=import_,x=export,q=quit)

functions[action](db)

前一章的convert-incidents.py程序在其import_()方法中使用了这种技术,下面是从其中提取的部分代码:

call = {(".aix", "dom"): self.import_xml_dom,

(“.aix", "etree"): self.import_xml_etree,

(".aix", "sax"): self.import_xml_sax,

(”.ait", "manual"): self.import_text_manual,

(".ait", "regex"): self.import_text_regex,

(".aib", None): self.import_binary,

(".aip", None): self.import_pickle}

result = call[extension, reader](filename)

该方法完整的实现代码有13行,参数extension是在该方法内计算得到的,参数 reader则是传入的。字典键为二元组,值为方法。如果使用了if语句,那么代码长度将为22行,并且不具有很好的扩展性。

生成器表达式与函数(Generator Expressions and Functions)

前面,我们介绍了生成器函数与方法。创建生成器表达式也是可能的。在语法上,这与列表内涵几乎是等同的,区别在于,语句包含在圆括号中,而不是方括号中,下面给出其语法格式:

(expression for item in iterable)

(expression for item in iterable if condition}

前面的章节中,我们使用yield表达式创建了一些迭代子方法。下面给出两个等价的代码段,展示如何将一个包含yield表达式的for ... in循环编码为一个生成器:

def items_in_key_order(d):

for key in sorted(d)):

yield key,d[key]

def items_in_key_order(d):

return ((key, d[key])

for key in sorted(d))

两个函数都返回一个生成器,用于为给定的字典生成一个键-值项列表。如果我们需要一次性提供这些项,就可以将函数返回的生成器作为参数传递给list()或tuple(),否则,可以对生成器进行迭代,以便在需要的时候再取回相应项。

生成器提供了一种执行“惰性”评估的方法,这意味着只有在实际需要的时候才计算值,这比一次性计算一个很大的列表要更加高效。有效的生成器可以生成我们所需要数量的值——而没有上限,比如:

def quarters(next_quarter=0.0):

while True:

yield next_quarter

next_quarter += 0.25

这一函数将返回0.0、0.25、0.5...,依此类推,下面的语句则展示了如何使用该生成器:

result =[]

for x in quarters():

result.append(x)

if x>=1.0:

break

break语句是必要的没有该语句,for... in循环将一直不会结束。最后,result列表为[0.0, 0.25, 0.5, 0.75, 1.0] 。每次调用quarters()时,都可以取回一个生成器,该生成器从0.0开始,并以0.25 进行递增。如果需要重置生成器当前值应该怎么做?可能的方法是将一个值传递给生成器,如下面新版本的生成器函数所示:

def quarters(next_quarter=0.0):

while True:

received = (yield next_quarter)

if received is None:

next_quarter += 0.25

else:

next_quarter = received

yield表达式依次向调用者返回每个值,此外,如果调用者调用了生成器的send() 方法,那么发送的值由生成器函数作为yield表达式的结果进行接收。下面展示如何使用新的生成器函数:

result =[]

generator = quarters()

while len(result) < 5:

x = next(generator)

if abs(x - 0.5) < sys.float_info.epsilon:

x = generator.send(1.0)

result.append(x)

我们创建一个变量来引用生成器,并调用内置的next()函数,该函数从给定的生成器中取回下一项。(调用生成器的特殊方法__next__()也可以达到同样的效果,这里也就是x = generator.__next__()。)如果值为0.5,我们就将值1.0发送给生成器(生成器将立即回传这一数值)。这一次,result列表为[0.0,0.25,1.0,1.25,1.5]。

下一小节中,我们将査看magic-numbers.py程序,该程序对命令行中给定的文件进行处理。遗憾的是,Windows shell程序(cmd.exe)没有提供通配符扩展(也称之为 file globbing),因此,如果某程序在Windows下使用参数*.*运行,那么sys.argv列表中收到的是字面意义的“*.*”,而非当前目录下的所有文件。我们通过创建两个不同的get_files()函数来解决这一问题,一个用于Windows,另一个用于UNIX,两者都使用了生成器。下面给出其代码:

if sys. platform.startswith("win"):

def get_files(names):

for name in names:

if os.path.isfile(name):

yield name

else:

for file in glob.iglob(name):

if not os.path.isfile(file):

continue

yield file

else:

def get_files(names):

return (file for file in names if os.path.isfile(file))

两种情况中,对函数的调用都应该使用文件名列表,比如,以sys.argv[1:]作为函数的参数。

在Windows下,该函数对所有列出的名称进行迭代,对每个文件名,该函数提供名称,但对于非文件(通常是目录),则使用glob模块的glob.iglob()函数返回一个迭代子,其迭代的文件名为通配符扩展后的文件名部分。对普通名,比如autoexec.bat, 返回一个生成一项(该名称)的迭代子;对使用通配符的名称,比如*.txt,则返回一个产生所有匹配文件(这里也就是那些带扩展名.txt的文件)的迭代子。(还有一个 glob.glob()函数(glob.glob()函数并没有UNIX bash shell那样强大的功能,因为虽然该函数支持*、?与[]等语法,但是不支持{}语法。),该函数返回的是一个列表,而非一个迭代子。)

在UNIX上,shell会自动进行通配符扩展,因此我们只需要为给定文件名的所有文件返回一个迭代子*。

动态代码执行与动态导入(Dynamic Code Execution and Dynamic Imports)

有一些场合中,编写一段代码,并用其生成我们所需要的代码,会比直接编写所需要的代码更简单。有些情况下,让用户自己输入代码(比如,电子表格中的函数)并让 Python执行输入的代码(而不是写一个分析器自己处理)是有用的——尽管以这种方式执行任意代码必然会存在潜在的安全风险。另一种需要动态代码执行的应用场景是提供插件以便扩展程序的功能。使用插件存在的不足是,不是所有必要的功能都内置在程序中(这使得程序的部署更加困难,并且插件也可能会丢失或失效);优势在于插件可以单独更新,也可以分开提供,并有可能提供一些原本没有重视的功能增强。

动态代码执行(Dynamic Code Execution)

要执行表达式,最简单的方法是使用内置的eval()函数,比如:

x = eval("(2 **31)-1") # x == 2147483647

对用户输入的表达式而言,这种做法是可以的,但是如果我们需要动态创建一个函数时会怎样呢?对这种情况,我们可以使用内置的exec()函数。比如,用户可以给出一个公式4πr2,以及名称"area of sphere",并要求将其转换为一个函数,假定我们可以用math.pi替代兀,则需要创建的函数类似于如下格式:

import math

code =""

def area_of_sphere(r):

return 4 * math.pi * r ** 2

'''

context = {}

context ["math"] = math

exec(code, context)

我们必须使用正确的缩排——毕竟引用的代码是标准的Python代码。(尽管在这种情况下,我们可以将其写在一行内,因为suite本身就只有一行。)

如果调用exec()时仅以某些代码作为其唯一的参数,那么没有途径可以存取该代码执行后创建的任何函数或变量,而且,exec()不能存取任意导入的模块,也不能存取调用时在范围内的任何变量、函数或其他对象。这两个问题都可以通过传递一个字典作为第2个参数来解决,字典提供了存放对象引用的场所,使得其在exec()调用结束后仍然可以存取。比如,使用context字典意味着,在exec()调用后,该字典中存放一 个对areas_of_sphere()函数(由exec()函数创建)的对象引用。在这一实例中,我们需要exec()可以存取math模块,因此,我们向context字典中插入一个项,其键为模块名,其值则为到相应模块对象的对象引用,通过这种做法,可以确保在exec()调用内部,math.pi是可存取的。

有些情况下,将整个的全局上下文提供给exec()会带来很多方便,这可以通过将 globals()函数返回的字典作为参数传递来实现。这种方法的一个不足是,exec()调用中创建的任何对象将被添加到全局字典中。为此,一种解决方案是将全局上下文复制到 —个字典中,比如context = globals().copy(),这种做法可以使得exec()仍然具备对范围内导入的模块、变量以及其他对象的存取权限,并且由于己经先行复制,因此,exec() 调用内部对上下文的所有改变将被保存到context字典中,而不会传播到全局环境。(使用copy.deepcopy()会更安全,但是如果安全性是重要衡量因素,最好完全不要使用 exec()。)我们也可以传递本地上下文,比如,将locals()作为第三个参数——这使得由 exec()执行的代码也可以访问本地范围内的对象。

执行exec()调用后,context字典中将包含一个名为“area_of_ sphere的键,其值 为area_of_sphere()函数,下面展示了如何访问与调用该函数:

area_of_sphere = context["area_of_sphere"]

area = area_of_sphere(5) # area == 314.15926535897933

area_of_sphere对象是对我们动态创建的函数的对象引用,可以像任何其他函数一样使用。并且,我们只在exec()调用中创建了一个函数,但是与eval()只能操作单一表达式不同,exec()可以处理我们需要处理的那么多Python语句,包括整个模块。

动态导入模块(Dynamically Importing Modules)

Python提供了 3种可用于创建插件的直接机制,这3种机制都涉及在运行时根据名称导入模块。动态导入了附加的模块之后,可以使用Python的内省(introspection)函数来检测我们所需要的函数是否存在,并在需要的时候对其进行访问。

在这里,我们将査看magic-numbers.py程序。该程序读入命令行中每个给定文件的头1000个字节,并对每个文件输出其文件类型(或文本“Unknown”)与文件名。 下面给出该程序在命令行中运行的实例及其部分输出信息:

C:\Python30\python.exe magic-numbers.py c:\windows\*.*

...

XML c:\windows\WindowsShell.Manifest

Unknown c:\windows\WindowsUpdate.log

Windows Executable..c:\windows\winhelp.exe

Windows Executable..c:\windows\winhlp32.exe

Windows BMP Image...c:\windows\winnt.bmp

该程序尝试载入程序所在目录中那些名称中包含文本“magic”的模块,这些模块被期待提供一个单一的公共函数,即get_file_type()。本书的实例中,提供了两个非常简单的实例模块,StandardMagicNumbers.py 与 WindowsMagicNumbers.py,每个模块都有一个 get_file_type()函数。

我们将分两部分来查看该程序的main()函数。

def main():

modules = load_modules()

get_fiIe_type_functions =[]

for module in modules:

get_file_type = get_function(module,“get_file_type”)

if get_file_type is not None:

get_file_type_functions.append(get_file_type)

很快,我们将看到load_modules()函数的3种不同实现,该函数将返回一个(可能为空)模块对象列表,我们还将进一步査看get_function()函数。对发现的每个模块,我们尝试取回一个get_file_type()函数,并将取回的内容添加到类似函数组成的列表中。这一循环对命令行中列出的每个文件进行迭代,对每个文件,读入其前1000个字节,之后,依次尝试每个get_file_type()函数,试探其是否可以确定当前文件的类型。 如果可以确定,就打印其详细资料,并跳出内部循环,继续处理下一个文件。如果没有哪个函数可以确定文件的类型,或者没有发现get_file_type()函数,就打印一个“Unknown” 行。

for file in get_files(sys.argv[1:]):

fh = None

try:

fh = open(file, ”rb")

magic = fh.read(1000)

for get_file_type in get_fiIe_type_functions:

filetype = get_file_type(magic,os.path.splitext(file)[1])

if filetype is not None:

print("n{0:.<20}{1}".format(filetype, file))

break

else:

print("{0:.<20}{1}".format("Unknown", file))

except EnvironmentError as err:

print(err)

finally:

if fh is not None:

fh.close()

我们将查看3种(等价的)动态导入模块的方法,从最长的也是最难的方法开始, 因为该方法显式地展示了每一个步骤:

我们首先对程序目录内所有文件进行迭代,如果是当前目录,那么os.path.dirname (__file__)将返回一个空字符串,并可能导致os.listdir()产生异常,因此,必要的时候我们传递一个对每个备选文件(以.py为扩展名,并且名称中包含文本“magic"), 我们剥离扩展名并获取模块名。如果模块名是一个有效的标识符,那么说明是一个可用的模块名;如果该名称尚未存在于sys.modules字典维护的全局模块列表中,那么可以尝试对其进行导入。

我们将文件的文本内容读入到code字符串中。接下来的一行(module = type(sys)(name)) 是非常微妙的。调用type()时,将返回作为参数给定的对象的类型对象,因此,如果调用 type(1),就返回整数。如果打印类型对象,那么只是获取可读的内容,比如“int",但如果将类型对象作为函数进行调用,就返回一个该类型的对象。比如,要获取存储于变量x中的整数 5,可以使用如下语句:x = 5,或x = int(5),或 x = type(0)(5),或 int_type = type(0);x =int_type(5)。在本程序中,我们使用的是type(sys),这里sys是一个模块,因此可以获取模块类型对象(实质上与类对象一样),并可以用其创建一个新模块(使用给定名称)。就像在int实例中获取int类型对象时不需要关心使用的具体整数一样,这里使用哪个模块(只要是一个已经导入的模块)对获取模块类型对象也无关紧要。

def load_modules():

modules =[]

for name in os.listdir(os.path.dirname(__file__) or "."):

if name.endswith(".py") and "magic" in name.lower():

filename = name

name = os.path.splitext(name)[0]

if name.isidentifier() and name not in sys.modules:

fh = None

try:

fh = open(filename, "r", encoding="utf8")

code = fh.read()

module = type(sys)(name)

sys.modules[name] = module

exec(code, module.__dict__)

modules.append(module)

except (EnvironmentError, SyntaxError) as err:

sys.modules.pop(name, None)

print(err)

finally:

if fh is not None:

fh.close()

return modules

在具备了一个新(空)模块之后,我们将其添加到模块的全局列表中,以便防止模块无意间被再次导入。这是在exec()调用之前完成的,以便更紧密地模拟import语句。之后调用exec()来执行已经读取的代码——我们使用模块的字典作为代码的上下文。最后,我们将模块添加到将要传回的模块列表中。如果中间有问题产生,我们将从全局模块字典中删除相应模块(如果该模块已添加到其中)——在有错误发生时, 模块将不会添加到模块列表中。注意,exec()可以处理任意数量的代码(eval()只能对单一的表达式进行评估——参见表8-1),如果有语法错误,那么该函数会产生Syntax Error异常。

语法 内省函数描述

__import__(...) 根据模块名导入模块,参见正文

compile(source, file, mode) 返回编译source文本生成的代码对象,这里,file应该是文件名,或“<string>",mode 必须为 “single"、“eval"或 “exec”

delattr(obj, name) 从对象obj中删除名为name的属性

dir(obj) 返回本地范围内的名称列表,或者,如果已给定obj,就返回obj的名称(比如,其属性与方法)

eval(source, globals, locals) 返回对source中单一表达式进行评估的结果,如果提供,那么globals表示的是全局上下文,locals表示的是本地上下文(作为字典)

exec(obj, globals, locals) 对对象obj进行评估,该对象可以是一个字符串,也可以是来自compile()的代码对象,返回则为None;如果提供,那么globals表示的是全局上下文,locals表示的是本地上下文

getattr(obj, name, val) 返回对象obj中名为name的属性值,如果没有这一属性,并且给定了 val参数,就返回 val

globals() 返回当前全局上下文的字典

hasattr(obj, name) 如果对象obj中有名为name的属性,就返回True

locals() 返回当前本地上下文的字典

setattr(obj, name, val) 将对象obj中名为name的属性值设置为val,必要的时候创建该属性

type(obj) 返回对象Obj的类型对象

vars(obj) 以字典形式返回对象obj的上下文,如果没有给定obj,就返回本地上下文

下面给出运行时动态加载模块的第二种方法——这里展示的代码替换了第一种方法中的try ... except语句块:

try:

exec("import" + name)

modules.append(sys.modules[name])

except SyntaxError as err:

print(err)

这种方法存在的一个理论上的问题是具有潜在的不安全性,name变量可以以sys 开始,并跟随一些破坏性的代码。

下面给出的是第三种方法,展示的也只是用于替换第一种方法中的try ... except 语句块的那部分代码:

try:

module =__import__(name)

modules.append(module)

except (ImportError, SyntaxError) as err:

print(err)

这是动态导入模块的最简单方法,也比使用exec()要安全一些——尽管从本质上说,与任何其他动态导入方法一样,这种方法也绝对算不上安全,因为我们并不知道导入模块时到底执行什么。这里展示的几种技术都不能对不同路径中的包与模块进行处理,但对上面相应代 码进行扩展使其具备这一功能并不难——如果需要更复杂的功能,阅读在线文档会有帮助,尤其是__import__()相关的部分。

def get_function(module, function_name):

function = get_function.cache.get((module, function_name), None)

if function is None:

try:

function = getattr(module, function_name)

if not hasattr(function, "__call__"):

raise AttributeError()

get_function.cache[module, function_name] = function

except AttributeError:

function = None

return function

get_function.cache = {}

暂时先不管cache相关的代码,我们可以看到,该函数所做的就是对模块对象调用getattr(),并使用我们所需要的函数的名称作为参数之一。如果不存在某一属性,就产生AttributeError异常;如果存在某一属性,就使用hasattr()检查该属性本身是否具有__call__属性——这是所有可调用对象(函数与方法)都具备的。(后面我们将看到 一种用于检测某个属性是否可调用的更好方法。)如果某属性存在并且是可调用的,那么可以将其返回给调用者,如果某个函数不可用,则返回None。

如果需要处理的文件有数百个(比如,在C:\windows目录中使用了*.*进行匹配), 我们不希望每个模块对每个文件都进行全面的仔细检査,因此,在定义了get_function() 函数之后,我们将一个属性添加到该函数中,这里添加的是一个名为cache的字典(一 般来说,Python允许我们向任意对象中添加任意属性)。第一次调用get_function()时, cache字典为空,因此dict.get()调用将返回None,但是每次在发现了适当的函数后, 都将会以二元组的形式将该函数放置在字典中,元组的一项是模块与函数名(作为字典的键),另一项是函数本身(作为字典的值)。因此,在第二次(以及所有后续的时候)请求某个函数时,该函数会立即从cache字典中返回,而不需要进行任何属性查询操作。

用于缓存get_function()的返回值(针对一组给定的参数)的技术称为内存化。这一技术可用于任何没有副作用(不改变任何全局变量)的函数,并要求这些函数对同样的(固定的)参数返回同样的结果。对每个内存化的函数,用于创建与管理其缓存的代码是相同的,因此,函数修饰器是一个理想的候选。然而,模块对象是可变的,因此,有些现成的内存化修饰器不能像其宣称的那样用于我们的get_function()函数。为此,一个简单的解决方法是使用每个模块的__name__字符串(而非模块本身)作为元组中键的第一部分。

动态导入模块是简单的,使用exec()函数执行任意Python代码也是简单的。这种机制非常便利,比如,允许我们将代码存储于数据库中。然而,我们无法控制导入模块的行为,也无法控制exec()执行的代码的具体目的。回想一下,除变量、函数与类之外,模块本身也可能包含在导入时执行的代码——如果代码来自不可信源,就可能会进行一些危险的操作。如何解决这一问题依赖于具体环境,当然,在某些环境下或用于个人用途时,这一问题可能根本就不算问题。

以上内容部分摘自视频课程05后端编程Python16高级程序设计(过程型程序-上),更多实操示例请参照视频讲解。跟着张员外讲编程,学习更轻松,不花钱还能学习真本领。

相关推荐

每天一个 Python 库:datetime 模块全攻略,时间操作太丝滑!

在日常开发中,时间处理是绕不开的一块,比如:生成时间戳比较两个时间差转换为可读格式接口传参/前端展示/日志记录今天我们就用一个案例+代码+思维导图,带你完全搞定datetime模块的用法!...

字节跳动!2023全套Python入门笔记合集

学完python出来,已经工作3年啦,最近有很多小伙伴问我,学习python有什么用其实能做的有很多可以提高工作效率增强逻辑思维还能做爬虫网站数据分析等等!!最近也是整理了很多适合零基...

为什么你觉得Matplotlib用起来困难?因为你还没看过这个思维导图

前言Matplotlib是一个流行的Python库,可以很容易地用于创建数据可视化。然而,设置数据、参数、图形和绘图在每次执行新项目时都可能变得非常混乱和繁琐。而且由于应用不同,我们不知道选择哪一个图...

Python新手必看!30分钟搞懂break/continue(附5个实战案例)

一、跳转语句的使命当程序需要提前结束循环或跳过特定迭代时,break和continue就是你的代码急刹按钮和跳步指令。就像在迷宫探险中:break=发现出口立即离开continue=跳过陷阱继续前进二...

刘心向学(24)Python中的数据类(python中5种简单的数据类型)

分享兴趣,传播快乐,增长见闻,留下美好!亲爱的您,这里是LearningYard新学苑。今天小编为大家带来文章“刘心向学(24)Python中的数据类”欢迎您的访问。Shareinterest,...

刘心向学(25)Python中的虚拟环境(python虚拟环境安装和配置)

分享兴趣,传播快乐,增长见闻,留下美好!亲爱的您,这里是LearningYard新学苑。今天小编为大家带来文章“刘心向学(25)Python中的虚拟环境”欢迎您的访问。Shareinte...

栋察宇宙(八):Python 中的 wordcloud 库学习介绍

分享乐趣,传播快乐,增长见识,留下美好。亲爱的您,这里是LearingYard学苑!今天小编为大家带来“Python中的wordcloud库学习介绍”欢迎您的访问!Sharethefun,...

AI在用|ChatGPT、Claude 3助攻,1分钟GET高颜值思维导图

机器之能报道编辑:Cardinal以大模型、AIGC为代表的人工智能浪潮已经在悄然改变着我们生活及工作方式,但绝大部分人依然不知道该如何使用。因此,我们推出了「AI在用」专栏,通过直观、有趣且简洁的人...

使用DeepSeek + Python开发AI思维导图应用,非常强!

最近基于Deepseek+PythonWeb技术开发了一个AI对话自动生成思维导图的应用,用来展示下如何基于低门槛的Python相关技术栈,高效结合deepseek实现从应用场景到实际应用的快速落地...

10幅思维导图告诉你 - Python 核心知识体系

首先,按顺序依次展示了以下内容的一系列思维导图:基础知识,数据类型(数字,字符串,列表,元组,字典,集合),条件&循环,文件对象,错误&异常,函数,模块,面向对象编程;接着,结合这些思维导图主要参考的...

Python基础核心思维导图,让你轻松入门

Python基础核心思维导图【高清图文末获取】学习路线图就给大家看到这里了,需要的小伙伴下方获取获取方式看下方图片...

Python基础核心思维导图,学会事半功倍

Python基础核心思维导图【高清图文末获取】学习路线图就给大家看到这里了,需要的小伙伴下方获取获取方式看下方图片...

硬核!288页Python核心知识笔记(附思维导图,建议收藏)

今天就给大家分享一份288页Python核心知识笔记,相较于部分朋友乱糟糟的笔记,这份笔记更够系统地总结相关知识,巩固Python知识体系。文末获取完整版PDF该笔记学习思维导图:目录内容展示【领取方...

Python学习知识思维导图(高效学习)

Python学习知识思维导图python基础知识python数据类型条件循环列表元组字典集合字符串序列函数面向对象编程模块错误异常文件对象#python##python自学##编程#...

别找了!288页Python核心知识笔记(附思维导图,建议收藏)

今天就给大家分享一份288页Python核心知识笔记,相较于部分朋友乱糟糟的笔记,这份笔记更够系统地总结相关知识,巩固Python知识体系。文末获取完整版PDF该笔记学习思维导图:目录内容展示【领取方...

取消回复欢迎 发表评论: