版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】怎么使用pdb进行Python调试
这篇文章主要介绍“怎么使用pdb进行Python调试”,在日常操作中,相信很多人在怎么使用pdb进行Python调试问题上存在疑惑,在下查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么使用pdb进行Python调试”的疑惑有所帮助!接下来,请跟着在下一起来学习吧!开始案例,我们首先探索pdb最简单的使用:查阅一个变量的值。首先,我们在一个源码文件中某一行,写入下列语句:import
pdb;
pdb.set_trace()当这一行代码被执行后,Python代码文件就会被暂停运行,等待你发布命令来指导它下一步如何操作。运行上面的代码后,你可以在命令行界面看到(Pdb)的提示符,这就意味着,代码被停止了,等待命令的输入。自从Python3.7以来,官方标准建议使用标准库内部函数breakpoint()替代上面的代码(注意:本文附带的代码都使用的上面代码形式),这样可以更加加快解释器的运行和调试:breakpoint()默认情况下,breakpoint()将会倒入pdb模块,然后调用pdb.set_trace()函数,只是它进行了进一步封装。但是,使用breakpoint()可以更加灵活,并且允许用户通过调用它的API来控制调试行为,以及使用环境变量PYTHONBREAKPOINT。例如,当我们设置PYTHONBREAKPOINT=0在我们的环境中,这就会完全关闭breakpoint()的功能,从而关闭调试功能。此外,我们还可以不用手动在源代码文件中加入断点代码,只需要在命令行输入运行指令时通过参数传递来设置,例如:$
python3
-m
pdb
app.py
arg1
arg2那么,让我们直接进入本小节的内容,也就是查阅代码中变量的值,看下面的案例,使用的源码文件是codeExample1.py:#!/usr/bin/env
python3
filename
=
__file__
import
pdb;
pdb.set_trace()
print(f"path={filename}")而在你命令行界面,运行上述的Python代码,你就可以得到下面的输出结果:$
./codeExample1.py
>
/code/codeExample1.py(5)<module>()
->
print(f"path={filename}")
(Pdb)接下来,让我们输入pfilename这个命令,来查看filename这个变量的值,可以看到下述结果:(Pdb) p
filename
"./codeExample1.py"
(Pdb)因为我们使用的是一个命令行接口界面程序(command-lineinterface),那么注意一下输出的字符和格式,解释如下:>开始的第一行告诉我们所运行的源码文件名称,源码名称之后,用小括号包含的是当前代码行数,再后面就是函数名称。这里,因为我们没用调用任何函数,而是处于模块级别,所用见到的是()。->开始的第二行表示目前行数代码对应的具体代码内容。(Pdb)是一个pdb提示符,等待下一个命令的输入。我们可以使用q命令,表示推出调试(quit)。当使用命令p,我们同样可以输入一个表达式,让Python来计算表达式的值。如果传入一个变量名,pdb就会答应当前变量对应的值。但是,我们可以进一步调查我们应用程序当前的运行状态。下面案例中,当函数get_path()被调用,为了查看在这个函数中发生了什么,我已经提前插入断点程序pdb.set_trace(),来阻断程序的运行,源码codeExample2.py内容如下:#!/usr/bin/env
python3
import
os
def
get_path(filename):
"""Return
file"s
path
or
empty
string
if
no
path."""
head,
tail
=
os.path.split(filename)
import
pdb;
pdb.set_trace()
return
head
filename
=
__file__
print(f"path
=
{get_path(filename)}")如果在命令行中运行这个文件,可以得到下面的输出:$
./codeExample2.py
>
/code/example2.py(10)get_path()
->
return
head
(Pdb)那么此时,我们处于什么阶段:>:表示我们在源码文件codeExample2.py的第10行代码处,此处是函数get_path()。如果运行命令p输出的标量,就是当前所引用的代码帧,也就是当前上下文内的标量。->:运行的代码已经被停止在returnhead处,这一行代码还没有被执行,是位于codeExample2.py文件的第10行处,具体是在函数get_path()内。如果想要查看应用当前状态代码上下文情况,可以使用命令ll(longlist),来查看代码内容,具体内容如下:(Pdb)
ll
6
def
get_path(filename):
7
"""Return
file"s
path
or
empty
string
if
no
path."""
8
head,
tail
=
os.path.split(filename)
9
import
pdb;
pdb.set_trace()
10
->
return
head
(Pdb)
p
filename
"./codeExample2.py"
(Pdb)
p
head,
tail
(".",
"codeExample2.py")
(Pdb)
p
"filename:
"
+
filename
"filename:
./codeExample2.py"
(Pdb)
p
get_path
<function
get_path
at
0x100760e18>
(Pdb)
p
getattr(get_path,
"__doc__")
"Return
file"s
path
or
empty
string
if
no
path."
(Pdb)
p
[os.path.split(p)[1]
for
p
in
os.path.sys.path]
["pdb-basics",
"python36.zip",
"python3.6",
"lib-dynload",
"site-packages"]
(Pdb)你可以输入任何有效的Python表达式接在p后面,来进行计算。当你正在调试并希望在运行时直接在应用程序中测试替代实现时,这尤其有用。您还可以使用命令pp(漂亮打印)来美观打印表达式。如果您想打印具有大量输出的变量或表达式,例如列表和字典。如果可以,漂亮打印将对象保留在一行上,如果它们不适合允许的宽度,则将它们分成多行。在这一部分,我们主要是用两个命令来实现代码的调试,如下图所示:命令n(next)和s(step)的区别是,pdb运行停止的位置。使用n(next),pdb会进行执行,直到运行到当前函数或模块的下一行代码,即:如果有外部函数被调用,不会跳转到外部函数代码中,可以把n理解为“stepover”。使用s(step)来执行当前代码,但是如果有外部函数被调用,会跳转到外部函数中,可以理解为“stepinto”,如果执行到外部跳转函数,s命令会输出--Call--。n(next)和s(step)命令都会暂定代码的执行,当运行到当前函数的结束部分,并且打印出--Return--,下面是codeExample3.py文件源码内容:#!/usr/bin/env
python3
import
os
def
get_path(filename):
"""Return
file"s
path
or
empty
string
if
no
path."""
head,
tail
=
os.path.split(filename)
return
head
filename
=
__file__
import
pdb;
pdb.set_trace()
filename_path
=
get_path(filename)
print(f"path
=
{filename_path}")如果在命令行中运行这个文件,同时输入命令n,可以得到下面的输出:$
./codeExample3.py
>
/code/example3.py(14)<module>()
->
filename_path
=
get_path(filename)
(Pdb)
n
>
/code/example3.py(15)<module>()
->
print(f"path
=
{filename_path}")
(Pdb)通过使用命令n(next),我们停止在15行代码,并且我们也只是在此模块中,没有跳转到函数get_path()。此处函数表示为(),表明我们目前是处于模块级别而不是任何函数内部。再让我们尝试使用s(step)命令,输出为:$
./codeExample3.py
>
/code/example3.py(14)<module>()
->
filename_path
=
get_path(filename)
(Pdb)
s
--Call--
>
/code/example3.py(6)get_path()
->
def
get_path(filename):
(Pdb)通过使用s(step)命令,我们停止在函数get_path()内部的第6行代码处,因为这个函数是在代码文件中第14行处被调用的,注意在s命令之后输出了--Call--,表明是函数调用。为了方便,pdb有命令记忆功能,如果我们要调试很多代码,可以输入Enter回车键,来重复执行命令。下面是我们混合使用n(next)和s(step)命令的案例,首先输入s(step),因为我们想要进入函数get_path(),然后通过命令n(next)在局部调试代码,并且使用Enter回车键,避免重复输入命令:$
./codeExample3.py
>
/code/codeExample3.py(14)<module>()
->
filename_path
=
get_path(filename)
(Pdb)
s
--Call--
>
/code/codeExample3.py(6)get_path()
->
def
get_path(filename):
(Pdb)
n
>
/code/codeExample3.py(8)get_path()
->
head,
tail
=
os.path.split(filename)
(Pdb)
>
/code/codeExample3.py(9)get_path()
->
return
head
(Pdb)
--Return--
>
/code/codeExample3.py(9)get_path()->"."
->
return
head
(Pdb)
>
/code/codeExample3.py(15)<module>()
->
print(f"path
=
{filename_path}")
(Pdb)
path
=
.
--Return--
>
/code/codeExample3.py(15)<module>()->None
->
print(f"path
=
{filename_path}")
(Pdb)注意输出的--Call--和--Return--,这是pdb输出的信息,提示我们调试过程的状态信息,n(next)和s(step)命令都会在函数返回后停止,这也就是我们会看到--Return--信息的输出。此外,还要注意->"."在第一个--Return--输出上面的结尾处:--Return--
>
/code/example3.py(9)get_path()->"."
->
return
head
(Pdb)当pdb停止到一个函数的结尾,但是还没有运行到return时,pdb同样会打印return值,在上面例子中就是".".3.1显示代码不要忘记,我们上面提到了命令ll(longlist:显示当前函数或帧的源代码),在我们调试进入到不熟悉的代码上下文中,这个命令非常有效,我们可以打印出整个函数代码,显示样例如下:$
./codeExample3.py
>
/code/codeExample3.py(14)<module>()
->
filename_path
=
get_path(filename)
(Pdb)
s
--Call--
>
/code/codeExample3.py(6)get_path()
->
def
get_path(filename):
(Pdb)
ll
6
->
def
get_path(filename):
7
"""Return
file"s
path
or
empty
string
if
no
path."""
8
head,
tail
=
os.path.split(filename)
9
return
head
(Pdb)如果想要查看简短的代码片段,我们可以使用命令l(list),不需要输入参数,它将会打印11行目前代码附近的代码内容,案例如下:$
./codeExample3.py
>
/code/codeExample3.py(14)<module>()
->
filename_path
=
get_path(filename)
(Pdb)
l
9
return
head
10
11
12
filename
=
__file__
13
import
pdb;
pdb.set_trace()
14
->
filename_path
=
get_path(filename)
15
print(f"path
=
{filename_path}")
[EOF]
(Pdb)
l
[EOF]
(Pdb)
l
.
9
return
head
10
11
12
filename
=
__file__
13
import
pdb;
pdb.set_trace()
14
->
filename_path
=
get_path(filename)
15
print(f"path
=
{filename_path}")
[EOF]
(Pdb)断点的正确使用,在我们调试过程中可以节约大量的时间。不需要单步调试一行行代码,而只用简单地在我们想要查阅的地方设置一个断点,就可以直接运行到断点处进行调试。同样的,我们可以添加条件,来让pdb判断是否需要设置断点。通常使用命令b(break)来设置一个断点,我们可以通过指定代码行数,或者是想要调试的函数名称,语法如下:b(reak)
[
([filename:]lineno
|
function)
[,
condition]
]如果filename:没有在代码行数之前被指定,那么默认就是当前代码文件中。注意第二个可选参数是b:condition,这个功能非常强大。假设在一个场景下,我们想要在某种条件成立的情况下设置断点,如果我们传入一个表达式座位第二个参数,pdb会在计算改表达式为true的情况下设置断点,我们会在下面给出案例。下面案例中,使用了一个工具模块util.py,让我们在函数get_path()中设置一个断点,下面是代码codeExample4.py的内容:#!/usr/bin/env
python3
import
util
filename
=
__file__
import
pdb;
pdb.set_trace()
filename_path
=
util.get_path(filename)
print(f"path
=
{filename_path}")下面是工具模块util.py文件内容:def
get_path(filename):
"""Return
file"s
path
or
empty
string
if
no
path."""
import
os
head,
tail
=
os.path.split(filename)
return
head首先,让我们使用源码文件名称和代码行数来设置断点:$
./example4.py
>
/code/example4.py(7)<module>()
->
filename_path
=
util.get_path(filename)
(Pdb)
b
util:5
Breakpoint
1
at
/code/util.py:5
(Pdb)
c
>
/code/util.py(5)get_path()
->
return
head
(Pdb)
p
filename,
head,
tail
("./example4.py",
".",
"example4.py")
(Pdb)命令c(continue)是实现被断点停止后继续运行的命令,下面,让我们使用函数名来设置断点:$
./codeExample4.py
>
/code/codeExample4.py(7)<module>()
->
filename_path
=
util.get_path(filename)
(Pdb)
b
util.get_path
Breakpoint
1
at
/code/util.py:1
(Pdb)
c
>
/code/util.py(3)get_path()
->
import
os
(Pdb)
p
filename
"./codeExample4.py"
(Pdb)如果输入b,并且不带任何参数,就可以查看到所有已经设置的断点信息:(Pdb)
b
Num
Type
Disp
Enb
Where
1
breakpoint
keep
yes
at
/code/util.py:1
(Pdb)你可以使用命令disablebpnumber和enablebpnumber禁用和重新启用断点。bpnumber是断点列表第一列Num中的断点编号。注意Enb列的值变化:(Pdb)
disable
1
Disabled
breakpoint
1
at
/code/util.py:1
(Pdb)
b
Num
Type
Disp
Enb
Where
1
breakpoint
keep
no
at
/code/util.py:1
(Pdb)
enable
1
Enabled
breakpoint
1
at
/code/util.py:1
(Pdb)
b
Num
Type
Disp
Enb
Where
1
breakpoint
keep
yes
at
/code/util.py:1
(Pdb)为了删除一个断点,可以使用命令cl(clear):cl(ear)
filename:lineno
cl(ear)
[bpnumber
[bpnumber...]]现在,让我们尝试在设置断点时输入表达式参数,在当前案例场景下,get_path()函数如果接受到一个相对路径,即:如果路径名称不是以/开始的,那么就不会设置断点,具体案例如下:$
./codeExample4.py
>
/code/codeExample4.py(7)<module>()
->
filename_path
=
util.get_path(filename)
(Pdb)
b
util.get_path,
not
filename.startswith("/")
Breakpoint
1
at
/code/util.py:1
(Pdb)
c
>
/code/util.py(3)get_path()
->
import
os
(Pdb)
a
filename
=
"./codeExample4.py"
(Pdb)如果创建一个断点后,继续输入c(continue)命令来运行,pdb只会在表达式计算为true的情况下停止运行。命令a(args)会打印出当前函数的传入参数。上述案例中,如果你通过函数名称而不是代码行数来设置断点,注意表达式只会使用当前函数的参数或者全局变量,不然的话,断点就会不去计算表达式,而直接停止函数运行。如果,我们还是想用不是当前的函数变量来计算表达式,也就是使用的变量不在当前函数参数列表中,那么就要指定代码行数,案例如下:$
./codeExample4.py
>
/code/codeExample4.py(7)<module>()
->
filename_path
=
util.get_path(filename)
(Pdb)
b
util:5,
not
head.startswith("/")
Breakpoint
1
at
/code/util.py:5
(Pdb)
c
>
/code/util.py(5)get_path()
->
return
head
(Pdb)
p
head
"."
(Pdb)
a
filename
=
"./codeExample4.py"
(Pdb)5.继续执行代码目前,我们可以使用n(next)和s(step)命令来调试查看代码,然后使用命令b(break)和c(continue)来停止或继续代码的运行,这里还有一个相关的命令:unt(until)。使用unt命令类似于c命令,但是它的运行结果是,下一行比当前代码行数大的位置。有时,unt更加方便和便捷使用,让我们在下面案例中展示,首先给出使用语法:取决于我们是否输入代码行数参数lineno,unt命令可以按照下面两种方式运行:没有lineno,代码可以继续执行到,下一次行数比当前行数大的位置,这就相似于n(next),也就是类似于执行“stepover”的另一种形式。但是,命令n和unt的不同点是,unt只会在下一次行数比当前行数大的位置停止,而n命令会停在下一个逻辑执行行。具有lineno,代码会运行到下一次行数比当前行数大或者相等的位置,这就类似于c(continue)后面带有一个代码函数参数。上面两种情况下,unt命令类似于n(next)和s(step)都只会停止在当前帧(或函数)。当你想继续执行并在当前源文件中更远的地方停止时,请使用unt。你可以将其视为n(next)和b(break)的混合体,具体取决于是否传递行号参数。在下面的示例中,有一个带有循环的函数。在这里,我们希望继续执行代码并在循环后停止,而不是单步执行循环的每次迭代或设置断点,下面是文件codeExample4unt.py文件的内容:#!/usr/bin/env
python3
import
os
def
get_path(fname):
"""Return
file"s
path
or
empty
string
if
no
path."""
import
pdb;
pdb.set_trace()
head,
tail
=
os.path.split(fname)
for
char
in
tail:
pass
#
Check
filename
char
return
head
filename
=
__file__
filename_path
=
get_path(filename)
print(f"path
=
{filename_path}")以及命令下使用unt输出如下:$
./codeExample4unt.py
>
/code/codeExample4unt.py(9)get_path()
->
head,
tail
=
os.path.split(fname)
(Pdb)
ll
6
def
get_path(fname):
7
"""Return
file"s
path
or
empty
string
if
no
path."""
8
import
pdb;
pdb.set_trace()
9
->
head,
tail
=
os.path.split(fname)
10
for
char
in
tail:
11
pass
#
Check
filename
char
12
return
head
(Pdb)
unt
>
/code/codeExample4unt.py(10)get_path()
->
for
char
in
tail:
(Pdb)
>
/code/codeExample4unt.py(11)get_path()
->
pass
#
Check
filename
char
(Pdb)
>
/code/codeExample4unt.py(12)get_path()
->
return
head
(Pdb)
p
char,
tail
("y",
"codeExample4unt.py")ll命令首先用于打印函数的源代码,然后是unt。pdb记得上次输入的命令,所以我只是按Enter重复unt命令。这将继续执行代码,直到到达比当前行大的源代码行。请注意,在上面的控制台输出中,pdb仅在第10行和第11行停止了一次。由于使用了unt,因此仅在循环的第一次迭代中停止执行。但是,循环的每次迭代都被执行。这可以在输出的最后一行进行验证。char变量的值"y"等于tail值"codeExample4unt.py"中的最后一个字符。6.显示表达式类似于打印表达式p和pp的功能,我们可以使用dispaly[expression]来告诉pdb来显示一个表达的值,同样适用undisplay[expression]来清楚一个表达式显示,下面使用一些使用语法解释:下面是一个案例,代码文件为codeExample4display.py,展示了一个循环的使用:$
./codeExample4display.py
>
/code/codeExample4display.py(9)get_path()
->
head,
tail
=
os.path.split(fname)
(Pdb)
ll
6
def
get_path(fname):
7
"""Return
file"s
path
or
empty
string
if
no
path."""
8
import
pdb;
pdb.set_trace()
9
->
head,
tail
=
os.path.split(fname)
10
for
char
in
tail:
11
pass
#
Check
filename
char
12
return
head
(Pdb)
b
11
Breakpoint
1
at
/code/codeExample4display.py:11
(Pdb)
c
>
/code/codeExample4display.py(11)get_path()
->
pass
#
Check
filename
char
(Pdb)
display
char
display
char:
"e"
(Pdb)
c
>
/code/codeExample4display.py(11)get_path()
->
pass
#
Check
filename
char
display
char:
"x"
[old:
"e"]
(Pdb)
>
/code/codeExample4display.py(11)get_path()
->
pass
#
Check
filename
char
display
char:
"a"
[old:
"x"]
(Pdb)
>
/code/codeExample4display.py(11)get_path()
->
pass
#
Check
filename
char
display
char:
"m"
[old:
"a"]在上面的输出中,pdb自动显示了char变量的值,因为每次遇到断点时,它的值都会发生变化。有时这很有帮助并且正是你想要的,但还有另一种使用显示的方法。你可以多次输入display以构建表达式监视列表。这比p更容易使用。添加你感兴趣的所有表达式后,只需输入display即可查看当前值:$
./codeExample4display.py
>
/code/codeExample4display.py(9)get_path()
->
head,
tail
=
os.path.split(fname)
(Pdb)
ll
6
def
get_path(fname):
7
"""Return
file"s
path
or
empty
string
if
no
path."""
8
import
pdb;
pdb.set_trace()
9
->
head,
tail
=
os.path.split(fname)
10
for
char
in
tail:
11
pass
#
Check
filename
char
12
return
head
(Pdb)
b
11
Breakpoint
1
at
/code/codeExample4display.py:11
(Pdb)
c
>
/code/codeExample4display.py(11)get_path()
->
pass
#
Check
filename
char
(Pdb)
display
char
display
char:
"e"
(Pdb)
display
fname
display
fname:
"./codeExample4display.py"
(Pdb)
display
head
display
head:
"."
(Pdb)
display
tail
display
tail:
"codeExample4display.py"
(Pdb)
c
>
/code/codeExample4display.py(11)get_path()
->
pass
#
Check
filename
char
display
char:
"x"
[old:
"e"]
(Pdb)
display
Currently
displaying:
char:
"x"
fname:
"./codeExample4display.py"
head:
"."
tail:
"codeExample4display.py"7.Python调用者ID在最后一节,我们会基于上述学习到的内容,来演示“callID”的功能使用。下面是案例代码codeExample5.py的内容:#!/usr/bin/env
python3
import
fileutil
def
get_file_info(full_fname):
file_path
=
fileutil.get_path(full_fname)
return
file_path
filename
=
__file__
filename_path
=
get_file_info(filename)
print(f"path
=
{filename_path}")以及工具模块fileutil.py文件内容:def
get_path(fname):
"""Return
file"s
path
or
empty
string
if
no
path."""
import
os
import
pdb;
pdb.set_trace()
head,
tail
=
os.path.split(fname)
return
head在这种情况下,假设有一个大型代码库,其中包含一个实用程序模块get_path()中的函数,该函数使用无效输入进行调用。但是,它是从不同包中的许多地方调用的。如何查看调用程序是谁?使用命令w(where)来打印一个代码栈序列,就是从低到上显示所有堆栈:$
./codeExample5.py
>
/code/fileutil.py(5)get_path()
->
head,
tail
=
os.path.split(fname)
(Pdb)
w
/code/codeExample5.py(12)<module>()
->
filename_path
=
get_file_info(filename)
/code/codeExample5.py(7)get_file_info()
->
file_path
=
fileutil.get_path(full_fname)
>
/code/fileutil.py(5)get_path()
->
head,
tail
=
os.path.split(fname)
(Pdb)如果这看起来令人困惑,或者你不确定堆栈跟踪或帧是什么,请不要担心。我将在下面解释这些术语。这并不像听起来那么困难。由于最近的帧在底部,从那里开始并从下往上阅读。查看以->开头的行,但跳过第一个实例,因为pdb.set_trace()用于在函数get_path()中输入pdb。在此示例中,调用函数get_path()的源代码行是:->
file_path
=
fileutil.get_path(full_fname)在每个
->
上面的行包含文件名和代码行数(在括号中),以及函数名称,所以调用者就是:
/code/example5.py(7)get_file_info()
->
file_path
=
fileutil.get_path(full_fname)显然在这个简单的样例中,我们展示了如何查找函数调用者,但是想象一个大型应用程序,您在其中设置了一个带有条件的断点,以确定错误输入值的来源,下面让我们进一步深入。什么是堆栈追踪和栈帧内容?堆栈跟踪只是Python为跟踪函数调用而创建的所有帧的列表。框架是Python在调用函数时创建并在函数返回时删除的数据结构。堆栈只是在任何时间点的帧或函数调用的有序列表。(函数调用)堆栈在应用程序的整个生命周期中随着函数被调用然后返回而增长和缩小。打印时,这个有序的帧列表,即堆栈,称为堆栈跟踪。你可以随时通过输入命令w来查看它,就像我们在上面找到调用者一样。当前栈帧什么意思?将当前帧视为pdb已停止执行的当前函数。换句话说,当前帧是你的应用程序当前暂停的位置,并用作pdb命令(如p(打印))的“参考帧”。p和其他命令将在需要时使用当前帧作为上下文。在p的情况下,当前帧将用于查找和打印变量引用。当pdb打印堆栈跟踪时,箭头>表示当前帧。怎么使用和切换栈帧?你可以使用两个命令u(向上)和
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024-2029年超声波探伤机行业市场现状供需分析及重点企业投资评估规划分析研究报告
- 2024-2029年谷氨酸脱氢酶行业市场现状供需分析及重点企业投资评估规划分析研究报告
- 2024-2029年药品行业行业风险投资发展分析及投资融资策略研究报告
- 2024-2029年茶叶提取物行业市场现状供需分析及重点企业投资评估规划分析研究报告
- 2024-2029年花盆行业市场现状供需分析及市场深度研究发展前景及规划投资研究报告
- 2024-2029年膜脱气器行业市场现状供需分析及市场深度研究发展前景及规划投资研究报告
- 2024-2029年脊髓刺激器(SCS)系统行业市场现状供需分析及重点企业投资评估规划分析研究报告
- 2024-2029年胡椒基丁醚(PBO)(Cas 51-03-6)行业市场现状供需分析及重点企业投资评估规划分析研究报告
- 2024-2029年肝芯片行业市场现状供需分析及重点企业投资评估规划分析研究报告
- 2024-2029年聚氯三氟乙烯行业市场现状供需分析及重点企业投资评估规划分析研究报告
- 北师大版数学八下5.3《分式的加减法(第2课时)》教案
- 盐城市沿海岸线利用和保护专项规划20162030
- JGJ_T441-2019建筑楼盖振动舒适度技术标准
- JGJ_T401-2017锚杆检测与监测技术规程
- 北京市重性精神疾病信息报告管理办法
- 12英寸晶圆55nm工艺后段介绍
- 六年级下册综合实践活动教案
- 邮政客户营销管理系统操作手册客户经理
- 用地分类颜色对照表
- 老干部工作演讲稿:青春在在老干部工作中闪光
- 大学生职业生涯规划表格
评论
0/150
提交评论