- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我不确定下面代码的 Python 对象模型背后发生了什么。
您可以从此link 下载ctabus.csv 文件的数据。
import csv
def read_as_dicts(filename):
records = []
with open(filename) as f:
rows = csv.reader(f)
headers = next(rows)
for row in rows:
route = row[0]
date = row[1]
daytype = row[2]
rides = int(row[3])
records.append({
'route': route,
'date': date,
'daytype': daytype,
'rides': rides})
return records
# read data from csv
rows = read_as_dicts('ctabus.csv')
print(len(rows)) #736461
# record route ids (object ids)
route_ids = set()
for row in rows:
route_ids.add(id(row['route']))
print(len(route_ids)) #690072
# unique_routes
unique_routes = set()
for row in rows:
unique_routes.add(row['route'])
print(len(unique_routes)) #185
当我调用 print(len(route_ids))
时,它会打印 "690072"
。为什么 Python 最终要创建这么多对象?
我希望此计数为 185 或 736461。185 因为当我计算集合中的唯一路由时,该集合的长度为 185。736461 因为这是 csv 文件中的记录总数。
这个奇怪的数字“690072”是什么?
我想了解为什么要使用这种部分缓存?为什么 python 无法执行如下所示的完整缓存。
import csv
route_cache = {}
#some hack to cache
def cached_route(routename):
if routename not in route_cache:
route_cache[routename] = routename
return route_cache[routename]
def read_as_dicts(filename):
records = []
with open(filename) as f:
rows = csv.reader(f)
headers = next(rows)
for row in rows:
row[0] = cached_route(row[0]) #cache trick
route = row[0]
date = row[1]
daytype = row[2]
rides = int(row[3])
records.append({
'route': route,
'date': date,
'daytype': daytype,
'rides': rides})
return records
# read data from csv
rows = read_as_dicts('ctabus.csv')
print(len(rows)) #736461
# unique_routes
unique_routes = set()
for row in rows:
unique_routes.add(row['route'])
print(len(unique_routes)) #185
# record route ids (object ids)
route_ids = set()
for row in rows:
route_ids.add(id(row['route']))
print(len(route_ids)) #185
最佳答案
文件中的典型记录如下所示:
rows[0]
{'route': '3', 'date': '01/01/2001', 'daytype': 'U', 'rides': 7354}
这意味着您的大部分不可变对象(immutable对象)都是字符串,只有 'rides'
值是整数。
对于小整数 (-5...255
),Python3 保留 an integer pool - 所以这些小整数感觉像是被缓存了(只要使用 PyLong_FromLong
和 Co.)。
字符串的规则更为复杂——正如@timgeb 所指出的那样,它们是 interned 的。有 a greate article about interning ,即使它是关于 Python2.7 的——但从那以后变化不大。简而言之,最重要的规则是:
0
和 1
的字符串都被保留。以上所有都是实现细节,但考虑到它们,我们得到上面的 row[0]
的以下内容:
'route'、'date'、'daytype'、'rides'
都被保留了,因为它们是在函数 read_as_dicts
的编译时创建的,并且没有“奇怪”的字符。'3'
和 'W'
被驻留,因为它们的长度仅为 1
。01/01/2001
未被驻留,因为它比 1
长,在运行时创建并且无论如何都不符合条件,因为它具有字符 /
在里面。7354
不是来自小整数池,因为太大了。但其他条目可能来自此池。这是对当前行为的解释,只有一些对象被“缓存”。
但是为什么 Python 不缓存所有创建的字符串/整数?
让我们从整数开始。如果已经创建了一个整数,为了能够快速查找(比 O(n)
快得多),必须保留一个额外的查找数据结构,这需要额外的内存。然而,整数太多,再次命中一个已经存在的整数的概率不是很高,因此查找数据结构的内存开销在大多数情况下不会被偿还。
因为字符串需要更多内存,所以查找数据结构的相对(内存)成本并没有那么高。但是实习一个 1000 个字符的字符串没有任何意义,因为随机创建的字符串具有完全相同字符的概率几乎为 0
!
另一方面,如果例如使用哈希字典作为查找结构,则哈希的计算将花费 O(n)
(n
-字符数),这可能不会为大字符串带来返回。
因此,Python 做了一个权衡,它在大多数情况下工作得很好——但在某些特殊情况下它并不完美。然而,对于那些特殊情况,您可以使用 sys.intern()
优化每手牌.
注意:拥有相同的 id 并不意味着是同一个对象,如果两个对象的生存时间不重叠,那么你在这个问题上的推理并不是完全防水的 - 但这无关紧要在这种特殊情况下。
关于Python - 为什么不总是缓存所有不可变对象(immutable对象)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53466954/
为什么禁用类型像 type t = A of int | B of string * mutable int 虽然允许此类类型: type t = A of int | B of string * i
我正在寻找一种类似结构的数据结构,我可以从中创建多个实例并具有某种类型提示而不是不可变的。 所以我有这样的东西: class ConnectionConfig(NamedTuple): nam
我需要转到引用的结构: class SearchKnot { var isWord : Bool = false var text : String = "" var to
如sec 10.4.3中所述 当控制进入执行时,执行以下步骤 功能对象F(调用者)中包含的功能代码的上下文 提供thisArg,而调用方提供argumentsList: 如
i make a game that start display Activity indicator And activity indicator bottom display UiLable wi
编辑:我在这里不断获得支持。只是为了记录,我认为这不再重要。自从我发布它以来我就不再需要它了。 我想在 Scala 中执行以下操作... def save(srcPath: String, destP
使用可变对象作为 Hashmap 键是一种不好的做法吗?当您尝试使用已修改足以更改其哈希码的键从 HashMap 中检索值时,会发生什么? 例如,给定 class Key { int a; /
如果您在Kotlin中访问List类型的Java值,则将获得(Mutable)List!类型。 例如。: Java代码: public class Example { public stati
我编写了 str 类(内置)的以下扩展,以便执行以下操作:假设我有字符串 "Ciao" ,通过做"Ciao" - "a"我想要的结果是字符串 "Cio" 。这是执行此操作的代码,并且运行良好: cla
使用可变对象作为 Hashmap 键是一种不好的做法吗?当您尝试使用已修改足以更改其哈希码的键从 HashMap 中检索值时,会发生什么? 例如,给定 class Key { int a; /
我正在为我的公司设计一个数据库来管理商业贷款。每笔贷款都可以有担保人,可以是个人或公司,在借款业务失败时作为财务支持。 我有 3 个表:Loan、Person 和 Company,它们存储明显的信息。
我使用二进制序列化从 C# 类中保存 F# 记录。一切正常: F#: type GameState = { LevelStatus : LevelStatus
import javax.swing.JOptionPane; public class HW { public static void main(String[] args) { Strin
使用 flatbuffer mutable 有多少性能损失? 是否“正确”使用 FlatBuffers 来拥有一个应该可编辑的对象/结构(即游戏状态) 在我的示例中,我现在有以下类: class Ga
std::function create_function (args...) { int x = initial_value (args...); return [x] () mut
我需要在 for 循环中找到用户输入的字符。我通常会这样做 如果(句子[i] == 'e') 但是因为在这里,'e' 将是一个单字母字符变量,我不知道如何获取要比较的值。我不能只输入 if (sent
我有一个这样的算法: let seed: Foo = ... let mut stack: Vec = Vec::new(); stack.push(&seed); while let Some(ne
这个问题可能看起来非常基础,但我很难弄清楚如何做。我有一个整数,我需要使用 for 循环来循环整数次。 首先,我尝试了—— fn main() { let number = 10; // An
如果我有以下结构: struct MyStruct { tuple: (i32, i32) }; 以及以下函数: // This will not compile fn function(&mut s
我希望在每个 session 的基础上指定列的默认值。下面的脚本不起作用,但描述了我想如何使用它。我目前使用的是 MySQL 5.5.28,但如果需要可以升级。 CREATE TABLE my_tbl
我是一名优秀的程序员,十分优秀!