使用‘导入模块’还是‘从模块导入’?

2024-11-22 08:47:00
admin
原创
162
摘要:问题描述:我试图找到一个全面的指南,以确定是否最好使用import module或from module import。我刚刚开始使用 Python,并试图从最佳实践开始。基本上,我希望有人可以分享他们的经验,其他开发人员有什么偏好,以及避免将来出现任何问题的最佳方法是什么?解决方案 1:import mod...

问题描述:

我试图找到一个全面的指南,以确定是否最好使用import modulefrom module import。我刚刚开始使用 Python,并试图从最佳实践开始。

基本上,我希望有人可以分享他们的经验,其他开发人员有什么偏好,以及避免将来出现任何问题的最佳方法是什么?


解决方案 1:

import module和之间的区别from module import foo主要是主观的。选择你最喜欢的那个,并坚持使用它。以下几点可以帮助你做出决定。

import module

  • 优点:

    • 减少语句维护import。无需添加任何额外导入即可开始使用模块中的另一个项目

  • 缺点:

    • 输入module.foo代码可能很繁琐和多余(可以使用import module as mo然后输入来最大限度地减少繁琐mo.foo

from module import foo

  • 优点:

    • 减少输入foo

    • 更好地控制可以访问模块的哪些项目

  • 缺点:

    • 要使用模块中的新项目,您必须更新您的import声明

    • 你失去了关于 的背景。例如,与 相比 的含义foo不太清楚ceil()`math.ceil()`

两种方法都可以接受,但不要使用from module import *

对于任何相当大一组代码,如果您import *将其固定到模块中,则无法将其移除。这是因为很难确定代码中使用的哪些项目来自“模块”,这很容易让您认为不再使用它们,import但很难确定。

解决方案 2:

这里还有一个细节没有提到,与写入模块有关。虽然这可能不是很常见,但我有时需要它。

由于 Python 中引用和名称绑定的工作方式,如果您想从模块外部更新模块中的某个符号(例如 foo.bar),并让其他导入代码“看到”该更改,则必须以某种方式导入 foo。例如:

模块 foo:

bar = "apples"

模块一:

import foo
foo.bar = "oranges"   # update bar inside foo module object

模块b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

但是,如果导入符号名而不是模块名,则此方法无效。

例如,如果我在模块 a 中执行以下操作:

from foo import bar
bar = "oranges"

任何外部的代码都不a会将其视为bar“橙子”,因为我的设置bar仅仅影响了模块内部的名称“bar” a,它并没有“深入”foo模块对象并更新其bar

解决方案 3:

尽管很多人已经解释了importvs import from,但我想尝试更多地解释一下内部发生的事情,以及所有发生变化的地方在哪里。


import foo

导入foo,并在当前命名空间中创建对该模块的引用。然后您需要定义完整的模块路径,以便从模块内部访问特定属性或方法。

例如foo.bar但不是bar

from foo import bar

导入foo并创建对所列所有成员的引用(bar)。不设置变量foo

例如bar但不是bazfoo.baz

from foo import *

导入foo,并创建对当前命名空间中该模块定义的所有公共对象的引用(__all__如果__all__存在,则引用 中列出的所有内容,否则引用不以 开头的所有内容_)。不设置变量foo

例如barbaz但不是_quxfoo._qux


现在让我们看看什么时候做import X.Y

>>> import sys
>>> import os.path

检查sys.modules姓名osos.path

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

globals()使用和检查命名空间locals()字典osos.path

>>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>

从上面的例子中我们发现只有os被插入到本地和全局命名空间中。因此,我们应该能够使用:

>>> os
<module 'os' from
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> os.path
<module 'posixpath' from
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

但事实并非如此path

>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

一旦从 locals() 命名空间中删除os,您将无法访问os,即使os.path它们存在于 sys.modules 中:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

现在我们来讨论一下import from

from

>>> import sys
>>> from os import path

sys.modules使用os和进行检查os.path

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

我们发现,sys.modules通过使用import name

locals()好的,让我们检查一下它在命名空间字典中是什么样子的globals()

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

您可以使用名称path而不是通过以下方式访问os.path

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

让我们从中删除“路径” locals()

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

最后一个例子是使用别名:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

并且没有定义路径:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>

解决方案 4:

支持这两种方式的原因在于:有时候一种方式比另一种方式更合适。

  • import module:当您使用模块中的许多位时,这很好。缺点是您需要用模块名称限定每个引用。

  • from module import ...:导入的项目可以直接使用,无需模块名称前缀,这一点很好。缺点是您必须列出您使用的每个东西,而且代码中不清楚某些东西来自哪里。

使用哪种方法取决于哪种方法可以让代码更清晰、更易读,这在很大程度上取决于个人喜好。我倾向于使用import module“一般”方法,因为在代码中,对象或函数的来源非常清晰。当我在代码中大量from module import ...使用某个对象/函数时,我会使用它。

解决方案 5:

我个人总是使用

from package.subpackage.subsubpackage import module

然后访问所有内容

module.function
module.modulevar

等等。原因是,同时您有简短的调用,并且您清楚地定义了每个例程的模块命名空间,如果您必须在源中搜索给定模块的使用情况,那么这非常有用。

不用说,不要使用 import *,因为它会污染你的命名空间,并且它不会告诉你给定函数来自哪里(来自哪个模块)

当然,如果两个不同的包中的两个不同的模块有相同的模块名,那么你可能会遇到麻烦,例如

from package1.subpackage import module
from package2.subpackage import module

在这种情况下,你当然会遇到麻烦,但随后就有强烈的暗示表明你的包装布局存在缺陷,你必须重新考虑。

解决方案 6:

import module

当您需要使用模块中的多项功能时,这是最好的选择。

from module import function

当您只需要时,最好避免使用模块中的所有函数和类型来污染全局命名空间function

解决方案 7:

我刚刚发现这两种方法之间还有一个细微的差别。

如果模块foo使用以下导入:

from itertools import count

然后模块bar可能会被错误地使用,count就好像它是在 中定义的foo,而不是在 中定义的itertools

import foo
foo.count()

如果foo使用:

import itertools

错误仍然可能发生,但发生的可能性较小。bar需要:

import foo
foo.itertools.count()

这给我带来了一些麻烦。我有一个模块错误地从一个没有定义该异常的模块中导入了一个异常,而只是从其他模块(使用from module import SomeException)导入了它。当不再需要导入并将其删除时,有问题的模块就坏了。

解决方案 8:

这里还有另一个未提及的区别。这是从http://docs.python.org/2/tutorial/modules.html逐字复制的。

使用时请注意

from package import item

该项目可以是包的子模块(或子包),也可以是包中定义的其他名称,如函数、类或变量。 import 语句首先测试该项目是否在包中定义;如果没有,则假定它是一个模块并尝试加载它。如果找不到它,则会引发 ImportError 异常。

相反,当使用如下语法时

import item.subitem.subsubitem

除最后一项之外的每一项都必须是一个包;最后一项可以是模块或包,但不能是前一项中定义的类或函数或变量。

解决方案 9:

由于我也是一名初学者,我将尝试用一种简单的方式来解释这一点:在 Python 中,我们有三种类型的import语句:

1. 仿制药进口:

import math

这种导入类型是我个人最喜欢的,这种导入技术的唯一缺点是,如果您需要使用任何模块的功能,则必须使用以下语法:

math.sqrt(4)

当然,它增加了打字的工作量,但作为初学者,它将帮助您跟踪与其相关的模块和功能(一个好的文本编辑器将大大减少打字的工作量,值得推荐)。

使用此导入语句可以进一步减少打字工作量:

import math as m

math.sqrt()现在,您可以使用 ,而不是 使用m.sqrt()

2.函数导入:

from math import sqrt

如果您的代码只需要访问模块中的单个或几个函数,则这种导入类型最适合,但要使用模块中的任何新项目,您必须更新导入语句。

3.通用进口:

from math import * 

虽然它大大减少了打字工作量,但不建议这样做,因为它会用模块中的各种函数填充您的代码,并且它们的名称可能会与用户定义函数的名称冲突。
例如:

如果您有一个名为 sqrt 的函数,并且您导入了 math,那么您的函数是安全的:有您的 sqrt 和 math.sqrt。但是,如果您从 math import * 导入,就会出现问题:即两个不同的函数具有完全相同的名称。来源:Codecademy

解决方案 10:

我想补充一点。如果你遇到循环导入,了解 Python 如何将导入的模块作为属性处理会很有用。

我有以下结构:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

我将使用不同的导入方法从 main.py 导入其他模块

主要文件:

import mod.a
import mod.b as b
from mod import c
import d

dis.dis 显示差异(注意模块名称,abcd):

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (mod.a)
              9 STORE_NAME               1 (mod)

  2          12 LOAD_CONST               0 (-1)
             15 LOAD_CONST               1 (None)
             18 IMPORT_NAME              2 (b)
             21 STORE_NAME               2 (b)

  3          24 LOAD_CONST               0 (-1)
             27 LOAD_CONST               2 (('c',))
             30 IMPORT_NAME              1 (mod)
             33 IMPORT_FROM              3 (c)
             36 STORE_NAME               3 (c)
             39 POP_TOP

  4          40 LOAD_CONST               0 (-1)
             43 LOAD_CONST               1 (None)
             46 IMPORT_NAME              4 (mod.d)
             49 LOAD_ATTR                5 (d)
             52 STORE_NAME               5 (d)
             55 LOAD_CONST               1 (None)

最后它们看起来相同(每个示例中的结果都是 STORE_NAME),但如果您需要考虑以下四个循环导入,则值得注意:

示例1

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

这有效

示例2

bar/
   __init__.py
   a.py
   b.py
a.py:
import bar.b as b
b.py:
import bar.a as a
>>> import bar.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bara.py", line 1, in <module>
    import bar.b as b
  File "bar.py", line 1, in <module>
    import bar.a as a
AttributeError: 'module' object has no attribute 'a'

没有骰子

示例3

baz/
   __init__.py
   a.py
   b.py
a.py:
from baz import b
b.py:
from baz import a
>>> import baz.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "baza.py", line 1, in <module>
    from baz import b
  File "baz.py", line 1, in <module>
    from baz import a
ImportError: cannot import name a

类似的问题...但显然 from x import y 与 import import xy as y 不同

示例4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

这个也有效

解决方案 11:

import package
import module

使用 时import,令牌必须是一个模块(包含 Python 命令的文件)或一个包(包含sys.path文件的文件夹__init__.py)。

当有子包时:

import package1.package2.package
import package1.package2.module

文件夹(包)或文件(模块)的要求相同,但文件夹或文件必须位于 内package2, 必须位于 内package1,并且 和 都package1必须package2包含__init__.py文件。https ://docs.python.org/2/tutorial/modules.html

采用fromimport 的风格:

from package1.package2 import package
from package1.package2 import module

import包或模块以module(或package)而不是 的形式进入包含语句的文件的命名空间package1.package2.module。你始终可以绑定到更方便的名称:

a = big_package_name.subpackage.even_longer_subpackage_name.function

只有from导入样式允许您命名特定的函数或变量:

from package3.module import some_function

是允许的,但是

import package3.module.some_function 

是不允许的。

解决方案 12:

这是我当前目录的目录结构:

.  
└─a  
   └─b  
     └─c
  1. import语句会记住所有中间名称

这些名称必须符合以下条件:

In[1]: import a.b.c

In[2]: a
Out[2]: <module 'a' (namespace)>

In[3]: a.b
Out[3]: <module 'a.b' (namespace)>

In[4]: a.b.c
Out[4]: <module 'a.b.c' (namespace)>
  1. from ... import ...语句仅记住导入的名称

此名称不得限定:

In[1]: from a.b import c

In[2]: a
NameError: name 'a' is not defined

In[2]: a.b
NameError: name 'a' is not defined

In[3]: a.b.c
NameError: name 'a' is not defined

In[4]: c
Out[4]: <module 'a.b.c' (namespace)>

  • 注意:当然,我在步骤 1 和步骤 2 之间重新启动了我的 Python 控制台。

解决方案 13:

除了人们所说的内容外from x import *,这还会使人们更难判断名称的来源,还会使 Pylint 等代码检查器失效。它们会将这些名称报告为未定义的变量。

解决方案 14:

我自己对此的回答主要取决于首先我将使用多少个不同的模块。如果我只使用一个或两个,我通常会使用from... import,因为它可以减少文件其余部分的击键次数,但如果我要使用许多不同的模块,我更喜欢仅仅import因为这意味着每个模块引用都是自文档化的。我可以看到每个符号来自哪里,而不必到处寻找。

通常我更喜欢简单导入的自文档样式,并且只有当我必须输入模块名称的次数增加到 10 到 20 次以上时才更改为 from.. import,即使只有一个模块被导入。

解决方案 15:

有很多答案,但没有一个提到测试(使用unittestpytest)。

总结

用于import foo外部模块以简化测试。

艰难之路

从模块中单独导入类/函数(from foo import bar)会使红绿重构循环变得乏味。例如,如果我的文件如下所示

# my_module.py

from foo import bar


class Thing:
    def do_thing(self):
        bar('do a thing')

我的测试是

# test_my_module.py

from unittest.mock import patch
import my_module


patch.object(my_module, 'bar')
def test_do_thing(mock_bar):
    my_module.Thing().do_thing()
    mock_bar.assert_called_with('do a thing')

乍一看,这似乎很棒。但如果我想Thing在另一个文件中实现类,会发生什么?我的结构必须像这样改变...

# my_module.py

from tools import Thing


def do_thing():
    Thing().do_thing()


# tools.py

from foo import bar


class Thing:
    def do_thing(self):
        bar('do a thing')


# test_my_module.py

from unittest.mock import patch
import my_module
import tools  # Had to import implementation file...


patch.object(tools, 'bar')  # Changed patch
def test_do_thing(mock_bar):
    my_module.do_thing()  # Changed test (expected)
    mock_bar.assert_called_with('do a thing')

不幸的是,由于我使用了from foo import bar,我需要更新我的补丁来引用该tools模块。本质上,由于我的测试对实现了解太多,因此需要进行比预期更多的更改才能进行此重构。

更好的方法

使用import foo,我的测试可以忽略模块的实现方式并简单地修补整个模块。

# my_module.py

from tools import Thing


def do_thing():
    Thing().do_thing()


# tools.py

import foo


class Thing:
    def do_thing(self):
        foo.bar('do a thing')  # Specify 'bar' is from 'foo' module


# test_my_module.py

from unittest.mock import patch
import my_module


patch('foo')  # Patch entire foo module
def test_do_thing(mock_foo):
    my_module.do_thing()  # Changed test (expected)
    mock_foo.bar.assert_called_with('do a thing')

测试知道的实现细节越少越好。这样,如果你想出一个更好的解决方案(使用类而不是函数,使用额外的文件来分离想法等),那么在测试中需要做的更改就更少,以适应重构。

解决方案 16:

我发现的一个显著区别是,令人惊讶的是没有人谈论过,那就是使用普通的导入就可以访问导入的模块,private variable而使用from-importprivate functions语句则无法做到这一点。

在此处输入图片描述

图片中的代码:

设置.py

public_variable = 42
_private_variable = 141
def public_function():
    print("I'm a public function! yay!")
def _private_function():
    print("Ain't nobody accessing me from another module...usually")

纯导入器.py

import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()

# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually

来自导入器.py

from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function()   #doesn't work

解决方案 17:

正如Jan Wrobel所提到的,不同进口的一个方面在于进口的披露方式。

mymath模块

from math import gcd
...

mymath的用途:

import mymath
mymath.gcd(30, 42)  # will work though maybe not expected

如果我导入gcd仅供内部使用,而不向 用户披露mymath,这可能会很不方便。我经常遇到这种情况,而且在大多数情况下,我希望“保持模块清洁”。

除了Jan Wrobel建议使用 来进一步模糊这一点import math之外,我还开始使用前导下划线来隐藏导入:

# for instance...
from math import gcd as _gcd
# or...
import math as _math

在大型项目中,这种“最佳实践”允许我精确控制哪些信息可以向后续导入公开,哪些信息不公开。这可以保持模块整洁,并在项目达到一定规模时获得回报。

解决方案 18:

因为很多人在这里回答,但我只是尽力而为:)

  1. import module当你不知道要从哪个项目导入时,这是最好的选择module。这样,当出现问题时,调试可能会很困难,因为你不知道哪个项目有问题。

  2. form module import <foo>当您知道需要导入哪个项目时,这种方法是最好的,而且也有助于更好地控制根据需要导入特定项目。使用这种方法调试可能很容易,因为您知道导入了哪个项目。

解决方案 19:

导入模块 - 您不需要额外的努力来从模块中获取另一个东西。它有冗余输入等缺点

模块导入自 - 更少的输入和更多的控制可以访问模块的哪些项目。要使用模块中的新项目,您必须更新导入语句。

解决方案 20:

有一些内置模块主要包含裸函数(base64、math、os、shutil、sys、time等),将这些裸函数绑定到某些命名空间绝对是一种很好的做法,从而可以提高代码的可读性。想想如果没有命名空间,理解这些函数的含义会有多困难:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

比当它们绑定到某个模块时:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

有时你甚至需要命名空间来避免不同模块之间的冲突(json.load与pickle.load)


另一方面,有些模块主要包含类(configparser、datetime、tempfile、zipfile等),其中许多模块的类名已经足够不言自明了:

configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

因此,可能会存在争议,在代码中使用这些类和附加模块命名空间是否会添加一些新信息或只是延长代码。

解决方案 21:

我之前回答过一个类似的问题,但发帖者在我发帖之前就删除了它。下面是一个例子来说明差异。

Python 库可能有一个或多个文件(模块)。例如,

package1
  |-- __init__.py

或者

package2
  |-- __init__.py
  |-- module1.py
  |-- module2.py

我们可以根据设计要求在任何文件中定义 python 函数或类。

让我们定义

  1. func1()__init__.py以下mylibrary1,并且

  2. foo()module2.py之下mylibrary2

我们可以func1()使用以下方法之一进行访问

import package1

package1.func1()

或者

import package1 as my

my.func1()

或者

from package1 import func1

func1()

或者

from package1 import *

func1()

我们可以使用以下方法之一来访问foo()

import package2.module2

package2.module2.foo()

或者

import package2.module2 as mod2

mod2.foo()

或者

from package2 import module2

module2.foo()

或者

from package2 import module2 as mod2

mod2.foo()

或者

from package2.module2 import *

foo()

解决方案 22:

简单来说,这都是为了程序员的方便。在核心层面,他们只需导入模块的所有功能即可。

import module:当您使用import modulethen 来使用此模块的方法时,您必须编写module.method()。每次使用任何方法或属性时,您都必须引用该模块。

from module import all:当您使用from module import all这个模块的方法时,您只需编写method()而无需引用该模块。

解决方案 23:

@ahfx 已经提到了这些导入的一个关键方面,即模块加载过程的内部结构。如果您的系统需要使用循环导入(例如,您想在某些流行的 http 框架中使用依赖项注入),就会出现这种情况。在这种情况下,from {module} import {function}对加载过程如何进行的要求似乎更加激进。让我们举个例子:

#m1.py:
print('--start-m1--')
from m2 import *    # form does not matter; just need to force import of m2
print('--mid-m1--')

def do1(x):
    print(x)

print('--end-m1--')

输入

#m2.py
print('--start-m2--')

# from m1 import *      # A
# from m1 import do1    # B
# import m1             # C
                        # D -- no import of "do1" at all
                        
print('--mid-m2--')

def do2(x):
    m1.do1(x)

print('--end-m2--')

通过运行

#main.py:
from m1 import do1
do1('ok')

m2.py在(A,B,C,D)中的所有导入可能性中,只有这from {module} import {function}实际上会导致加载过程崩溃,从而导致臭名昭著的 (CPython 3.10.6)

ImportError: cannot import name 'do1' from partially initialized module 'm1' 
(most likely due to a circular import)

虽然我无法说出为什么会发生这种情况,但看起来该from ... import ...声明对相关模块在初始化过程中“进展如何”提出了更严格的要求。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用