您能向 Python 的语法添加新的语句吗?

2025-01-14 08:50:00
admin
原创
121
摘要:问题描述:您能在 Python 语法中添加新的语句(如,,)吗print?raise`with`说,允许..mystatement "Something" 或者,new_if True: print "example" 并不是是否应该这样做,而是是否可能(除了修...

问题描述:

您能在 Python 语法中添加新的语句(如,,)吗printraise`with`

说,允许..

mystatement "Something"

或者,

new_if True:
    print "example"

并不是是否应该这样做,而是是否可能(除了修改 Python 解释器代码)


解决方案 1:

您可能会发现这很有用 - Python 内部:向 Python 添加新语句,此处引用:


本文旨在帮助您更好地理解 Python 前端的工作原理。仅阅读文档和源代码可能有点无聊,因此我在这里采取亲自动手的方法:我将向untilPython 添加一条语句。

本文的所有编码都是针对Python Mercurial 存储库镜像中最先进的 Py3k 分支完成的。

声明until

有些语言,比如 Ruby,有一个语句,它是(相当于)until的补充。在 Ruby 中,我可以这样写:while`until num == 0`while num != 0

num = 3
until num == 0 do
  puts num
  num -= 1
end

它将打印:

3
2
1

所以,我想为 Python 添加类似的功能。也就是说,可以这样写:

num = 3
until num == 0:
  print(num)
  num -= 1

语言倡导题外话

本文并不试图建议在 Python 中添加语句until。虽然我认为这样的语句会使一些代码更清晰,并且本文展示了添加语句是多么容易,但我完全尊重 Python 的极简主义哲学。我在这里所做的一切,实际上,只是深入了解 Python 的内部工作原理。

修改语法

Python 使用名为 的自定义解析器生成器pgen。这是一个 LL(1) 解析器,可将 Python 源代码转换为解析树。解析器生成器的输入是文件Grammar/Grammar[1]。这是一个指定 Python 语法的简单文本文件。

[1]:从这里开始,对 Python 源代码中的文件的引用都是相对于源代码树的根目录给出的,该目录是运行 configure 和 make 来构建 Python 的目录。

语法文件需要做两处修改。第一处是添加until语句的定义。我找到了语句while的定义位置 ( while_stmt),并until_stmt在下面添加了[2]

compound_stmt: if_stmt | while_stmt | until_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
while_stmt: 'while' test ':' suite ['else' ':' suite]
until_stmt: 'until' test ':' suite

[2]:这演示了我在修改不熟悉的源代码时使用的一种常见技术:按相似性工作。这个原则不会解决你所有的问题,但它肯定可以简化这个过程。由于所有需要为 做的事情while也需要为 做until,所以它是一个很好的指导方针。

else请注意,我已决定从我的定义中排除该子句until,只是为了使其略有不同(因为坦率地说,我不喜欢else循环子句并且认为它不太符合 Python 之禅)。

第二个变化是修改 的规则以compound_stmt包含until_stmt,如上面的代码片段所示。它while_stmt再次位于 之后。

make修改后运行时Grammar/Grammar,请注意程序pgen将运行以重新生成Include/graminit.hPython/graminit.c,然后重新编译几个文件。

修改 AST 生成代码

Python 解析器创建解析树后,该树将被转换为 AST,因为 AST在编译过程的后续阶段使用起来要简单得多。

因此,我们将访问Parser/Python.asdl定义 Python AST 结构的内容,并为新until语句添加一个 AST 节点,同样位于下方while

| While(expr test, stmt* body, stmt* orelse)
| Until(expr test, stmt* body)

如果您现在运行make,请注意,在编译一堆文件之前,Parser/asdl_c.py会运行以从 AST 定义文件生成 C 代码。这(与Grammar/Grammar)是使用迷你语言(换句话说,DSL)简化编程的 Python 源代码的另一个示例。还请注意,由于Parser/asdl_c.py是 Python 脚本,因此这是一种引导程序- 要从头开始构建 Python,必须已经可以使用 Python。

虽然Parser/asdl_c.py生成了管理我们新定义的 AST 节点的代码(放入文件Include/Python-ast.h和中Python/Python-ast.c),但我们仍然必须手动编写将相关解析树节点转换为它的代码。这是在文件中完成的Python/ast.c。在那里,一个名为的函数ast_for_stmt将语句的解析树节点转换为 AST 节点。同样,在我们的老朋友的指导下,我们直接跳到处理复合语句的while大块中,并添加一个子句:switch`until_stmt`

case while_stmt:
    return ast_for_while_stmt(c, ch);
case until_stmt:
    return ast_for_until_stmt(c, ch);

现在我们应该实现ast_for_until_stmt。它如下:

static stmt_ty
ast_for_until_stmt(struct compiling *c, const node *n)
{
    /* until_stmt: 'until' test ':' suite */
    REQ(n, until_stmt);

    if (NCH(n) == 4) {
        expr_ty expression;
        asdl_seq *suite_seq;

        expression = ast_for_expr(c, CHILD(n, 1));
        if (!expression)
            return NULL;
        suite_seq = ast_for_suite(c, CHILD(n, 3));
        if (!suite_seq)
            return NULL;
        return Until(expression, suite_seq, LINENO(n), n->n_col_offset, c->c_arena);
    }

    PyErr_Format(PyExc_SystemError,
                 "wrong number of tokens for 'until' statement: %d",
                 NCH(n));
    return NULL;
}

同样,这是在仔细查看等效项时编写的ast_for_while_stmt,不同之处在于until我决定不支持该else子句。正如预期的那样,AST 是递归创建的,使用其他 AST 创建函数,例如ast_for_expr条件表达式和ast_for_suite语句主体。最后,返回until一个名为的新节点。Until

n请注意,我们使用一些宏(如NCH和)来访问解析树节点CHILD。这些值得理解 - 它们的代码在Include/node.h

题外话:AST 组成

我选择为该语句创建一个新类型的 AST until,但实际上这不是必需的。我可以节省一些工作,并使用现有 AST 节点的组合来实现新功能,因为:

until condition:
   # do stuff

功能上等同于:

while not condition:
  # do stuff

我可以创建一个以节点为子节点的节点,而不是Until在 中创建节点。由于 AST 编译器已经知道如何处理这些节点,因此可以跳过该过程的后续步骤。ast_for_until_stmt`Not`While

将 AST 编译为字节码

下一步是将 AST 编译为 Python 字节码。编译的中间结果是一个 CFG(控制流图),但由于相同的代码会处理它,因此我暂时将忽略此细节并将其留到另一篇文章中。

接下来我们要看的代码是Python/compile.c。顺着代码的线索while,我们找到了函数compiler_visit_stmt,它负责将语句编译成字节码。我们为添加一个子句Until

case While_kind:
    return compiler_while(c, s);
case Until_kind:
    return compiler_until(c, s);

如果您想知道它Until_kind是什么,它是一个常量(实际上是枚举的值_stmt_kind),自动从 AST 定义文件生成到 中Include/Python-ast.h。无论如何,我们调用compiler_until它,当然,它仍然不存在。我稍后会讲到它。

如果你和我一样好奇,你会注意到这compiler_visit_stmt很奇怪。无论使用多少次grep-ping 源树都无法揭示它被调用的位置。在这种情况下,只剩下一个选项 - C macro-fu。事实上,经过短暂的调查,我们找到了VISIT在 中定义的宏Python/compile.c

#define VISIT(C, TYPE, V) {\n    if (!compiler_visit_ ## TYPE((C), (V))) \n        return 0; \n

它用于调用compiler_visit_stmtcompiler_body回到我们的正事上……

正如承诺的那样,这里是compiler_until

static int
compiler_until(struct compiler *c, stmt_ty s)
{
    basicblock *loop, *end, *anchor = NULL;
    int constant = expr_constant(s->v.Until.test);

    if (constant == 1) {
        return 1;
    }
    loop = compiler_new_block(c);
    end = compiler_new_block(c);
    if (constant == -1) {
        anchor = compiler_new_block(c);
        if (anchor == NULL)
            return 0;
    }
    if (loop == NULL || end == NULL)
        return 0;

    ADDOP_JREL(c, SETUP_LOOP, end);
    compiler_use_next_block(c, loop);
    if (!compiler_push_fblock(c, LOOP, loop))
        return 0;
    if (constant == -1) {
        VISIT(c, expr, s->v.Until.test);
        ADDOP_JABS(c, POP_JUMP_IF_TRUE, anchor);
    }
    VISIT_SEQ(c, stmt, s->v.Until.body);
    ADDOP_JABS(c, JUMP_ABSOLUTE, loop);

    if (constant == -1) {
        compiler_use_next_block(c, anchor);
        ADDOP(c, POP_BLOCK);
    }
    compiler_pop_fblock(c, LOOP, loop);
    compiler_use_next_block(c, end);

    return 1;
}

我必须坦白:这段代码不是基于对 Python 字节码的深刻理解而编写的。与本文的其余部分一样,它是模仿 kincompiler_while函数编写的。但是,通过仔细阅读,记住 Python VM 是基于堆栈的,并浏览模块的文档dis(其中包含带有描述的Python 字节码列表),可以了解发生了什么。

就这样,我们就完成了...不是吗?

完成所有更改并运行后make,我们可以运行新编译的 Python 并尝试我们的新until语句:

>>> until num == 0:
...   print(num)
...   num -= 1
...
3
2
1

瞧,成功了!让我们看看使用该dis模块为新语句创建的字节码,如下所示:

import dis

def myfoo(num):
    until num == 0:
        print(num)
        num -= 1

dis.dis(myfoo)

结果如下:

4           0 SETUP_LOOP              36 (to 39)
      >>    3 LOAD_FAST                0 (num)
            6 LOAD_CONST               1 (0)
            9 COMPARE_OP               2 (==)
           12 POP_JUMP_IF_TRUE        38

5          15 LOAD_NAME                0 (print)
           18 LOAD_FAST                0 (num)
           21 CALL_FUNCTION            1
           24 POP_TOP

6          25 LOAD_FAST                0 (num)
           28 LOAD_CONST               2 (1)
           31 INPLACE_SUBTRACT
           32 STORE_FAST               0 (num)
           35 JUMP_ABSOLUTE            3
      >>   38 POP_BLOCK
      >>   39 LOAD_CONST               0 (None)
           42 RETURN_VALUE

最有趣的操作是第 12 项:如果条件为真,则在循环后跳转到。这是正确的语义until。如果未执行跳转,则循环体将继续运行,直到它跳回到操作 35 处的条件。

我对自己的改变感到很满意,然后我尝试运行该函数(执行myfoo(3)),而不是显示其字节码。结果并不令人鼓舞:

Traceback (most recent call last):
  File "zy.py", line 9, in
    myfoo(3)
  File "zy.py", line 5, in myfoo
    print(num)
SystemError: no locals when loading 'print'

哇哦……这可不是什么好事。那么到底出了什么问题呢?

缺失符号表的情况

Python 编译器在编译 AST 时执行的步骤之一是为它编译的代码创建一个符号表。对PySymtable_Buildin 的PyAST_Compile调用会调用符号表模块 ( Python/symtable.c),该模块以类似于代码生成函数的方式遍历 AST。每个作用域都有一个符号表有助于编译器找出一些关键信息,例如哪些变量是全局的,哪些变量是作用域的本地变量。

为了修复这个问题,我们必须修改symtable_visit_stmt中的函数Python/symtable.c,在语句[3]until的类似代码之后添加处理语句的代码:while

case While_kind:
    VISIT(st, expr, s->v.While.test);
    VISIT_SEQ(st, stmt, s->v.While.body);
    if (s->v.While.orelse)
        VISIT_SEQ(st, stmt, s->v.While.orelse);
    break;
case Until_kind:
    VISIT(st, expr, s->v.Until.test);
    VISIT_SEQ(st, stmt, s->v.Until.body);
    break;

[3]:顺便说一句,如果没有此代码,则会出现编译器警告Python/symtable.c。编译器注意到Until_kind枚举值未在 switch 语句中处理,symtable_visit_stmt并发出警告。检查编译器警告始终很重要!

现在我们真的完成了。在进行此更改后编译源代码可使工作myfoo(3)按预期执行。

结论

在本文中,我演示了如何向 Python 添加新语句。尽管需要对 Python 编译器的代码进行大量修改,但实现这一更改并不困难,因为我使用了类似的现有语句作为指导。

Python 编译器是一个复杂的软件,我不敢说自己是这方面的专家。但是,我对 Python 的内部结构非常感兴趣,尤其是它的前端。因此,我发现这个练习对于理论研究编译器原理和源代码非常有用。它将作为未来深入研究编译器的文章的基础。

参考

我在撰写这篇文章时参考了一些非常好的参考资料。它们如下(无特定顺序):

  • PEP 339:CPython 编译器的设计- 可能是 Python 编译器最重要、最全面的官方文档。它非常简短,痛苦地显示了 Python 内部良好文档的稀缺性。

  • “Python 编译器内部原理”——Thomas Lee 撰写的文章

  • “Python:设计和实现”——Guido van Rossum 的演讲

  • Python (2.5) 虚拟机导览 - Peter Tröger 的演讲

原始来源

解决方案 2:

执行此类操作的一种方法是预处理源代码并对其进行修改,将添加的语句转换为 Python。这种方法会带来各种问题,我不建议将其用于一般用途,但对于语言实验或特定用途的元编程,它偶尔会很有用。

例如,假设我们要引入一个“myprint”语句,它不是打印到屏幕上,而是记录到特定的文件中。即:

myprint "This gets logged to file"

相当于

print >>open('/tmp/logfile.txt','a'), "This gets logged to file"

关于如何进行替换,有多种选择,从正则表达式替换到生成 AST,再到编写自己的解析器(具体取决于您的语法与现有 Python 的匹配程度)。一种好的中间方法是使用 tokenizer 模块。这应该允许您添加新的关键字、控制结构等,同时以类似于 Python 解释器的方式解释源代码,从而避免粗糙的正则表达式解决方案可能导致的破坏。对于上面的“myprint”,您可以编写以下转换代码:

import tokenize

LOGFILE = '/tmp/log.txt'
def translate(readline):
    for type, name,_,_,_ in tokenize.generate_tokens(readline):
        if type ==tokenize.NAME and name =='myprint':
            yield tokenize.NAME, 'print'
            yield tokenize.OP, '>>'
            yield tokenize.NAME, "open"
            yield tokenize.OP, "("
            yield tokenize.STRING, repr(LOGFILE)
            yield tokenize.OP, ","
            yield tokenize.STRING, "'a'"
            yield tokenize.OP, ")"
            yield tokenize.OP, ","
        else:
            yield type,name

(这确实使 myprint 成为一个关键字,因此在其他地方用作变量可能会导致问题)

那么问题就是如何使用它,以便您的代码可以在 Python 中使用。一种方法就是编写您自己的导入函数,并使用它来加载用您的自定义语言编写的代码。即:

import new
def myimport(filename):
    mod = new.module(filename)
    f=open(filename)
    data = tokenize.untokenize(translate(f.readline))
    exec data in mod.__dict__
    return mod

然而,这要求你以不同于普通 Python 模块的方式处理自定义代码。即“ some_mod = myimport("some_mod.py")”而不是“ import some_mod

另一个相当巧妙(尽管有点粗糙)的解决方案是创建自定义编码(请参阅PEP 263),如本食谱所示。您可以将其实现为:

import codecs, cStringIO, encodings
from encodings import utf_8

class StreamReader(utf_8.StreamReader):
    def __init__(self, *args, **kwargs):
        codecs.StreamReader.__init__(self, *args, **kwargs)
        data = tokenize.untokenize(translate(self.stream.readline))
        self.stream = cStringIO.StringIO(data)

def search_function(s):
    if s!='mylang': return None
    utf8=encodings.search_function('utf8') # Assume utf8 encoding
    return codecs.CodecInfo(
        name='mylang',
        encode = utf8.encode,
        decode = utf8.decode,
        incrementalencoder=utf8.incrementalencoder,
        incrementaldecoder=utf8.incrementaldecoder,
        streamreader=StreamReader,
        streamwriter=utf8.streamwriter)

codecs.register(search_function)

现在,此代码运行后(例如,您可以将其放在 .pythonrc 或 site.py 中),任何以注释“#coding: mylang”开头的代码都将自动通过上述预处理步骤进行翻译。例如。

# coding: mylang
myprint "this gets logged to file"
for i in range(10):
    myprint "so does this : ", i, "times"
myprint ("works fine" "with arbitrary" + " syntax" 
  "and line continuations")

注意事项:

预处理器方法存在一些问题,如果您使用过 C 预处理器,您可能对此很熟悉。主要问题是调试。python 看到的只是预处理文件,这意味着堆栈跟踪等中打印的文本将引用该文件。如果您执行了大量翻译,这可能与您的源文本有很大不同。上面的示例不会更改行号等,因此不会有太大差异,但您更改得越多,就越难弄清楚。

解决方案 3:

是的,在某种程度上这是可能的。有一个模块用于sys.settrace()实现gotocomefrom“关键字”:

from goto import goto, label
for i in range(1, 10):
  for j in range(1, 20):
    print i, j
    if j == 3:
      goto .end # breaking out from nested loop
label .end
print "Finished"

解决方案 4:

除非更改和重新编译源代码(使用开源可以实现),否则更改基础语言实际上是不可能的。

即使你重新编译了源代码,它也不是 python,只是你修改过的版本,你需要非常小心,不要引入错误。

但是,我不确定你为什么要这么做。Python 的面向对象特性使得使用该语言实现类似结果变得非常简单。

解决方案 5:

一般答案:您需要预处理源文件。

更具体的答案:安装EasyExtend,并执行以下步骤

i)创建一个新的langlet(扩展语言)

import EasyExtend
EasyExtend.new_langlet("mystmts", prompt = "my> ", source_ext = "mypy")

如果没有额外说明,将会在 EasyExtend/langlets/mystmts/ 下创建一组文件。

ii)打开 mystmts/parsedef/Grammar.ext 并添加以下几行

small_stmt: (expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt |
             import_stmt | global_stmt | exec_stmt | assert_stmt | my_stmt )

my_stmt: 'mystatement' expr

这足以定义新语句的语法。small_stmt 非终结符是 Python 语法的一部分,也是新语句被挂接的地方。解析器现在将识别新语句,即包含它的源文件将被解析。但是编译器将拒绝它,因为它仍然必须转换为有效的 Python。

iii) 现在必须添加语句的语义。为此,必须编辑 msytmts/langlet.py 并添加 my_stmt 节点访问者。

 def call_my_stmt(expression):
     "defines behaviour for my_stmt"
     print "my stmt called with", expression

 class LangletTransformer(Transformer):
       @transform
       def my_stmt(self, node):
           _expr = find_node(node, symbol.expr)
           return any_stmt(CST_CallFunc("call_my_stmt", [_expr]))

 __publish__ = ["call_my_stmt"]

iv) 转到 langlets/mystmts 并输入

python run_mystmts.py

现在应启动一个会话并且可以使用新定义的语句:

__________________________________________________________________________________

 mystmts

 On Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)]
 __________________________________________________________________________________

 my> mystatement 40+2
 my stmt called with 42

要得到一个简单的语句需要经过好几个步骤,对吧?目前还没有一个 API 可以让人定义简单的东西而不必关心语法。但 EE 非常可靠,尽管存在一些错误。因此,出现一个 API 只是时间问题,它允许程序员使用方便的 OO 编程来定义方便的东西,如中缀运算符或小语句。对于更复杂的事情,比如通过构建 langlet 将整个语言嵌入 Python,没有办法绕过完整的语法方法。

解决方案 6:

这是一种非常简单但糟糕的添加新语句的方法,仅在解释模式下。我使用它来编辑基因注释的小单字母命令,仅使用 sys.displayhook,但为了回答这个问题,我还添加了 sys.excepthook 来处理语法错误。后者真的很丑陋,从 readline 缓冲区获取原始代码。好处是,通过这种方式添加新语句非常简单。


jcomeau@intrepid:~/$ cat demo.py; ./demo.py
#!/usr/bin/python -i
'load everything needed under "package", such as package.common.normalize()'
import os, sys, readline, traceback
if __name__ == '__main__':
    class t:
        @staticmethod
        def localfunction(*args):
            print 'this is a test'
            if args:
                print 'ignoring %s' % repr(args)

    def displayhook(whatever):
        if hasattr(whatever, 'localfunction'):
            return whatever.localfunction()
        else:
            print whatever

    def excepthook(exctype, value, tb):
        if exctype is SyntaxError:
            index = readline.get_current_history_length()
            item = readline.get_history_item(index)
            command = item.split()
            print 'command:', command
            if len(command[0]) == 1:
                try:
                    eval(command[0]).localfunction(*command[1:])
                except:
                    traceback.print_exception(exctype, value, tb)
        else:
            traceback.print_exception(exctype, value, tb)

    sys.displayhook = displayhook
    sys.excepthook = excepthook
>>> t
this is a test
>>> t t
command: ['t', 't']
this is a test
ignoring ('t',)
>>> ^D

解决方案 7:

我找到了有关添加新语句的指南:

https://troeger.eu/files/teaching/pythonvm08lab.pdf

基本上,要添加新的语句,您必须编辑Python/ast.c(除其他外)并重新编译 python 二进制文件。

虽然这是可能的,但不要这么做。你几乎可以通过函数和类实现所有功能(这不需要人们重新编译 Python 来运行你的脚本……)

解决方案 8:

使用EasyExtend可以做到这一点:

EasyExtend (EE) 是一个用纯 Python 编写并与 CPython 集成的预处理器生成器和元编程框架。EasyExtend 的主要目的是创建扩展语言,即为 Python 添加自定义语法和语义。

解决方案 9:

它并不完全是在语言语法中添加新的语句,但宏是一个强大的工具:https://github.com/lihaoyi/macropy

解决方案 10:

有些事情可以用装饰器来完成。例如,假设 Python 没有with语句。然后我们可以实现类似的行为,如下所示:

# ====== Implementation of "mywith" decorator ======

def mywith(stream):
    def decorator(function):
        try: function(stream)
        finally: stream.close()
    return decorator

# ====== Using the decorator ======

@mywith(open("test.py","r"))
def _(infile):
    for l in infile.readlines():
        print(">>", l.rstrip())

_然而,正如这里所做的那样,这是一个相当不干净的解决方案。尤其是装饰器调用函数并设置为的行为None是出乎意料的。澄清一下:这个装饰器相当于写

def _(infile): ...
_ = mywith(open(...))(_) # mywith returns None.

装饰器通常被期望去修改函数而不是执行函数。

我以前在一个脚本中使用过这种方法,其中我必须为几个函数临时设置工作目录。

解决方案 11:

过时:根据Logix 网站,

Logix 项目现在已被弃用并且不再开发。

有一种基于 Python 的语言叫做Logix,你可以用它做这些事情。它已经有一段时间没有开发了,但是你要求的功能在最新版本中确实有效。

解决方案 12:

不修改解释器是不行的。我知道过去几年里很多语言都被描述为“可扩展”,但不是像你描述的那样。你可以通过添加函数和类来扩展 Python。

解决方案 13:

十年前你做不到,我怀疑这一点现在也没有改变。不过,如果你准备重新编译 Python,那么修改语法并不难,我怀疑这一点现在也没有改变。

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

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用