<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 問題 作為某種編程規約,你想在對函數參數進行強制類型檢查。 ## 解決方案 在演示實際代碼前,先說明我們的目標:能對函數參數類型進行斷言,類似下面這樣: >>> @typeassert(int, int) ... def add(x, y): ... return x + y ... >>> >>> add(2, 3) 5 >>> add(2, 'hello') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "contract.py", line 33, in wrapper TypeError: Argument y must be <class 'int'> >>> 下面是使用裝飾器技術來實現 `@typeassert` : from inspect import signature from functools import wraps def typeassert(*ty_args, **ty_kwargs): def decorate(func): # If in optimized mode, disable type checking if not __debug__: return func # Map function argument names to supplied types sig = signature(func) bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments @wraps(func) def wrapper(*args, **kwargs): bound_values = sig.bind(*args, **kwargs) # Enforce type assertions across supplied arguments for name, value in bound_values.arguments.items(): if name in bound_types: if not isinstance(value, bound_types[name]): raise TypeError( 'Argument {} must be {}'.format(name, bound_types[name]) ) return func(*args, **kwargs) return wrapper return decorate 可以看出這個裝飾器非常靈活,既可以指定所有參數類型,也可以只指定部分。并且可以通過位置或關鍵字來指定參數類型。下面是使用示例: >>> @typeassert(int, z=int) ... def spam(x, y, z=42): ... print(x, y, z) ... >>> spam(1, 2, 3) 1 2 3 >>> spam(1, 'hello', 3) 1 hello 3 >>> spam(1, 'hello', 'world') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "contract.py", line 33, in wrapper TypeError: Argument z must be <class 'int'> >>> 討論 這節是高級裝飾器示例,引入了很多重要的概念。 首先,裝飾器只會在函數定義時被調用一次。 有時候你去掉裝飾器的功能,那么你只需要簡單的返回被裝飾函數即可。 下面的代碼中,如果全局變量 `__debug__` 被設置成了False(當你使用-O或-OO參數的優化模式執行程序時), 那么就直接返回未修改過的函數本身: def decorate(func): # If in optimized mode, disable type checking if not __debug__: return func 其次,這里還對被包裝函數的參數簽名進行了檢查,我們使用了 `inspect.signature()` 函數。簡單來講,它運行你提取一個可調用對象的參數簽名信息。例如: >>> from inspect import signature >>> def spam(x, y, z=42): ... pass ... >>> sig = signature(spam) >>> print(sig) (x, y, z=42) >>> sig.parameters mappingproxy(OrderedDict([('x', <Parameter at 0x10077a050 'x'>), ('y', <Parameter at 0x10077a158 'y'>), ('z', <Parameter at 0x10077a1b0 'z'>)])) >>> sig.parameters['z'].name 'z' >>> sig.parameters['z'].default 42 >>> sig.parameters['z'].kind <_ParameterKind: 'POSITIONAL_OR_KEYWORD'> >>> 裝飾器的開始部分,我們使用了 `bind_partial()` 方法來執行從指定類型到名稱的部分綁定。下面是例子演示: >>> bound_types = sig.bind_partial(int,z=int) >>> bound_types <inspect.BoundArguments object at 0x10069bb50> >>> bound_types.arguments OrderedDict([('x', <class 'int'>), ('z', <class 'int'>)]) >>> 在這個部分綁定中,你可以注意到缺失的參數被忽略了(比如并沒有對y進行綁定)。不過最重要的是創建了一個有序字典 `bound_types.arguments` 。這個字典會將參數名以函數簽名中相同順序映射到指定的類型值上面去。在我們的裝飾器例子中,這個映射包含了我們要強制指定的類型斷言。 在裝飾器創建的實際包裝函數中使用到了 `sig.bind()` 方法。`bind()` 跟 `bind_partial()` 類似,但是它不允許忽略任何參數。因此有了下面的結果: >>> bound_values = sig.bind(1, 2, 3) >>> bound_values.arguments OrderedDict([('x', 1), ('y', 2), ('z', 3)]) >>> 使用這個映射我們可以很輕松的實現我們的強制類型檢查: >>> for name, value in bound_values.arguments.items(): ... if name in bound_types.arguments: ... if not isinstance(value, bound_types.arguments[name]): ... raise TypeError() ... >>> 不過這個方案還有點小瑕疵,它對于有默認值的參數并不適用。比如下面的代碼可以正常工作,盡管items的類型是錯誤的: >>> @typeassert(int, list) ... def bar(x, items=None): ... if items is None: ... items = [] ... items.append(x) ... return items >>> bar(2) [2] >>> bar(2,3) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "contract.py", line 33, in wrapper TypeError: Argument items must be <class 'list'> >>> bar(4, [1, 2, 3]) [1, 2, 3, 4] >>> 最后一點是關于適用裝飾器參數和函數注解之間的爭論。例如,為什么不像下面這樣寫一個裝飾器來查找函數中的注解呢? @typeassert def spam(x:int, y, z:int = 42): print(x,y,z) 一個可能的原因是如果使用了函數參數注解,那么就被限制了。如果注解被用來做類型檢查就不能做其他事情了。而且 `@typeassert` 不能再用于使用注解做其他事情的函數了。而使用上面的裝飾器參數靈活性大多了,也更加通用。 可以在PEP 362以及 `inspect` 模塊中找到更多關于函數參數對象的信息。在9.16小節還有另外一個例子。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看