【问题标题】:How to disable @assert in Julia如何在 Julia 中禁用 @assert
【发布时间】:2019-10-09 13:45:01
【问题描述】:

作为一名老 C 程序员,我在代码中使用了很多断言。现在我想全局关闭它们以加快速度。这样做的最佳做法是什么?

【问题讨论】:

  • 这确实是应该加的,但是目前没有这个flag。

标签: julia assert


【解决方案1】:

目前还没有内置选项/命令行标志来全局禁用@asserts(!)。

现在,您可以定义一个 @myassert 宏,根据全局开关,它是无操作或常规 @assert

asserting() = false # when set to true, this will enable all `@myassert`s

macro mayassert(test)
  esc(:(if $(@__MODULE__).asserting()
    @assert($test)
   end))
end

f(x) = @mayassert x < 2 

(取自https://discourse.julialang.org/t/assert-alternatives/24775/14

【讨论】:

    【解决方案2】:

    虽然拥有此功能会很好,但可以通过定义和调度您自己的类型来减少代码中对@asserts 的需求。例如,假设您有一个函数foo(t::TimeType) = t,但您只想接受五分钟的倍数。您可以根据此要求创建新类型:

    using Dates
    
    struct FiveMinuteMultiple
        t::DateTime
    
        function FiveMinuteMultiple(y, m, d, h, mi)
            if mi%5 != 0
                throw(DomainError(m, "the minute argument must be a multiple of 5"))
            end
            new(DateTime(y, m, d, h, mi))
        end
    end
    

    现在您实际上无法创建不是五分钟倍数的FiveMinuteMultiple

    julia> t = FiveMinuteMultiple(2016, 7, 15, 4, 23)
    ERROR: DomainError with 7:
    the minute argument must be a multiple of 5
    Stacktrace:
     [1] FiveMinuteMultiple(::Int64, ::Int64, ::Int64, ::Int64, ::Int64) at ./REPL[2]:5
     [2] top-level scope at none:0
    
    julia> t = FiveMinuteMultiple(2016, 7, 15, 4, 25)
    FiveMinuteMultiple(2016-07-15T04:25:00)
    

    因此,如果您现在定义 foo(t::FiveMinuteMultiple) = t,则不再需要 @assert 来验证参数是五分钟的倍数。当然,当您构造 FiveMinuteMultiple 时,您仍然需要支付参数检查的成本,但除非它是一个热内循环,否则您可能无论如何都需要额外的数据验证。

    优点:

    • 方法分派保证函数的参数类型正确。
    • 您可以避免在多个函数foo(t::FiveMinuteMultiple)bar(t::FiveMinuteMultiple)baz(t::FiveMinuteMultiple) 之间重复相同的断言。
    • 更具体的参数注释会提醒用户和开发人员该函数需要更具体的数据类型。

    缺点:

    • 根据您的用例,您可能需要将各种方法转发到结构中的数据字段。例如,对于FiveMinuteMultiple,您可能需要将dayhour 等方法转发到结构的t 字段。
    • 添加新概念(类型)来表示有关数据的断言可能会引入不必要的抽象层。

    【讨论】:

    • 创建自定义类型以避免断言对我来说似乎有点矫枉过正。我不会引入多个 Float64 包装器类型来替换一堆浮点值断言。
    • 当然这取决于上下文。我认为在某些情况下这种模式是有意义的。一个优点是,更具体的参数注释会提醒用户该函数需要更具体的数据类型。
    • 我使用断言来记录代码中的假设。这些是代码假定“不可能是真的”的事情。这不同于预期的错误,例如 API 的错误参数。所有代码都做出假设,有时它们是错误的。最好测试这些限制,但也可以在发货时全局关闭测试
    • 我不确定“不可能是真的”是什么意思。如果是这种情况,那么您将不需要断言。也许区别在于用户错误和开发人员错误?
    • 断言开发人员在编写代码时所做的文档假设。看到这里写一篇好的文章stackoverflow.com/questions/1081409/why-should-i-use-asserts
    【解决方案3】:

    您可以将@assert 语句放在@debug 块中。然后 @assert 调用将被停用,除非您在全局 (ENV["JULIA_DEBUG"] = "all") 或仅为您的模块 (ENV["JULIA_DEBUG"] = "NameOfYourModule") 激活调试

    julia> @debug begin
              @assert 1==2
           end
           #or 
           @debug @assert 1==2 # assert is not called
    
    julia> ENV["JULIA_DEBUG"] = "all" # enable debugging
    "all"
    
    julia> @debug begin
              @assert 1==2
           end
    ┌ Error: Exception while generating log record in module Main at REPL[4]:1
    │   exception =
    │    AssertionError: 1 == 2
    │    Stacktrace:
    │     [1] top-level scope at REPL[4]:2
    │     [2] top-level scope at logging.jl:319
    |     ...
    └ @ Main REPL[4]:1
    

    【讨论】:

    • 不幸的是,违反断言不再导致程序终止,而是日志消息Error: Exception while generating log record in module
    猜你喜欢
    • 2011-07-18
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多