我知道".pyc"文件是纯文本".py"文件的编译版本,在运行时创建以使程序运行得更快.但是我发现了一些事情:
rm *.pyc)后,程序行为有时会发生变化.这表明他们没有在".py"更新时编译.问题:
所以只是为了建立,我觉得我理解复制模块中的copyvs 之间的区别deepcopy,我已经使用过copy.copy并且copy.deepcopy成功之前,但这是我第一次真正去重载__copy__和__deepcopy__方法.我已经围绕谷歌搜索,并通过看内置的Python模块查找的实例__copy__和__deepcopy__功能(例如sets.py,decimal.py和fractions.py),但我仍然肯定不是100%我已经得到了它的权利.
这是我的情景:
我有一个配置对象,它主要由简单属性组成(尽管它可能包含其他非基本对象的列表).最初,我将使用一组默认值来实例化一个配置对象.此配置将切换到多个其他对象(以确保所有对象以相同的配置启动).然而,一旦用户交互开始,每个对象将需要能够独立地调整配置而不影响彼此的配置(对我来说,我需要使用我的初始配置的深度复制来处理).
这是一个示例对象:
class ChartConfig(object):
def __init__(self):
#Drawing properties (Booleans/strings)
self.antialiased = None
self.plot_style = None
self.plot_title = None
self.autoscale = None
#X axis properties (strings/ints)
self.xaxis_title = None
self.xaxis_tick_rotation = None
self.xaxis_tick_align = None
#Y axis properties (strings/ints)
self.yaxis_title = None
self.yaxis_tick_rotation = None
self.yaxis_tick_align = None
#A list of non-primitive objects
self.trace_configs = [] …Run Code Online (Sandbox Code Playgroud) 在优化我的代码时,我意识到以下内容:
>>> from timeit import Timer as T
>>> T(lambda : 1234567890 / 4.0).repeat()
[0.22256922721862793, 0.20560789108276367, 0.20530295372009277]
>>> from __future__ import division
>>> T(lambda : 1234567890 / 4).repeat()
[0.14969301223754883, 0.14155197143554688, 0.14141488075256348]
>>> T(lambda : 1234567890 * 0.25).repeat()
[0.13619112968444824, 0.1281130313873291, 0.12830305099487305]
Run Code Online (Sandbox Code Playgroud)
并且:
>>> from math import sqrt
>>> T(lambda : sqrt(1234567890)).repeat()
[0.2597470283508301, 0.2498021125793457, 0.24994492530822754]
>>> T(lambda : 1234567890 ** 0.5).repeat()
[0.15409398078918457, 0.14059877395629883, 0.14049601554870605]
Run Code Online (Sandbox Code Playgroud)
我假设它与C实现python的方式有关,但我想知道是否有人会解释为什么会如此?
这更像是一个概念性问题.我最近在Python中看到了一段代码(它在2.7中工作,也可能在2.5中运行),其中一个for循环对迭代的列表和列表中的项使用相同的名称,这既是一种糟糕的做法,也是一种根本不起作用的东西.
例如:
x = [1,2,3,4,5]
for x in x:
print x
print x
Run Code Online (Sandbox Code Playgroud)
产量:
1
2
3
4
5
5
Run Code Online (Sandbox Code Playgroud)
现在,我觉得打印的最后一个值是从循环中分配给x的最后一个值,但是我不明白为什么你能够为for循环的两个部分使用相同的变量名并且它按预期运作.它们在不同的范围内吗?引擎盖下发生了什么让这样的事情发挥作用?
所以我正在玩list对象,并发现一些奇怪的事情,如果list创建list()它使用更多的内存,而不是列表理解?我正在使用Python 3.5.2
In [1]: import sys
In [2]: a = list(range(100))
In [3]: sys.getsizeof(a)
Out[3]: 1008
In [4]: b = [i for i in range(100)]
In [5]: sys.getsizeof(b)
Out[5]: 912
In [6]: type(a) == type(b)
Out[6]: True
In [7]: a == b
Out[7]: True
In [8]: sys.getsizeof(list(b))
Out[8]: 1008
Run Code Online (Sandbox Code Playgroud)
来自文档:
列表可以通过以下几种方式构建:
- 使用一对方括号表示空列表:
[]- 使用方括号,用逗号分隔项目:
[a],[a, b, c]- 使用列表理解:
[x for x in iterable]- 使用类型构造函数:
list()或list(iterable)
但似乎使用list()它会占用更多内存. …
我遇到了这种奇怪的行为并且无法解释它.这些是基准:
py -3 -m timeit "tuple(range(2000)) == tuple(range(2000))"
10000 loops, best of 3: 97.7 usec per loop
py -3 -m timeit "a = tuple(range(2000)); b = tuple(range(2000)); a==b"
10000 loops, best of 3: 70.7 usec per loop
Run Code Online (Sandbox Code Playgroud)
为什么与变量赋值的比较比使用临时变量的单个衬里快27%以上?
通过Python文档,在timeit期间禁用垃圾收集,因此它不可能.这是某种优化吗?
结果也可以在Python 2.x中重现,但程度较小.
运行Windows 7,CPython 3.5.1,Intel i7 3.40 GHz,64位操作系统和Python.看起来像我尝试在Intel i7 3.60 GHz上使用Python 3.5.0运行的另一台机器不能重现结果.
使用与timeit.timeit()@ 10000循环相同的Python进程运行分别产生0.703和0.804.仍显示尽管程度较轻.(〜12.5%)
深入研究Python的源代码后,我发现它维护了一个PyInt_Objects 数组,范围从int(-5)到int(256)(@src/Objects/intobject.c)
一个小实验证明了这一点:
>>> a = 1
>>> b = 1
>>> a is b
True
>>> a = 257
>>> b = 257
>>> a is b
False
Run Code Online (Sandbox Code Playgroud)
但是如果我在py文件中一起运行这些代码(或者用分号连接它们),结果会有所不同:
>>> a = 257; b = 257; a is b
True
Run Code Online (Sandbox Code Playgroud)
我很好奇为什么它们仍然是同一个对象,所以我深入研究语法树和编译器,我想出了一个下面列出的调用层次结构:
PyRun_FileExFlags()
mod = PyParser_ASTFromFile()
node *n = PyParser_ParseFileFlagsEx() //source to cst
parsetoke()
ps = PyParser_New()
for (;;)
PyTokenizer_Get()
PyParser_AddToken(ps, ...)
mod = PyAST_FromNode(n, ...) //cst to ast
run_mod(mod, ...)
co = PyAST_Compile(mod, ...) //ast to CFG …Run Code Online (Sandbox Code Playgroud) import sys
x = 'ñ'
print(sys.getsizeof(x))
int(x) #throws an error
print(sys.getsizeof(x))
Run Code Online (Sandbox Code Playgroud)
我们得到74,然后是两个getsizeof调用的77个字节.
看起来我们正在从失败的int调用中向对象添加3个字节.
来自twitter的更多示例(您可能需要重新启动python以将大小重置为74):
x = 'ñ'
y = 'ñ'
int(x)
print(sys.getsizeof(y))
Run Code Online (Sandbox Code Playgroud)
77!
print(sys.getsizeof('ñ'))
int('ñ')
print(sys.getsizeof('ñ'))
Run Code Online (Sandbox Code Playgroud)
74,然后77.
试图理解 Python for 循环,我认为这会给出{1}一次迭代的结果,或者只是陷入无限循环,这取决于它是否像在 C 或其他语言中那样进行迭代。但实际上两者都没有。
>>> s = {0}
>>> for i in s:
... s.add(i + 1)
... s.remove(i)
...
>>> print(s)
{16}
Run Code Online (Sandbox Code Playgroud)
为什么要进行 16 次迭代?结果{16}从何而来?
这是使用 Python 3.8.2。在 pypy 上,它产生了预期的结果{1}。
为什么你不能*args在Python中使用尾随逗号?换句话说,这是有效的
>>> f(1, 2, b=4,)
Run Code Online (Sandbox Code Playgroud)
但事实并非如此
>>> f(*(1, 2), b=4,)
File "<stdin>", line 1
f(*(1, 2), b=4,)
^
SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)
Python 2和Python 3都是这种情况.
python ×10
python-internals ×10
cpython ×2
python-3.x ×2
c ×1
caching ×1
for-loop ×1
list ×1
literals ×1
performance ×1
pyc ×1
python-2.7 ×1
string ×1
syntax ×1
unicode ×1