在Python 3中,列表理解只是语法糖,用于生成list函数的生成器表达式?
例如是以下代码:
squares = [x**2 for x in range(1000)]
Run Code Online (Sandbox Code Playgroud)
实际上在后台转换成以下内容?
squares = list(x**2 for x in range(1000))
Run Code Online (Sandbox Code Playgroud)
我知道输出是相同的,并且Python 3修复了列表推导所具有的周围命名空间的令人惊讶的副作用,但就CPython解释器所做的事情而言,前者转换为后者,或者是否有任何区别在如何执行代码?
我发现,在评论部分等价的这一主张这个问题,和快速谷歌搜索显示了同样的要求正在作出这里.
在Python 3.0文档中的新内容中也提到了这一点,但措辞有些含糊:
还要注意,列表推导具有不同的语义:它们更接近于list()构造函数中的生成器表达式的语法糖,特别是循环控制变量不再泄漏到周围的范围中.
python list-comprehension generator-expression python-3.x python-internals
我从Python Github存储库下载了一个Python 3.6 alpha版本,我最喜欢的一个新功能是文字字符串格式化.它可以像这样使用:
>>> x = 2
>>> f"x is {x}"
"x is 2"
Run Code Online (Sandbox Code Playgroud)
这似乎与format在str实例上使用该函数做同样的事情.但是,我注意到的一件事是,与仅调用相比,这种文字字符串格式化实际上非常慢format.以下是timeit关于每种方法的内容:
>>> x = 2
>>> timeit.timeit(lambda: f"X is {x}")
0.8658502227130764
>>> timeit.timeit(lambda: "X is {}".format(x))
0.5500578542015617
Run Code Online (Sandbox Code Playgroud)
如果我使用字符串作为timeit参数,我的结果仍然显示模式:
>>> timeit.timeit('x = 2; f"X is {x}"')
0.5786435347381484
>>> timeit.timeit('x = 2; "X is {}".format(x)')
0.4145195760771685
Run Code Online (Sandbox Code Playgroud)
如您所见,使用format几乎占用了一半的时间.我希望文字方法更快,因为涉及的语法更少.幕后发生了什么导致文字方法如此慢?
可以通过两种方式分割白色空间str.strip.您可以发出不带参数的调用str.strip(),默认情况下使用空格分隔符或自己显式提供参数str.strip(' ').
但是,为什么在定时时这些功能的表现如此不同?
使用具有有意量的空格的示例字符串:
s = " " * 100 + 'a' + " " * 100
Run Code Online (Sandbox Code Playgroud)
时间s.strip()和时间s.strip(' ')分别为:
%timeit s.strip()
The slowest run took 32.74 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 396 ns per loop
%timeit s.strip(' ')
100000 loops, best of 3: 4.5 µs per loop
Run Code Online (Sandbox Code Playgroud)
strip需要396ns而strip(' ')采用4.5 …
Python如何为大整数分配内存?
一个int类型的大小28 bytes和随着我不断增加的值int,大小以增量为单位增加4 bytes.
为什么28 bytes最初的价值低至何1?
为什么增量4 bytes?
PS:我在x86_64(64位机器)上运行Python 3.5.2.关于(3.0+)解释器如何处理如此庞大的数字的任何指针/资源/ PEP都是我正在寻找的.
代码说明尺寸:
>>> a=1
>>> print(a.__sizeof__())
28
>>> a=1024
>>> print(a.__sizeof__())
28
>>> a=1024*1024*1024
>>> print(a.__sizeof__())
32
>>> a=1024*1024*1024*1024
>>> print(a.__sizeof__())
32
>>> a=1024*1024*1024*1024*1024*1024
>>> a
1152921504606846976
>>> print(a.__sizeof__())
36
Run Code Online (Sandbox Code Playgroud) 我的理解yield from是,它类似于yield从可迭代对象中获取每个项目。然而,我在以下示例中观察到不同的行为。
我有Class1
class Class1:
def __init__(self, gen):
self.gen = gen
def __iter__(self):
for el in self.gen:
yield el
Run Code Online (Sandbox Code Playgroud)
和 Class2 的不同之处仅在于yield将 for 循环替换为yield from
class Class2:
def __init__(self, gen):
self.gen = gen
def __iter__(self):
yield from self.gen
Run Code Online (Sandbox Code Playgroud)
下面的代码从给定类的实例中读取第一个元素,然后在 for 循环中读取其余元素:
a = Class1((i for i in range(3)))
print(next(iter(a)))
for el in iter(a):
print(el)
Run Code Online (Sandbox Code Playgroud)
Class1这会为和产生不同的输出Class2。对于Class1输出是
0
1
2
Run Code Online (Sandbox Code Playgroud)
Class2输出为
0
Run Code Online (Sandbox Code Playgroud)
yield from产生不同行为的背后机制是什么?
由于dictPython 3.6 中的实现发生了变化,现在默认排序.现在还set保留秩序吗?
我找不到任何关于它的信息,但由于这两种数据结构在它们工作的方式非常相似,我认为可能就是这种情况.
我知道dict在所有情况下都无法订购s,但它们大多数情况下都是如此.如Python文档中所述:
这个新实现的顺序保留方面被认为是一个实现细节,不应该依赖它
当我尝试print在Python 3.4中使用不带括号的简单名称时,我得到:
>>> print max
Traceback (most recent call last):
...
File "<interactive input>", line 1
print max
^
SyntaxError: Missing parentheses in call to 'print'
Run Code Online (Sandbox Code Playgroud)
好的,现在我明白了,我只是忘了移植我的Python 2代码.
但是现在当我尝试打印函数的结果时:
>>> print max([1,2])
Traceback (most recent call last):
...
print max([1,2])
^
SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)
要么:
print max.__call__(23)
^
SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)
(请注意,在这种情况下,光标指向第一个点之前的字符.)
消息不同(并且稍有误导,因为标记位于max函数下方).
为什么Python不能提前检测到问题?
注意:这个问题的灵感来自于围绕这个问题的困惑:Pandas read.csv语法错误,由于误导性的错误消息,一些Python专家错过了真正的问题.
我有限的大脑无法理解为什么会这样:
>>> print '' in 'lolsome'
True
Run Code Online (Sandbox Code Playgroud)
在PHP中,等效比较返回false:
var_dump(strpos('', 'lolsome'));
Run Code Online (Sandbox Code Playgroud) 对于一些简单的线程相关代码,即:
\nimport threading\n\n\na = 0\nthreads = []\n\n\ndef x():\n global a\n for i in range(1_000_000):\n a += 1\n\n\nfor _ in range(10):\n thread = threading.Thread(target=x)\n threads.append(thread)\n thread.start()\n\n\nfor thread in threads:\n thread.join()\n\n\nprint(a)\nassert a == 10_000_000\nRun Code Online (Sandbox Code Playgroud)\n根据 Python 版本,我们得到了不同的行为。
\n对于 3.10,输出为:
\n\xe2\x9d\xaf python3.10 b.py\n10000000\nRun Code Online (Sandbox Code Playgroud)\n对于 3.9,输出为:
\n\xe2\x9d\xaf python3.9 b.py\n2440951\nTraceback (most recent call last):\n File "/Users/romka/t/threads-test/b.py", line 24, in <module>\n assert a == 10_000_000\nAssertionError\nRun Code Online (Sandbox Code Playgroud)\n由于我们没有获取任何锁,对我来说,3.9 的结果是显而易见的并且是预期的。问题是为什么 3.10 得到了“正确”的结果,而不应该得到“正确”的结果?
\n我正在查看 Python 3.10 的变更日志,没有任何与线程或 GIL 相关的内容可以带来这样的结果。
\npython multithreading python-multithreading python-internals
我认为我的问题与此有关,但并不完全相似.考虑以下代码:
def countdown(n):
try:
while n > 0:
yield n
n -= 1
finally:
print('In the finally block')
def main():
for n in countdown(10):
if n == 5:
break
print('Counting... ', n)
print('Finished counting')
main()
Run Code Online (Sandbox Code Playgroud)
此代码的输出是:
Counting... 10
Counting... 9
Counting... 8
Counting... 7
Counting... 6
In the finally block
Finished counting
Run Code Online (Sandbox Code Playgroud)
是否保证在"完成计数"之前打印"在最后一个块中"这一行?或者这是因为cPython实现细节,当引用计数达到0时,对象将被垃圾收集.
另外我对如何好奇finally的块countdown执行发电机?例如,如果我将代码更改main为
def main():
c = countdown(10)
for n in c:
if n == 5:
break
print('Counting... ', n)
print('Finished …Run Code Online (Sandbox Code Playgroud) python ×10
python-internals ×10
python-3.x ×4
generator ×2
performance ×2
python-3.6 ×2
string ×2
cpython ×1
f-string ×1
int ×1
set ×1
syntax-error ×1
yield ×1
yield-from ×1