任何修补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
在数据库表中插入主键时,为什么将负id或零视为不良做法?
我认为它在某些情况下可能有用,但是人们说它不推荐,尽管它们从不说/知道为什么.
所以,我想知道是否存在,根据定义,是否有一些限制,或者它是否应该没有任何问题,或者它是否仅仅是一个约定,如果真的存在一些限制,为什么不阻止该功能?
database database-design primary-key identifier least-astonishment
此方法搜索第一组单词字符(即:)[a-zA-Z0-9_]
,返回第一个匹配的组或None
出现故障.
def test(str):
m = re.search(r'(\w+)', str)
if m:
return m.group(1)
return None
Run Code Online (Sandbox Code Playgroud)
相同的功能可以改写为:
def test2(str):
m = re.search(r'(\w+)', str)
return m and m.group(1)
Run Code Online (Sandbox Code Playgroud)
这工作原理相同,并且是记录在案的行为; 作为此页中明确指出:
表达式
x and y
首先评估x
; 如果x
为false,则返回其值; 否则,y
将评估并返回结果值.
但是,作为一个布尔运算符(它甚至在手册上都这么说),我期望and
返回一个布尔值.结果,当我发现(如何)这有效时,我感到很惊讶.
有什么其他用例,和/或这种相当不直观的实现的理由是什么?
(与PropertyInfo SetValue和nulls相关)
如果我有public class Thing { public int X; }
,a Thing o
和a FieldInfo fi
指向该X
字段,为什么打电话合法fi.SetValue(o, null)
?运行时将字段X
设置为零,即default(int)
不是抱怨a ValueType
不能设置为null
.
有没有人知道这种行为背后的设计选择,至少从C#中违背了我最不惊讶的原则?
我有些偶然地发现,您可以使用设置对象的“非法”属性setattr
。非法是指__getattr__
具有传统.
操作员引用的接口无法检索的名称属性。它们只能通过getattr
方法检索。
在我看来,这似乎非常令人惊讶,我想知道是否有这个原因,或者只是被忽略了,等等。由于存在用于检索属性的运算符和setattribute
接口的标准实现,所以我希望它仅允许实际上可以正常检索的属性名称。而且,如果出于某些奇怪的原因想要具有无效名称的属性,则必须为它们实现自己的接口。
我一个人会为这种行为感到惊讶吗?
class Foo:
"stores attrs"
foo = Foo()
setattr(foo, "bar.baz", "this can't be reached")
dir(foo)
Run Code Online (Sandbox Code Playgroud)
这将返回既奇怪又有点误导的东西:
[...'__weakref__', 'bar.baz']
而且,如果我想以“标准”方式访问foo.bar.baz,则不能。无法检索它是很有意义的,但是设置它的能力令人惊讶。
foo.bar.baz
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'bar'
Run Code Online (Sandbox Code Playgroud)
是否只是假设,如果必须使用setattr
来设置变量,您将通过引用它getattr
?因为在运行时,这可能并不总是正确的,尤其是使用Python的交互式解释器,反射等时。默认情况下允许这样做仍然很奇怪。
编辑:我希望看到的作为setattr的默认实现的一个(非常粗糙的)示例:
import re
class Safe:
"stores attrs"
def __setattr__(self, attr, value):
if not re.match(r"^\w[\w\d\-]+$", attr):
raise AttributeError("Invalid characters in attribute name")
else:
super().__setattr__(attr, …
Run Code Online (Sandbox Code Playgroud) 想知道在多层应用程序结构中设置默认值的最佳方法。具体来说,如果某个工作流程需要一组嵌套的函数调用,那么默认值是在所有函数上指定,还是仅在顶层函数上指定并向下传递?或者完全是其他模式?
例如,考虑一个具有 3 层的 Web 应用程序:
假设客户端想要获取一个对象——对于这个例子,假设它是一个Place
对象。地点对象有type
——城市、州、城镇、县等。
资源函数可能如下所示(使用 Django HTTP 对象):
def resource_get_place(request, type=None):
""" Gets a place of the specified type, or a place of any type if
type is None """
place = business_get_place(type=type)
return HttpResponse(request, {
"place" : place
}
Run Code Online (Sandbox Code Playgroud)
那么另外两个可能是:
def business_get_place(type):
# Trivial in this case, used for consistency
return data_get_place(type)
def data_get_place(type):
# Get a place of specified type from the cache, or db,
# …
Run Code Online (Sandbox Code Playgroud) python ×3
.net ×1
architecture ×1
clr ×1
database ×1
default ×1
dry ×1
identifier ×1
primary-key ×1
three-tier ×1