让我们首先考虑正方形和长方形。如果我们认为在接口方面,忽略了实现细节,方块是否是矩形的子类型?
子类型的定义取决于Liskov代换原理。为了成为一个子类型,它必须能够完成超级类型所做的一切。
如何定义矩形的接口?
zope.interface import Interface class IRectangleInterface: get_length: """Squares can do that""" get_width: """Squares can do that""" set_dimensions length width: """Uh oh"""
如果这是定义,则方块不能是矩形的子类型;它们不能响应set_dimensions方法,如果长度和宽度不同。
另一种方法是选择制作矩形。不变.
class IRectangleInterface: get_length: """Squares can do that""" get_width: """Squares can do that""" with_dimensions length width: """Returns a new rectangle"""
现在,一个正方形可以是一个矩形。它可以返回一个新的矩形(通常不是正方形)with_dimensions被称为,但它不会停止成为一个正方形。
这似乎是一个学术问题-直到我们考虑到,从某种意义上说,正方形和长方形是它们两边的容器。在我们理解了这个例子之后,更实际的情况是使用更传统的容器。例如,考虑随机访问数组.
我们有ISquare和IRectangle,和ISquare是IRectangle.
我们希望在随机访问数组中放置矩形:
class IArrayOfRectanglesInterface: get_element i: """Returns Rectangle""" set_element i rectangle: """'rectangle' can be any IRectangle"""
我们也想把正方形放在一个随机存取数组中:
class IArrayOfSquareInterface: get_element i: """Returns Square""" set_element i square: """'square' can be any ISquare"""
即使ISquare是IRectangle,任何数组都不能实现这两者。IArrayOfSquare和IArrayOfRectangle.
为什么不行"htmlcode">
> rectangle make_rectangle > bucket.set_element rectangle # This is allowed by IArrayOfRectangle > thing bucket.get_element # That has to be a square by IArrayOfSquare > assert thing.height thing.width Traceback most recent call last: File "<stdin>" line module AssertionError
两者都不能实现,这意味着两者都不是另一种类型的子类型,尽管ISquare是IRectangle。问题是set_element方法:如果我们有一个只读数组,IArrayOfSquare的子类型IArrayOfRectangle.
可变性,都是可变的。IRectangle接口和可变IArrayOf接口使得对类型和子类型的思考变得更加困难-而放弃的能力意味着我们期望类型之间的直观关系实际上仍然有效。
突变也可以非局部效果。当两个地方之间的共享对象被一个突变时,就会发生这种情况。典型的例子是一个线程与另一个线程交互一个共享对象,但是即使在一个单线程程序中,在相距很远的地方之间共享也很容易。考虑到在Python中,大多数对象都可以从许多地方访问:作为一个模块全局,或者在堆栈跟踪中,或者作为一个类属性。
如果我们不能限制共享,我们可能会考虑限制可变。
下面是一个不可变的矩形,它利用AutoS库:
attr.frozen class Rectangeobject: length attr. width attr. classmethod with_dimensionscls length width: return clslength width
这里是一个正方形:
attr.frozen class Squareobject: side attr. classmethod with_dimensionscls length width: return Rectanglelength width
使用frozen参数,我们可以很容易地创建一个不可变的类。所有艰苦的写作工作__setitem__正确的做法是别人做的,对我们来说是完全看不见的。
修改对象仍然是容易的,改变它们几乎是不可能的
too_long Rectangle reasonable attr.evolvetoo_long length
可靠的包装允许我们有不可变的容器
# Vector of integers a = pyrsistent.v(1, 2, 3) # Not a vector of integers b = a.set(1, "hello")
当b不是整数的向量,任何东西都不会停止。a从成为一个。
万一a一百万个元素长了吗?是b要复制999 999份吗?Pyrsistent附带“大O”性能保证:所有操作都采用O(log n)时间到了。它还附带了一个可选的C扩展,以提高性能超越大O。
为了修改嵌套对象,它附带了“转换器”的概念:
blog pyrsistent. title"My blog" linkspyrsistent."github" "twitter" postspyrsistent. pyrsistent.title"no updates" content"I'm busy" pyrsistent.title"still no updates" content"still busy" new_blog blog.transform"posts" "content" "pretty busy"
new_blog将成为不可变的等价物。
'links': 'github' 'twitter' 'posts': 'content': "I'm busy" 'title': 'no updates' 'content': 'pretty busy' 'title': 'still no updates' 'title': 'My blog'
但blog还是一样的。这意味着任何引用旧对象的人都没有受到影响:转换只有本土化效果。
当分享猖獗时,这是有用的。例如,考虑默认参数:
silly_suma b extrav : extra extra.extenda b return extra
在这篇文章中,我们了解了为什么不变性对于思考我们的代码是有用的,以及如何在没有昂贵的性能代价的情况下实现它。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。如果你想了解更多相关内容请查看下面相关链接
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。