任何修补Python足够长的人都被以下问题咬伤(或撕成碎片):
def foo(a=[]):
a.append(5)
return a
Run Code Online (Sandbox Code Playgroud)
Python新手希望这个函数总能返回一个只包含一个元素的列表:[5]
.结果却非常不同,而且非常惊人(对于新手来说):
>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()
Run Code Online (Sandbox Code Playgroud)
我的一位经理曾经第一次遇到这个功能,并称其为该语言的"戏剧性设计缺陷".我回答说这个行为有一个潜在的解释,如果你不理解内部,那确实非常令人费解和意想不到.但是,我无法回答(对自己)以下问题:在函数定义中绑定默认参数的原因是什么,而不是在函数执行时?我怀疑经验丰富的行为有实际用途(谁真的在C中使用静态变量,没有繁殖错误?)
编辑:
巴泽克提出了一个有趣的例子.再加上你的大部分评论和特别是Utaal,我进一步阐述了:
>>> def a():
... print("a executed")
... return []
...
>>>
>>> def b(x=a()):
... x.append(5)
... print(x)
...
a executed
>>> b()
[5]
>>> b()
[5, 5]
Run Code Online (Sandbox Code Playgroud)
对我而言,似乎设计决策是相对于放置参数范围的位置:在函数内部还是"与它一起"?
在函数内部进行绑定意味着在调用函数时x
有效地绑定到指定的默认值,而不是定义,这会产生一个深层次的缺陷:def
在某种意义上,该行将是"混合"的(部分绑定)函数对象)将在定义时发生,并在函数调用时发生部分(默认参数的赋值).
实际行为更加一致:执行该行时,该行的所有内容都会得到评估,这意味着在函数定义中.
python language-design least-astonishment default-parameters
为什么Java不包含对无符号整数的支持?
在我看来,这是一个奇怪的遗漏,因为它们允许人们编写不太可能在意外的大输入上产生溢出的代码.
此外,使用无符号整数可以是一种自我文档形式,因为它们表明unsigned int意图保留的值绝不应该是负数.
最后,在某些情况下,无符号整数对于某些操作(例如除法)可能更有效.
包含这些内容的不利之处是什么?
C#编译器要求每当自定义类型定义运算符时==
,它还必须定义!=
(参见此处).
为什么?
我很想知道为什么设计师认为这是必要的,为什么当只有另一个运算符存在时,编译器不能默认为任何一个运算符的合理实现.例如,Lua允许您仅定义相等运算符,而您可以免费获得另一个运算符.C#也可以通过要求你定义==或者两者==和!=然后自动编译缺少的!=运算符来做同样的事情!(left == right)
.
我知道有一些奇怪的角落情况,其中一些实体可能既不平等也不平等(如IEEE-754 NaN),但这些似乎是例外,而不是规则.所以这并不能解释为什么C#编译器设计者将例外规则作为例外.
我已经看到了定义等式运算符的做工不好的情况,然后不等式运算符是一个复制粘贴,每个比较都被反转,每个&&切换到|| (你得到的重点......基本上!(a == b)通过De Morgan的规则扩展).编译器可以通过设计消除这种糟糕的做法,就像Lua的情况一样.
注意:对于运算符<> <=> =也是如此.我无法想象你需要以不自然的方式定义它们的情况.Lua允许您通过前者的否定自然地定义<和<=并定义> =和>.为什么C#不做同样的事情(至少'默认')?
编辑
显然有正当理由允许程序员实现对他们喜欢的平等和不平等的检查.一些答案指向可能很好的情况.
然而,我的问题的核心是为什么在C#中强制要求它通常在逻辑上不必要?
它与.NET接口的设计选择形成鲜明对比,例如Object.Equals
,IEquatable.Equals
IEqualityComparer.Equals
缺少NotEquals
对应物表明框架将!Equals()
对象视为不相等而且就是这样.此外,类Dictionary
和类等方法.Contains()
完全依赖于上述接口,即使定义了运算符也不直接使用运算符.事实上,当ReSharper生成相等成员时,它定义了两者==
并且!=
就其而言,Equals()
即使只是用户选择生成运算符.框架不需要相等运算符来理解对象相等性.
基本上,.NET框架并不关心这些运算符,它只关心几种Equals
方法.要求用户串联定义==和!=运算符的决定纯粹与语言设计有关,而与.NET有关的不是对象语义.
Java 8最有用的功能之一是default
接口上的新方法.基本上有两个原因(可能还有其他原因)为什么会被引入:
Iterator.remove()
Iterable.forEach()
从API设计者的角度来看,我希望能够在接口方法上使用其他修饰符,例如final
.在添加便捷方法时,这将非常有用,可防止在实现类时出现"意外"覆盖:
interface Sender {
// Convenience method to send an empty message
default final void send() {
send(null);
}
// Implementations should only implement this method
void send(String message);
}
Run Code Online (Sandbox Code Playgroud)
如果Sender
是一个类,上面已经是常见的做法:
abstract class Sender {
// Convenience method to send an empty message
final void send() {
send(null);
}
// Implementations should only implement this method
abstract void send(String message);
}
Run Code Online (Sandbox Code Playgroud)
现在,default
并final
有明显矛盾的关键字,但默认关键字本身不会一直严格要求 …
所以这些年来我终于停止了我的脚,并决定"正确"学习JavaScript.语言设计中最令人头疼的元素之一是它的继承实现.有Ruby经验,我很高兴看到闭包和动态打字; 但是对于我的生活来说,无法弄清楚使用其他实例进行继承的对象实例会带来什么好处.
javascript oop inheritance language-design prototype-programming
我刚刚在JavaScript中遇到了一个有趣的情况.我有一个类,其方法使用object-literal表示法定义多个对象.在这些对象中,this
正在使用指针.从程序的行为,我推断出this
指针指的是调用方法的类,而不是文字创建的对象.
这似乎是随意的,尽管这是我期望它工作的方式.这是定义的行为吗?跨浏览器安全吗?有没有任何理由可以解释为什么它超出"规范如此说明"的方式(例如,它是否是一些更广泛的设计决策/哲学的结果)?简化代码示例:
// inside class definition, itself an object literal, we have this function:
onRender: function() {
this.menuItems = this.menuItems.concat([
{
text: 'Group by Module',
rptletdiv: this
},
{
text: 'Group by Status',
rptletdiv: this
}]);
// etc
}
Run Code Online (Sandbox Code Playgroud) 为什么更多主流的静态类型语言不支持返回类型的函数/方法重载?我想不出那样做.通过参数类型支持过载似乎没有那么有用或合理.怎么这么不受欢迎呢?
programming-languages overloading language-design function-calls
我无法理解为什么Python没有sign
函数.它有一个abs
内置(我认为sign
是它的妹妹),但没有sign
.
在python 2.6中甚至有一个copysign
函数(在数学中),但没有符号.copysign(x,y)
当你只能写一个sign
然后copysign
直接从中获取时,为什么还要写一个abs(x) * sign(y)
?后者会更加清晰:x带有y的符号,而对于copysign,你必须记住它的x是否带有y或y的符号,带有x的符号!
显然sign(x)
不提供任何东西cmp(x,0)
,但它也会更具可读性(对于像python这样的高可读性语言,这本来是一个很大的优点).
如果我是一名蟒蛇设计师,那我就是另一种方式:没有cmp
内置,而是一个sign
.当你需要时cmp(x,y)
,你可以做一个sign(x-y)
(或者,甚至更好的非数字的东西,只是一个x> y - 当然这应该需要sorted
接受一个布尔而不是一个整数比较器).这也将更加清晰:正时x>y
(而与cmp
你必须记住公约正值当第一个是大,但它可能是周围的其他方式).当然cmp
,由于其他原因(例如,在排序非数字事物时,或者如果您希望排序稳定,这是不可能使用简单的布尔值)
所以,问题是:为什么Python设计师决定将该sign
功能从语言中删除?为什么麻烦copysign
而不是它的父母sign
呢?
我错过了什么吗?
编辑 - 在彼得汉森评论之后.很公平,你没有使用它,但你没有说你使用python的.在我使用蟒蛇的7年中,我无数次需要它,最后一根是打破骆驼背部的稻草!
是的,你可以通过cmp,但是我需要通过它的90%的时间都是这样的成语,就像
lambda x,y: cmp(score(x),score(y))
用标志就好了.
最后,我希望你同意这sign
会比这更有用copysign
,所以即使我买了你的观点,为什么还要在数学中定义它而不是标志呢?copysign如何比签名更有用?
language-design ×10
javascript ×3
python ×3
java ×2
basic ×1
c# ×1
inheritance ×1
integer ×1
java-8 ×1
jsr335 ×1
oop ×1
overloading ×1
performance ×1
ruby ×1
unsigned ×1
vb6 ×1