是否有 Python2 的任何实现,其中排序是可传递的?
Is there any implementation of Python2 where ordering is transitive?
是否有 Python2 的现有实现,其中排序是 transitive?也就是说,如果不创建用户定义的类型就不可能看到这种行为:
>>> x < y < z < x
True
由于这个反例,CPython 是不可传递的
x = 'b'
y = ()
z = u'ab'
但是,CPython 中的这种排序 documented 只是一个实现细节。
除了 Skulpt 之外,每个主流 Python 实现都以某种方式失败,但可以说它是一个不完整的实现。
CPython(和变体)、PyPy 和 Jython:
>>> 'b' < () < u'ab' < 'b'
True
铁Python:
IronPython 在内部比较不同对象的 .NET Object.GetHashCode()
哈希值,因此您可以通过滥用 int
和 float
比较的特殊处理来破坏它,并且float('+inf')
的内部散列表示小于 []
的散列这一事实(我不确定这有多稳定,所以它可能不适用于 IronPython 的每个安装):
>>> 2**200 < float('+inf') < [] < 2**200
True
>>> {1: 3} < {1: 4} < {1: 3}
1
>>> {1: 3} < {1: 3}
0
骷髅
如果您将 Skulpt 算作 Python 2 的完整实现(它无法比较字典和其他一些不方便的类型,并且没有 unicode
类型),它实际上通过复制 CPython 的比较规则并方便地省略 unicode
类型来工作:
# 1. None is less than anything
# 2. Sequence types are greater than numeric types
# 3. [d]ict < [l]ist < [s]tring < [t]uple
>>> None < 0 < {} < [] < '' < ()
True
对于 CPython 2,您实际上会有 [t]uple < [u]nicode
,但是因为 unicode
和 str
比较是作为特殊情况处理的,所以您失去了传递性。尽管 Python 2 不太可能获得修复此问题的补丁 "bug",但我认为您可以通过显式更改以下顺序来确保传递性:
[d]ict < [l]ist < [s]tring < [t]uple < [u]nicode
收件人:
[u]nicode < [d]ict < [l]ist < [s]tring < [t]uple
这样,str
与 unicode
比较的特殊情况不会破坏任何东西。
在 Python 2.7:
中未指定 一些比较
最重要的一般比较规则在
The Python Language Reference chapter 5. Expressions / 5.9 Comparisons。
第一个规则是用于比较数字类型(bool、int、long、float)、字符串(str、unicode)、元组和列表的众所周知的规则。最后两条规则声明什么没有指定:
- Mappings (dictionaries) compare equal if and only if their sorted (key, value) lists compare equal. [5] Outcomes other than equality are resolved consistently, but are not otherwise defined. [6]
- Most other objects of built-in types compare unequal unless they are the same object; the choice whether one object is considered smaller or larger than another one is made arbitrarily but consistently within one execution of a program.
许多具体规则在Python标准库/内置的比较章节Types,在上面的问题中引用,在关于特定类型的文档中,如 complex、Decimal 或 Fraction .
类型 complex 不支持顺序比较,它应该引发 TypeError。 十进制类型按值比较。自 Python 2.7 起,它与 numbers.Number 兼容。 fractions.Fraction也是按值比较的
我的反思:如果一个比较关系可以是任意的并且在同一台计算机上的程序的两次执行中是不可重现的,那么谈论它是没有用的传递性。 Python 2 中未明确指定顺序的所有情况都应在 Python 3 中引发 TypeError。
已知内置类型的传递性或排序在 Python 2.7 中仅在实现了不同内置类型的值等效但未实现与其他类型等效的类型之间被破坏。
示例:IronPython 中的传递性中断(受 Blender 的评论启发并进行了简化):
>>> assert long(0) < 1.0 < [] < long(0) # 0 < 1; 'float' < 'list' < 'long'
即使是看起来更容易决定的等价关系 (==
) 也不 总是可传递的。这打破了运算符的传递性 (<=
)。请参阅评论中的示例。 (感谢修复)(等价不是身份。a is b
意味着 a == b
,但反之亦然。)
示例使用许多简单的用户定义 类,名称为单字母大写或小写:
class A(object): pass
class a(object): pass
...
class z(object): pass
观察 - 数字
所有数字类型在 CPython 和 IronPython 中都有许多自然等价的值(根据文档可能在所有其他实现中)
>>> assert (False == 0 == 0L == 0.0 == 0 + 0j == Decimal('0') == Fraction(0, 1) <
... True == 1 == 1L == 1.0 == 1 + 0j == Decimal('1') == Fraction(1, 1))
在 CPython:
中,数字类型排在所有其他类型之前
>>> assert 0 < 10**1000 < float('inf') < A() < Z() < a()
Iron 中数值类型分散在其他类型之间Python
>>> assert D() < decimal.Decimal('0') < E()
>>> assert F() < fractions.Fraction(0, 1) < G()
>>> assert b() < False < c() # bool
>>> assert c() < 0 + 0j < d() # complex
>>> assert f() < 0.0 < g() # float
>>> assert i() < 0 < j() # int
>>> assert l() < 0L < m() # long
字符串等
str、bytearray 和 unicode 具有相同的值
>>> assert bytearray('ab') == 'ab' == u'ab'
在 CPython,
中没有使用其他类型的特殊命令
>>> assert b() < bytearray('ab') < c() # bytearray
>>> assert s() < 'ab' < t() # str
>>> assert u() < u'ab' < v() # unicode in CPython
在 IronPython 中:类型 unicode
的行为类似于 str
。这并不奇怪,因为字符串像 unicode 一样在 .NET 中实现,在 IronPython.
中也是如此
>>> assert s() < u'ab' < t() # unicode in Iron Python like str
>>> unicode
<type 'str'>
是否有 Python2 的现有实现,其中排序是 transitive?也就是说,如果不创建用户定义的类型就不可能看到这种行为:
>>> x < y < z < x
True
由于这个反例,CPython 是不可传递的
x = 'b'
y = ()
z = u'ab'
但是,CPython 中的这种排序 documented 只是一个实现细节。
除了 Skulpt 之外,每个主流 Python 实现都以某种方式失败,但可以说它是一个不完整的实现。
CPython(和变体)、PyPy 和 Jython:
>>> 'b' < () < u'ab' < 'b'
True
铁Python:
IronPython 在内部比较不同对象的 .NET Object.GetHashCode()
哈希值,因此您可以通过滥用 int
和 float
比较的特殊处理来破坏它,并且float('+inf')
的内部散列表示小于 []
的散列这一事实(我不确定这有多稳定,所以它可能不适用于 IronPython 的每个安装):
>>> 2**200 < float('+inf') < [] < 2**200
True
>>> {1: 3} < {1: 4} < {1: 3}
1
>>> {1: 3} < {1: 3}
0
骷髅
如果您将 Skulpt 算作 Python 2 的完整实现(它无法比较字典和其他一些不方便的类型,并且没有 unicode
类型),它实际上通过复制 CPython 的比较规则并方便地省略 unicode
类型来工作:
# 1. None is less than anything
# 2. Sequence types are greater than numeric types
# 3. [d]ict < [l]ist < [s]tring < [t]uple
>>> None < 0 < {} < [] < '' < ()
True
对于 CPython 2,您实际上会有 [t]uple < [u]nicode
,但是因为 unicode
和 str
比较是作为特殊情况处理的,所以您失去了传递性。尽管 Python 2 不太可能获得修复此问题的补丁 "bug",但我认为您可以通过显式更改以下顺序来确保传递性:
[d]ict < [l]ist < [s]tring < [t]uple < [u]nicode
收件人:
[u]nicode < [d]ict < [l]ist < [s]tring < [t]uple
这样,str
与 unicode
比较的特殊情况不会破坏任何东西。
在 Python 2.7:
中未指定 一些比较最重要的一般比较规则在 The Python Language Reference chapter 5. Expressions / 5.9 Comparisons。
第一个规则是用于比较数字类型(bool、int、long、float)、字符串(str、unicode)、元组和列表的众所周知的规则。最后两条规则声明什么没有指定:
- Mappings (dictionaries) compare equal if and only if their sorted (key, value) lists compare equal. [5] Outcomes other than equality are resolved consistently, but are not otherwise defined. [6]
- Most other objects of built-in types compare unequal unless they are the same object; the choice whether one object is considered smaller or larger than another one is made arbitrarily but consistently within one execution of a program.
许多具体规则在Python标准库/内置的比较章节Types,在上面的问题中引用,在关于特定类型的文档中,如 complex、Decimal 或 Fraction .
类型 complex 不支持顺序比较,它应该引发 TypeError。 十进制类型按值比较。自 Python 2.7 起,它与 numbers.Number 兼容。 fractions.Fraction也是按值比较的
我的反思:如果一个比较关系可以是任意的并且在同一台计算机上的程序的两次执行中是不可重现的,那么谈论它是没有用的传递性。 Python 2 中未明确指定顺序的所有情况都应在 Python 3 中引发 TypeError。
已知内置类型的传递性或排序在 Python 2.7 中仅在实现了不同内置类型的值等效但未实现与其他类型等效的类型之间被破坏。
示例:IronPython 中的传递性中断(受 Blender 的评论启发并进行了简化):
>>> assert long(0) < 1.0 < [] < long(0) # 0 < 1; 'float' < 'list' < 'long'
即使是看起来更容易决定的等价关系 (==
) 也不 总是可传递的。这打破了运算符的传递性 (<=
)。请参阅评论中的示例。 (感谢修复)(等价不是身份。a is b
意味着 a == b
,但反之亦然。)
示例使用许多简单的用户定义 类,名称为单字母大写或小写:
class A(object): pass
class a(object): pass
...
class z(object): pass
观察 - 数字
所有数字类型在 CPython 和 IronPython 中都有许多自然等价的值(根据文档可能在所有其他实现中)
>>> assert (False == 0 == 0L == 0.0 == 0 + 0j == Decimal('0') == Fraction(0, 1) <
... True == 1 == 1L == 1.0 == 1 + 0j == Decimal('1') == Fraction(1, 1))
在 CPython:
中,数字类型排在所有其他类型之前>>> assert 0 < 10**1000 < float('inf') < A() < Z() < a()
Iron 中数值类型分散在其他类型之间Python
>>> assert D() < decimal.Decimal('0') < E()
>>> assert F() < fractions.Fraction(0, 1) < G()
>>> assert b() < False < c() # bool
>>> assert c() < 0 + 0j < d() # complex
>>> assert f() < 0.0 < g() # float
>>> assert i() < 0 < j() # int
>>> assert l() < 0L < m() # long
字符串等
str、bytearray 和 unicode 具有相同的值
>>> assert bytearray('ab') == 'ab' == u'ab'
在 CPython,
中没有使用其他类型的特殊命令>>> assert b() < bytearray('ab') < c() # bytearray
>>> assert s() < 'ab' < t() # str
>>> assert u() < u'ab' < v() # unicode in CPython
在 IronPython 中:类型 unicode
的行为类似于 str
。这并不奇怪,因为字符串像 unicode 一样在 .NET 中实现,在 IronPython.
>>> assert s() < u'ab' < t() # unicode in Iron Python like str
>>> unicode
<type 'str'>