<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>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 問題 你想定義某些在屬性賦值上面有限制的數據結構。 ## 解決方案 在這個問題中,你需要在對某些實例屬性賦值時進行檢查。所以你要自定義屬性賦值函數,這種情況下最好使用描述器。 下面的代碼使用描述器實現了一個系統類型和賦值驗證框架: # Base class. Uses a descriptor to set a value class Descriptor: def __init__(self, name=None, **opts): self.name = name for key, value in opts.items(): setattr(self, key, value) def __set__(self, instance, value): instance.__dict__[self.name] = value # Descriptor for enforcing types class Typed(Descriptor): expected_type = type(None) def __set__(self, instance, value): if not isinstance(value, self.expected_type): raise TypeError('expected ' + str(self.expected_type)) super().__set__(instance, value) # Descriptor for enforcing values class Unsigned(Descriptor): def __set__(self, instance, value): if value < 0: raise ValueError('Expected >= 0') super().__set__(instance, value) class MaxSized(Descriptor): def __init__(self, name=None, **opts): if 'size' not in opts: raise TypeError('missing size option') super().__init__(name, **opts) def __set__(self, instance, value): if len(value) >= self.size: raise ValueError('size must be < ' + str(self.size)) super().__set__(instance, value) 這些類就是你要創建的數據模型或類型系統的基礎構建模塊。下面就是我們實際定義的各種不同的數據類型: class Integer(Typed): expected_type = int class UnsignedInteger(Integer, Unsigned): pass class Float(Typed): expected_type = float class UnsignedFloat(Float, Unsigned): pass class String(Typed): expected_type = str class SizedString(String, MaxSized): pass 然后使用這些自定義數據類型,我們定義一個類: class Stock: # Specify constraints name = SizedString('name', size=8) shares = UnsignedInteger('shares') price = UnsignedFloat('price') def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price 然后測試這個類的屬性賦值約束,可發現對某些屬性的賦值違法了約束是不合法的: >>> s.name 'ACME' >>> s.shares = 75 >>> s.shares = -10 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "example.py", line 17, in __set__ super().__set__(instance, value) File "example.py", line 23, in __set__ raise ValueError('Expected >= 0') ValueError: Expected >= 0 >>> s.price = 'a lot' Traceback (most recent call last): File "<stdin>", line 1, in <module> File "example.py", line 16, in __set__ raise TypeError('expected ' + str(self.expected_type)) TypeError: expected <class 'float'> >>> s.name = 'ABRACADABRA' Traceback (most recent call last): File "<stdin>", line 1, in <module> File "example.py", line 17, in __set__ super().__set__(instance, value) File "example.py", line 35, in __set__ raise ValueError('size must be < ' + str(self.size)) ValueError: size must be < 8 >>> 還有一些技術可以簡化上面的代碼,其中一種是使用類裝飾器: # Class decorator to apply constraints def check_attributes(**kwargs): def decorate(cls): for key, value in kwargs.items(): if isinstance(value, Descriptor): value.name = key setattr(cls, key, value) else: setattr(cls, key, value(key)) return cls return decorate # Example @check_attributes(name=SizedString(size=8), shares=UnsignedInteger, price=UnsignedFloat) class Stock: def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price 另外一種方式是使用元類: # A metaclass that applies checking class checkedmeta(type): def __new__(cls, clsname, bases, methods): # Attach attribute names to the descriptors for key, value in methods.items(): if isinstance(value, Descriptor): value.name = key return type.__new__(cls, clsname, bases, methods) # Example class Stock2(metaclass=checkedmeta): name = SizedString(size=8) shares = UnsignedInteger() price = UnsignedFloat() def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price ## 討論 本節使用了很多高級技術,包括描述器、混入類、`super()` 的使用、類裝飾器和元類。不可能在這里一一詳細展開來講,但是可以在8.9、8.18、9.19小節找到更多例子。但是,我在這里還是要提一下幾個需要注意的點。 首先,在 `Descriptor` 基類中你會看到有個 `__set__()` 方法,卻沒有相應的 `__get__()` 方法。如果一個描述僅僅是從底層實例字典中獲取某個屬性值的話,那么沒必要去定義 `__get__()` 方法。 所有描述器類都是基于混入類來實現的。比如 `Unsigned` 和 `MaxSized` 要跟其他繼承自 `Typed` 類混入。這里利用多繼承來實現相應的功能。 混入類的一個比較難理解的地方是,調用 `super()` 函數時,你并不知道究竟要調用哪個具體類。你需要跟其他類結合后才能正確的使用,也就是必須合作才能產生效果。 使用類裝飾器和元類通常可以簡化代碼。上面兩個例子中你會發現你只需要輸入一次屬性名即可了。 # Normal class Point: x = Integer('x') y = Integer('y') # Metaclass class Point(metaclass=checkedmeta): x = Integer() y = Integer() 所有方法中,類裝飾器方案應該是最靈活和最高明的。首先,它并不依賴任何其他新的技術,比如元類。其次,裝飾器可以很容易的添加或刪除。 最后,裝飾器還能作為混入類的替代技術來實現同樣的效果; # Decorator for applying type checking def Typed(expected_type, cls=None): if cls is None: return lambda cls: Typed(expected_type, cls) super_set = cls.__set__ def __set__(self, instance, value): if not isinstance(value, expected_type): raise TypeError('expected ' + str(expected_type)) super_set(self, instance, value) cls.__set__ = __set__ return cls # Decorator for unsigned values def Unsigned(cls): super_set = cls.__set__ def __set__(self, instance, value): if value < 0: raise ValueError('Expected >= 0') super_set(self, instance, value) cls.__set__ = __set__ return cls # Decorator for allowing sized values def MaxSized(cls): super_init = cls.__init__ def __init__(self, name=None, **opts): if 'size' not in opts: raise TypeError('missing size option') super_init(self, name, **opts) cls.__init__ = __init__ super_set = cls.__set__ def __set__(self, instance, value): if len(value) >= self.size: raise ValueError('size must be < ' + str(self.size)) super_set(self, instance, value) cls.__set__ = __set__ return cls # Specialized descriptors @Typed(int) class Integer(Descriptor): pass @Unsigned class UnsignedInteger(Integer): pass @Typed(float) class Float(Descriptor): pass @Unsigned class UnsignedFloat(Float): pass @Typed(str) class String(Descriptor): pass @MaxSized class SizedString(String): pass 這種方式定義的類跟之前的效果一樣,而且執行速度會更快。設置一個簡單的類型屬性的值,裝飾器方式要比之前的混入類的方式幾乎快100%。現在你應該慶幸自己讀完了本節全部內容了吧?^_^
                  <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>

                              哎呀哎呀视频在线观看