标签: python-internals

为什么locals()会返回一个奇怪的自引用列表?

所以我使用locals()来获取函数中的一些参数.很好地工作:

def my_function(a, b):
    print locals().values()

>>> my_function(1,2)
[1, 2]
Run Code Online (Sandbox Code Playgroud)

标准的东西.但现在让我们介绍一下列表理解:

def my_function(a, b):
    print [x for x in locals().values()]

>>> my_function(1,2)
[[...], 1, 2]
Run Code Online (Sandbox Code Playgroud)

EHH?为什么要插入自引用?

python list-comprehension python-2.6 locals python-internals

14
推荐指数
1
解决办法
444
查看次数

模块加载如何在CPython中运行?

模块加载如何在CPython下工作?特别是,用C编写的扩展的动态加载如何工作?我在哪里可以了解到这一点?

我发现源代码本身相当压倒性.我可以看到,可靠的ol' dlopen()和朋友用在支持它的系统上但没有任何大局观,从源代码中解决这个问题需要很长时间.

关于这个主题可以写很多,但据我所知,几乎没有任何内容 - 描述Python语言本身的大量网页使搜索变得困难.一个很好的答案将提供一个相当简短的概述和参考资源,我可以了解更多.

我最关心的是它是如何在类Unix系统上运行的,因为这就是我所知道的但我感兴趣的是如果这个过程在其他地方类似.

为了更具体(但风险假设太多),CPython如何使用模块方法表和初始化函数来"理解"动态加载的C?

python cpython dynamic-loading python-import python-internals

13
推荐指数
1
解决办法
1695
查看次数

为什么类定义总是生成相同的字节码?

说我同意:

#!/usr/bin/env python
# encoding: utf-8

class A(object):
    pass
Run Code Online (Sandbox Code Playgroud)

现在我拆开它:

python -m dis test0.py 
  4           0 LOAD_CONST               0 ('A')
              3 LOAD_NAME                0 (object)
              6 BUILD_TUPLE              1
              9 LOAD_CONST               1 (<code object A at 0x1004ebb30, file "test0.py", line 4>)
             12 MAKE_FUNCTION            0
             15 CALL_FUNCTION            0
             18 BUILD_CLASS         
             19 STORE_NAME               1 (A)
             22 LOAD_CONST               2 (None)
             25 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

现在我在类定义中添加一些语句:

#!/usr/bin/env python
# encoding: utf-8

class A(object):
    print 'hello'
    1+1
    pass
Run Code Online (Sandbox Code Playgroud)

然后我又拆开了:

  4           0 LOAD_CONST               0 ('A')
              3 LOAD_NAME                0 (object)
              6 BUILD_TUPLE …
Run Code Online (Sandbox Code Playgroud)

python bytecode disassembly python-internals

13
推荐指数
1
解决办法
355
查看次数

为什么hash(None)会在不同平台和不同调用中发生变化?

我在Python上使用哈希函数面临一个非常奇怪的行为.当我在Mac OS(10.10)上运行以下命令时,我从不同的调用中获得不同的值.

$ python -c "print hash(None)"
-9223372036579216774
$ python -c "print hash(None)"
-9223372036582852230
Run Code Online (Sandbox Code Playgroud)

另一方面,当我在Ubuntu 14.04上运行相同的东西时,我得到:

$ python -c "print hash(None)"
596615
$ python -c "print hash(None)"
596615
Run Code Online (Sandbox Code Playgroud)

对我来说,看起来,在OS X中,python以某种方式使用内存地址而Ubuntu则不然.从中我可以看出哈希函数可能依赖于实现.但是,它不应该只基于"无"的"价值"吗?这些数字代表什么?为什么即使在相同的python版本上,但在不同的操作系统上它的行为也不同?

python hash python-internals

13
推荐指数
1
解决办法
425
查看次数

为什么天真的字符串连接在一定长度之上变成二次方?

通过重复的字符串连接来构建字符串是一种反模式,但我仍然很好奇为什么它的性能在字符串长度超过大约10**6后从线性切换到二次方:

# this will take time linear in n with the optimization
# and quadratic time without the optimization
import time
start = time.perf_counter()
s = ''
for i in range(n):
    s += 'a'
total_time = time.perf_counter() - start
time_per_iteration = total_time / n
Run Code Online (Sandbox Code Playgroud)

例如,在我的机器上(Windows 10,python 3.6.1):

  • 因为10 ** 4 < n < 10 ** 6,time_per_iteration几乎完全恒定在170±10μs
  • 因为10 ** 6 < n,time_per_iteration几乎是完全线性的,达到520μs n == 10 ** 7.

线性增长time_per_iteration相当于二次增长total_time. …

python cpython python-internals

13
推荐指数
1
解决办法
1019
查看次数

究竟`functools.partial`正在制作什么?

CPython 3.6.4:

from functools import partial

def add(x, y, z, a):
    return x + y + z + a

list_of_as = list(range(10000))

def max1():
    return max(list_of_as , key=lambda a: add(10, 20, 30, a))

def max2():
    return max(list_of_as , key=partial(add, 10, 20, 30))
Run Code Online (Sandbox Code Playgroud)

现在:

In [2]: %timeit max1()
4.36 ms ± 42.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [3]: %timeit max2()
3.67 ms ± 25.9 µs per loop (mean ± std. dev. of …
Run Code Online (Sandbox Code Playgroud)

python performance cpython python-internals functools

13
推荐指数
1
解决办法
736
查看次数

从Python中的__str__方法返回int

我知道,str()方法的目的是返回一个对象的字符串表示,所以我想测试如果我强迫它做其他事情会发生什么.

我创建了一个类和一个对象:

class MyClass(object):

    def __str__(self, a=2, b=3):
        return a + b

mc = MyClass()
Run Code Online (Sandbox Code Playgroud)

我打电话的时候:

print(str(mc))
Run Code Online (Sandbox Code Playgroud)

口译员抱怨说:

TypeError: __str__ returned non-string (type int)
Run Code Online (Sandbox Code Playgroud)

这是完全可以理解的,因为str()方法试图返回int.

但如果我尝试:

print(mc.__str__())
Run Code Online (Sandbox Code Playgroud)

我得到输出:5.

那么为什么解释器允许我在__str__直接调用时返回int ,而不是当我使用str(mc)时 - 正如我所理解的那样 - 也被评估为mc.__str__().

python string cpython python-internals

13
推荐指数
2
解决办法
1184
查看次数

小集合如何存储在内存中?

如果我们看看 50k 元素以下的集合的调整大小行为:

>>> import sys
>>> s = set()
>>> seen = {}
>>> for i in range(50_000):
...     size = sys.getsizeof(s)
...     if size not in seen:
...         seen[size] = len(s)
...         print(f"{size=} {len(s)=}")
...     s.add(i)
... 
size=216 len(s)=0
size=728 len(s)=5
size=2264 len(s)=19
size=8408 len(s)=77
size=32984 len(s)=307
size=131288 len(s)=1229
size=524504 len(s)=4915
size=2097368 len(s)=19661
Run Code Online (Sandbox Code Playgroud)

此模式与一旦集合已满 3/5 后将后备存储大小翻四倍,再加上一些可能恒定的开销是一致的PySetObject

>>> for i in range(9, 22, 2):
...     print(2**i + 216)
... 
728
2264
8408
32984
131288
524504 …
Run Code Online (Sandbox Code Playgroud)

python memory cpython set python-internals

13
推荐指数
1
解决办法
816
查看次数

为什么bytearray不是Python 2中的Sequence?

我看到Python 2和3之间的行为有一种奇怪的差异.

在Python 3中,似乎工作正常:

Python 3.5.0rc2 (v3.5.0rc2:cc15d736d860, Aug 25 2015, 04:45:41) [MSC v.1900 32 b
it (Intel)] on win32
>>> from collections import Sequence
>>> isinstance(bytearray(b"56"), Sequence)
True
Run Code Online (Sandbox Code Playgroud)

但不是在Python 2中:

Python 2.7.10 (default, May 23 2015, 09:44:00) [MSC v.1500 64 bit (AMD64)] on wi
n32
>>> from collections import Sequence
>>> isinstance(bytearray("56"), Sequence)
False
Run Code Online (Sandbox Code Playgroud)

在Python 2.x和3.x的次要版本中,结果似乎是一致的.这是一个已知的错误?它是一个bug吗?这种差异背后有什么逻辑吗?

我实际上更担心C API函数PySequence_Check正确识别类型的对象,PyByteArray_Type因为它暴露了序列协议,通过查看它看起来应该的源代码,但是对这整个事物的任何洞察都是非常受欢迎的.

python bytearray abc python-internals

12
推荐指数
1
解决办法
264
查看次数

为什么在迭代期间修改dict并不总是引发异常?

从迭代中删除项目通常会导致RuntimeError: dictionary changed size during iteration异常:

d = {1: 2}
# exception raised
for k in d:
  del d[k]
Run Code Online (Sandbox Code Playgroud)

更确切地说,删除本身将成功.但是,要进入下一轮迭代,解释器必须调用next(it),it通过之前获得的字典,迭代器在哪里.此时,next()会注意到字典大小发生了变化,并抱怨.

到现在为止还挺好.但是如果我们都删除并添加项目到字典呢?

d = {1: 1}
# no exception raised
for k in d:
  # order of next two lines doesn't matter
  d[k*10] = k*10
  del d[k]
Run Code Online (Sandbox Code Playgroud)

我几乎可以肯定这不安全(文档暗示在迭代期间不允许插入或删除).为什么解释器允许此代码无错运行?

我唯一的猜测是,每当调用insert或delete方法时,检查哪些迭代器无效是太昂贵了.所以dict不要尝试完善提出这个例外.相反,它只是跟踪每个迭代器内部字典的大小,并在实际要求迭代器移动到下一个项目时检查它是否未更改.有没有办法能够以低成本实现全面验证?

python dictionary python-3.x python-internals

12
推荐指数
2
解决办法
539
查看次数