当前位置:

首页 > 编程开发 > 如何排除Python程序中的错误和异常?

如何排除Python程序中的错误和异常?

开始捕捉以防万一你不熟悉异常,让我们从一般定义开始......exception:(计算)正常处理时发生的中断,通常由错误条件引起,可由另一部分程序处理。让我们看一个简单的例子:definitiate_security_protocol(code):ifcode==1:print("Returningonboardcompaniontohomelocation...")ifcode==712:print("Dematerializingtopresetlocation...")code=int(input

本文目录

    开始捕捉

    以防万一你不熟悉异常,让我们从一般定义开始......

    exception:(计算)正常处理时发生的中断,通常由错误条件引起,可由另一部分程序处理。

    让我们看一个简单的例子:

    def initiate_security_protocol(code):
        if code == 1:
            print("Returning onboard companion to home location...")
        if code == 712:
            print("Dematerializing to preset location...")
    
    code = int(input("Enter security protocol code: "))
    initiate_security_protocol(code)
    >>> Enter security protocol code: 712
    Dematerializing to preset location...
    >>> Enter security protocol code: seven one two
    Traceback (most recent call last):
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/security_protocols.py", line 7, in 
        code = int(input("Enter security protocol code: "))
    ValueError: invalid literal for int() with base 10: 'seven one two'

    显然,这是一个错误。我们不希望我们的程序因为用户输入了一些奇怪的东西而突然崩溃。正如下面这个笑话所说...

    一名 QA 工程师走进一家酒吧。他点了一杯啤酒。他点了五瓶啤酒。他点了 -1 杯啤酒。他点了一只蜥蜴。

    我们想防止奇怪的输入。在这种情况下,只有一个重要的故障点:就是int()函数。它期望接收可以转换为整数的参数,如果它没有得到它,则会抛出ValueError异常。为了正确处理这个问题,我们将可能失败的代码包装在一个try...except块中。

    try:
        code = int(input("Enter security protocol code: "))
    except ValueError:
        code = 0
    initiate_security_protocol(code)

    当我们再次测试我们的代码时,我们不会遇到这种失败错误。如果我们无法从用户那里获得我们需要的信息,我们将只需要设置code=0。当然,我们可以重写我们的initiate_security_protocol()函数来处理0不同的代码,但是我不会在这里展示,只是为了节省时间。

    注意:无论出于何种原因,作为一名多语言程序员,我经常忘记在 Python 中使用except,而用大多数其他语言所使用的catch语句。我已经在这篇文章中打错了三遍(然后立即修复它)。这只是一个记忆点。值得庆幸的是,Python没有catch的关键字,因此语法错误会很突出。如果你会多种语言,当你感到困惑时,请不要惊慌。python里是except,不是catch。

    阅读Traceback

    在我们深入探讨该try...except语句的一些更深层次的细节之前,让我们再次回顾一下该错误语句。毕竟,如果我们不讨论错误消息,那么一篇关于错误处理的文章有什么用呢?在 Python 中,我们称之为Traceback,因为它从涉及的第一行代码到最后一行跟踪错误的起源。在许多其他语言中,这将被称为堆栈跟踪( stack trace)。

    Traceback (most recent call last):
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/security_protocols.py", line 7, in 
        code = int(input("Enter security protocol code: "))
    ValueError: invalid literal for int() with base 10: 'seven one two'

    我有从下到上阅读这些信息的习惯,因为它可以帮助我首先获得最重要的信息。如果你查看最后一行,你会看到ValueError,这是已引发的特定异常。确切的细节如下;在这种情况下,无法使用 . 将字符串'seven one two'用int()转换为整数。我们还了解到它正在尝试转换为以10 为底的整数,这在其他场景中可能是有用的信息。想象一下,例如,如果那行改成...

    ValueError: invalid literal for int() with base 10: '5bff'

    如果我们忘记指定以 16 为基数进行int('5bff', 16)转化,而不是默认值(以 10 为基数),这是完全可能的。简而言之,你应该始终彻底阅读并理解错误消息的最后一行!有太多次我看了一半的帖子,花了半个小时追错了bug,才发现我忘记了一个参数或使用了错误的函数。

    错误消息上方是错误来自 ( code = int(input("Enter security protocol code: "))) 的代码行。上面是文件的绝对路径 ( security_protocols.py) 和行号7。该语句in 意味着代码在任何函数之外。在这个例子中,回调只有一步,所以让我们看一些稍微复杂一点的东西。我已经更改并扩展了之前的代码。

    Traceback (most recent call last):
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/databank.py", line 6, in 
        decode_message("Bad Wolf")
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/databank.py", line 4, in decode_message
        initiate_security_protocol(message)
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/security_protocols.py", line 2, in initiate_security_protocol
        code = int(code)
    ValueError: invalid literal for int() with base 10: 'Bad Wolf'

    我们遇到了与以前类似的错误 - 我们正在尝试将字符串转换为整数,但它不起作用。倒数第二行向我们展示了失败的代码;果然,这儿提到了int()这一点。根据上面的行,这个有问题的代码位于security_protocols.py文件的第2 行initiate_security_protocol()函数内部!我们就可以马上找到那儿,并将其包装在一个try...except. 了解了为什么从下到上阅读可以节省时间了吧?

    然而,让我们想象它并不那么简单。也许我们没有修改security_protocols.py的选项,所以我们需要在执行该模块之前防止出现问题。如果我们查看下一行,我们会看到在databank.py第 4 行,在decode_message()函数内部,我们调用的initiate_security_protocol()函数有问题。是由于在databank.py第6行被调用,这就是我们将参数传递"Bad Wolf"给它的地方。

    数据输入不是问题,因为我们要解码消息“Bad Wolf”。但是,为什么我们要将我们试图解码的消息传递给安全协议呢?也许我们需要改写那个函数(或者除了其他更改之外?)。如你所见,Traceback对于了解错误的来源非常重要。养成仔细阅读的习惯;许多有用的信息可能隐藏在意想不到的地方。

    顺便说一句,第一行每次都是一样的,但是如果你忘记如何阅读这些消息,它会非常有用。最近执行的代码列在最后。因此,正如我之前所说,你应该从下往上阅读它们。

    Exception

    “请求宽恕比获得许可更容易。” -海军少将格蕾丝·霍珀

    这句话最初是关于主动的;如果你相信一个想法,请尽力去尝试它,而不是等待其他人的许可来追求它。然而,在这种情况下,它很好地描述了 Python 的错误处理哲学:如果某些事情经常以一种或多种特定方式失败,通常最好使用try...except语句来处理这些情况。

    这种哲学被正式命名为“请求宽恕比许可更容易”,或EAFP。

    这有点抽象,所以让我们考虑另一个例子。假设我们希望能够在字典中查找信息。

    datafile_index = {
        # Omitted for brevity.
        # Just assume there's a lot of data in here.
    }
    
    def get_datafile_id(subject):
        id = datafile_index[subject]
        print(f"See datafile {id}.")
    
    get_datafile_id("Clara Oswald")
    get_datafile_id("Ashildir")
    See datafile 6035215751266852927.
    
    Traceback (most recent call last):
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/databank.py", line 30, in 
        get_datafile_id("Ashildir")
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/databank.py", line 26, in get_datafile_id
        id = datafile_index[subject]
    KeyError: 'Ashildir'

    第一个函数调用是对的。我们在字典database_index中搜索存在的键"Clara Oswald",因此我们返回与其关联的值 (6035215751266852927 ),并在我们格式化语句print()中打印出该数据。但是,第二个函数调用失败。引发异常KeyError,因为"Ashildir"它不是字典中的键。

    技术说明: Python 为collections.defaultdict这个确切问题提供了另一种解决方案;尝试访问不存在的键将使用一些默认值在字典中创建键/值对。但是,由于这是演示错误处理的示例,因此我没有使用它。

    由于不能合理地期望我们知道或记住字典中的所有键,尤其是在现实世界的场景中,我们需要一些方法来处理尝试访问不存在的键的常见情况。你的第一直觉可能是在尝试访问字典键之前检查它......

    def get_datafile_id(subject):
        if subject in datafile_index:
            id = datafile_index[subject]
            print(f"See datafile {id}.")
        else:
            print(f"Datafile not found on {subject})

    在 Python 文化中,这种方法被称为“跳前看”[LBYL]。

    但这不是最有效的方法!“宽恕,而不是许可”在这里发挥作用:我们不是先测试,而是使用try...except.

    def get_datafile_id(subject):
        try:
            id = datafile_index[subject]
            print(f"See datafile {id}.")
        except KeyError:
            print(f"Datafile not found on {subject}")

    这背后的逻辑很简单:我们不是通过两次获取键,而是只访问一次,并使用实际exception作为逻辑分支的手段。

    在 Python 中,我们不认为异常是可以避免的。事实上,try...except它是许多 Python 设计模式和算法的常规部分。不要害怕引发和捕获异常!事实上,即使是键盘中断也是通过KeyboardInterrupt异常处理的。

    注意: try...except是一个强大的工具,但它并不适用于一切。例如,None从函数返回通常被认为比引发异常更好。仅在发生最好由调用者处理的实际错误时抛出异常。

    反面模式

    迟早,每个 Python 开发人员都会发现这是可行的:

    try:
        someScaryFunction()
    except:
        print("An error occured. Moving on!")

    一个单except语句允许你在一个中捕获所有异常。这个被称为反面模式,这是一个非常非常糟糕的想法。总结一下……

    ...实际错误的所有上下文放在了一起抛出,永远看不到问题跟踪器的内部。当发生“大量”异常时,堆栈跟踪指向发生次要错误的位置,而不是 try 块内的实际失败位置。

    长话短说,你应该始终明确地捕获特定的异常类型。任何你无法预见的失败都可能与一些需要解决的错误有关;例如,当你的超级复杂搜索功能突然开始提出 anOSError而不是预期的KeyError或者TypeError时。

    像往常一样,The Zen Python 对此有话要说……

    错误永远不应该悄无声息地过去。
    除非明确沉默。

    换句话说,这不是口袋妖怪 - 你不应该抓住他们!

    Except, Else, Finally

    我不会一下子就捕捉到所有异常。那么,如何处理多个可能的故障呢?

    你要知道 Python 的try...except工具比它最初展示的要多得多。

    class SonicScrewdriver:
    
        def __init__(self):
            self.memory = 0
    
        def perform_division(self, lhs, rhs):
            try:
                result = float(lhs)/float(rhs)
            except ZeroDivisionError:
                print("Wibbly wobbly, timey wimey.")
                result = "Infinity"
            except (ValueError, UnicodeError):
                print("Oy! Don't diss the sonic!")
                result = "Cannot Calculate"
            else:
                self.memory = result
            finally:
                print(f"Calculation Result: {result}\n")
    
    
    sonic = SonicScrewdriver()
    
    sonic.perform_division(8, 4)
    sonic.perform_division(4, 0)
    sonic.perform_division(4, "zero")
    
    print(f"Memory Is: {sonic.memory}")

    在我向你展示输出之前,请仔细查看代码。你认为这三个sonic.perform_division()函数调用中的每一个都会打印出什么?最终存储sonic.memory的是什么?看看你能不能弄明白。

    如果你已经有答案?让我们看看你是否正确。

    Calculation Result: 2.0
    
    Wibbly wobbly, timey wimey.
    Calculation Result: Infinity
    
    Oy! Don't diss the sonic!
    Calculation Result: Cannot Calculate
    
    Memory Is: 2.0

    你是惊讶,还是你做对了?让我们分析一下。

    try:当然,是我们试图运行的代码,它可能会也可能不会引发异常。

    except ZeroDivisionError:当我们试图除以零时发生。在这种情况下,我们说该值"Infinity"是计算的结果,并打印出一条关于除以0的提示信息。

    except (ValueError, UnicodeError):只要引发这两个异常之一,就会抛出异常。ValueError是每当我们传递的任何参数都不能被强制转换float()时,就会发生这种错误,而UnicodeError是如果编码或解码 Unicode 有问题,就会发生这种报错。实际上,第二个只是为了说明一点。对于ValueError所有无法将参数转换为浮点数的可信场景,这已经足够了。无论哪种情况,我们都将值"Cannot Calculate"作为我们的结果,并提醒用户不要对硬件提出不合理的要求。

    这就是事情变得有趣的地方。仅在未引发异常时else:运行。在这种情况下,如果我们有一个有效的除法计算结果,我们实际上希望将它存储在内存中;相反,如果我们得到“无穷大”或“无法计算”作为我们的结果,我们不会存储它。

    无论如何,该finally:部分都会运行。在这种情况下,我们打印出我们的计算结果。

    顺序确实很重要。我们必须遵循模式try...except...else...finally,else如果存在,必须在所有except语句之后。finally总是最后的。

    最初很容易混淆else和finally,因此请确保你了解其中的区别。else仅在未引发异常时运行;finally每次运行。

    Finally执行顺序

    你希望以下代码实现什么?

    class SonicScrewdriver:
    
        def __init__(self):
            self.memory = 0
    
        def perform_division(self, lhs, rhs):
            try:
                result = float(lhs)/float(rhs)
            except ZeroDivisionError:
                print("Wibbly wobbly, timey wimey.")
                result = "Infinity"
            except (ValueError, UnicodeError):
                print("Oy! Don't diss the sonic!")
                result = "Cannot Calculate"
            else:
                self.memory = result
                return result
            finally:
                print(f"Calculation Result: {result}\n")
                result = -1
    
    
    sonic = SonicScrewdriver()
    
    print(sonic.perform_division(8, 4))

    下面的那return句话else应该是事情的结束了吧?其实,不!如果我们运行该代码...

    Calculation Result: 2.0
    
    2.0

    有两个重要的观察结果:

    1. finally正在运行,即使在我们的return声明之后。该函数不会像通常那样退出。

    2. 该return语句确实在finally块执行之前运行。我们知道这一点是因为结果result输出是2.0,而不是我们在语句finally中分配的-1。

    finally每次都会运行,即使你return在try...except结构中的其他地方有。

    但是,我也用一个os.abort()代替测试了上面的return result,在这种情况下,finally块永远不会运行;该程序彻底中止。你可以在任何地方直接停止程序执行,Python 只会放弃它正在做的事情并退出。该规则是不变的,即使是不寻常的finally行为。

    抛出异常

    所以,我们可以用try...except捕获异常. 但是如果我们只是想主动抛出一个呢?

    在 Python 术语中,我们说我们引发了异常,并且与该语言中的大多数事情一样,实现这一点很明显:只需使用raise关键字:

    class Tardis:
    
        def __init__(self):
            pass
    
        def camouflage(self):
            raise NotImplementedError('Chameleon circuits are stuck.')
    
    tardis = Tardis()
    tardis.camouflage()

    当我们执行该代码时,我们会看到我们引发的异常。

    Traceback (most recent call last):
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/tardis.py", line 10, in 
        tardis.camoflague()
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/tardis.py", line 7, in camoflague
        raise NotImplementedError('Chameleon circuits are stuck.')
    NotImplementedError: Chameleon circuits are stuck.

    这样就能知道我们在哪儿出现了异常错误。

    注意:异常NotImplementedError是Python 中的内置异常之一,有时用于指示一个函数不应该使用,因为它还没有完成(但总有一天会完成)。它不能与NotImplementedvalue互换。请参阅文档以了解何时使用它们。

    显然,关键代码是raise NotImplementedError('Chameleon circuits are stuck.'). 在raise关键字之后,我们给出要引发的异常对象的名称。在大多数情况下,我们从 Exception 类创建一个新对象,从括号的使用可以看出。所有异常都接受字符串作为消息的第一个参数。一些例外接受或需要更多参数,因此请参阅官方文档。

    使用异常

    有时我们需要在捕捉到异常后对其进行处理。我们有一些非常简单的方法来做到这一点。

    最明显的是从异常中打印消息。为此,我们需要能够处理我们捕获的异常对象。让我们将except语句更改为except NotImplementedError as e:,其中e是我们“绑定”到异常对象的名称。然后,我们可以e直接作为对象使用。

    tardis = Tardis()
    
    try:
        tardis.camouflage()
    except NotImplementedError as e:
        print(e)

    异常类已经定义了它的__str__()函数来返回异常消息,所以如果我们将它转换成一个字符串(str()),这就是我们将得到的。你可能还记得上一篇文章print()自动将其参数转换为字符串。当我们运行这段代码时,我们得到...

    Chameleon circuits are stuck.

    是不是很容易!

    冒泡

    现在,如果我们想再次引发异常怎么办?

    等等,什么?我们刚刚捕获了那个东西。为什么还要再次引发异常?

    一个示例是,如果你需要在幕后进行一些清理工作,但最终仍希望调用者必须处理异常。这是一个例子......

    class Byzantium:
    
        def __init__(self):
            self.power = 0
    
        def gravity_field(self):
            if self.power <= 0:
            raise SystemError("Gravity Failing")
    
    
    def grab_handle():
        pass
    
    
    byzantium = Byzantium()
    
    try:
        byzantium.gravity_field()
    except SystemError:
        grab_handle()
        print("Night night")
        raise

    在上面的示例中,我们只是想捕获一些实体 ( grab_handle()) 并打印一条附加消息,然后让异常继续raise抛出. 当我们重新引发异常时,我们说它冒泡了。

    Night night
    Traceback (most recent call last):
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/byzantium.py", line 18, in 
        byzantium.gravity_field()
      File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/byzantium.py", line 8, in gravity_field
        raise SystemError("Gravity Failing")
    SystemError: Gravity Failing

    注意:你可能认为我们需要说except SystemError as e:或者说raise e什么,但那是矫枉过正。对于冒泡的异常,我们只需要自己调用raise。

    现在,如果我们想在冒泡异常的同时添加一些额外的信息怎么办?你的第一个猜测可能只是完全引发一个新异常,但这会带来一些问题。为了演示,我将在执行顺序中添加另一层。请注意,当我处理这个问题时SystemError,我会提出一个新的RuntimeError。我在第二个try...except区块中发现了这个新异常。

    byzantium = Byzantium()
    
    def test():
        try:
            byzantium.gravity_field()
        except SystemError:
            grab_handle()
            raise RuntimeError("Night night")
    
    try:
        test()
    except RuntimeError as e:
        print(e)
        print(e.__cause__)

    当我们运行它时,我们得到以下输出。

    Night night
    None

    当我们捕获到这个新异常时,我们完全没有关于它是什么原因的上下文。为了解决这个问题,Python 3在PEP 3134中引入了显式异常链接。实现它很容易。看看我们的新函数test(),这是我与上一个示例相比唯一更改的部分。

    byzantium = Byzantium()
    
    def test():
        try:
            byzantium.gravity_field()
        except SystemError as e:
            grab_handle()
            raise RuntimeError("Night night") from e
    
    try:
        test()
    except RuntimeError as e:
        print(e)
        print(e.__cause__)

    你有没有发现我在那儿做什么?在except声明中,我将名称绑定e到我们捕获的原始异常。然后,在引发新RuntimeError异常时,我将其链接到上一个异常,并使用from e. 我们现在的输出...

    Night night
    Gravity Failing

    当我们运行它时,我们的新异常会记住它是从哪里来的——前一个异常存储在它的__cause__属性中(打印在输出的第二行)。这对于日志记录特别有用。

    你可以使用异常类执行许多其他技巧,尤其是在引入 PEP 3134 时。像往常一样,我建议你阅读文档,我在文章末尾链接到该文档。

    自定义异常

    Python 有一大堆异常,它们的使用有据可查。当我为工作选择合适的异常时,我经常参考这个异常列表。然而,有时,我们只需要更多……定制的东西。

    所有错误类型的异常都是从Exception类派生的,而类又是从BaseException类派生的。这种双重层次结构的原因是你可以捕获所有错误Exceptions,而无需对特殊的、非系统退出的异常(如KeyboardInterrupt. 当然,这在实践中对你来说并不重要,因为except Exception实际上总是我之前提到的反模式的另一种形式。无论如何,不建议你直接派生自BaseException——只要知道它存在即可。

    在进行自定义异常时,你实际上可以从任何你喜欢的异常类派生。有时,最好从与你正在自定义的异常最接近的异常中获取。但是,如果你不知所措,你可以从Exception派生.

    让我们自定义一个,好吗?

    class SpacetimeError(Exception):
        def __init__(self, message):
            super().__init__(message)
    
    class Tardis():
    
        def __init__(self):
            self._destination = ""
            self._timestream = []
    
        def cloister_bell(self):
            print("(Ominous bell tolling)")
    
        def dematerialize(self):
            self._timestream.append(self._destination)
            print("(Nifty whirring sound)")
    
        def set_destination(self, dest):
            if dest in self._timestream:
                self.cloister_bell()
            self._destination = dest
    
        def engage(self):
            if self._destination in self._timestream:
                raise SpacetimeError("You should not cross your own timestream!")
            else:
                self.dematerialize()
    
    
    tardis = Tardis()
    
    # Should be fine
    tardis.set_destination("7775/349x10,012/acorn")
    tardis.engage()
    
    # Also fine
    tardis.set_destination("5136/161x298,58/delta")
    tardis.engage()
    
    # The TARDIS is not going to like this...
    tardis.set_destination("7775/349x10,012/acorn")
    tardis.engage()

    显然,最后一个将导致我们的SpacetimeError异常被引发。

    让我们再看看那个异常类声明。

    class SpacetimeError(Exception):
        def __init__(self, message):
            super().__init__(message)

    这实际上非常容易编写。如果你还记得我们之前对类的探索,super().__init__()就是在基类上调用初始化函数,Exception在这种情况下就是这样。我们将消息传递给SpacetimeError异常构造函数,并将其交给基类初始化函数。

    事实上,如果我唯一要做的就是将 传递message给super(), 类,我可以让这更简单:

    class SpacetimeError(Exception):
        pass

    Python 自己处理基础异常。

    这就是我们需要做的所有事情,尽管像往常一样,我们可以用这个做更多的技巧。自定义异常不仅仅是一个漂亮的名字;我们可以使用它们来处理各种不寻常的错误场景,尽管这显然超出了本指南的范围。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python
    相关文章 更多
    python删除一个列表里的重复元素的方法与代码示例
    python删除一个列表里的重复元素的方法与代码示例

    学习如何使用Python高效删除列表中的重复元素。本文提供5种常见方法的代码示例,涵盖保持顺序与不保持顺序的场景,适合初学者和进阶开发者参考。

    Python写接口的步骤及完整代码示例
    Python写接口的步骤及完整代码示例

    详细讲解使用Python编写Web接口的核心步骤与完整代码示例,涵盖环境准备、路由定义、数据校验、服务启动及调试测试方法。

    codex怎么读取word文档及docx文件操作教程
    codex怎么读取word文档及docx文件操作教程

    介绍如何利用编程工具读取和解析Word文档(docx格式),涵盖基础文本提取代码示例、结构化数据处理逻辑,以及处理复杂排版时的技术局限与替代方案。

    怎么在Python中调用C语言代码提升性能
    怎么在Python中调用C语言代码提升性能

    详细讲解在Python中调用C语言代码提升性能的完整实践指南,包含原理分析、编译步骤、ctypes与CFFI具体实现、性能对比及常见陷阱。

    Python与C语言的性能差异及底层原理
    Python与C语言的性能差异及底层原理

    深入解析Python与C语言在执行效率上的数量级差异,从编译机制、变量内存布局、动态类型推断到GIL锁,系统阐明底层核心原理。

    Python和C语言哪个更适合编程入门
    Python和C语言哪个更适合编程入门

    客观对比Python与C语言在心智负担、底层机制与学习反馈上的核心差异,提供清晰有据的选择标准与切实的入门学习路径。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    langgraph python guide中文入门教程详解
    langgraph python guide中文入门教程详解

    本篇LangGraph Python中文入门教程详解,系统梳理StateGraph状态机定义、节点编写、边与条件路由、检查点持久化(MemorySaver)等核心机制,提供从环境安装到完整循环智能体构建的代码示例与实操指导。

    Windows 安装 Python:从官方入口到虚拟环境的可复现实践
    Windows 安装 Python:从官方入口到虚拟环境的可复现实践

    面向后端开发者,基于 Python 官方文档说明如何在 Windows 上安装 Python、创建 venv 虚拟环境及使用 pip 管理依赖。包含可复制命令、验证方法及工具选择边界,避免常见配置误区。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。