强制在Python中通过引用传递

1 投票
3 回答
935 浏览
提问于 2025-04-16 21:59

我真搞不懂Python里的引用传递问题……我创建了一个非常有用的“解包器”类,我把它传给需要从中解包的各种对象,但由于它的速度极慢,我可以肯定每次传递BU对象时,它都在复制binaryStr。我知道这一点是因为如果我把BU分成更小的部分,它的运行速度快得惊人,快了整整100倍(我最开始是用它来存放一个16MB的文件输入输出缓冲区)。

所以我的问题是,为什么这个成员没有通过引用传递,有没有办法强制它这样做?我很确定BU对象本身是通过引用传递的(因为我的代码能正常工作),但速度的表现却让我觉得.binaryStr对象被复制了。我是不是遗漏了什么更微妙的东西?

class BinaryUnpacker(object):
    def __init__(self, binaryStr):
        self.binaryStr = binaryStr
        self.pos = 0

    def get(self, varType, sz=0):
        pos = self.pos
        if varType == UINT32:
            value = unpack('<I', self.binaryStr[pos:pos+4])[0]
            self.pos += 4
            return value
        elif varType == UINT64:
            value = unpack('<Q', self.binaryStr[pos:pos+8])[0]
            self.pos += 8
            return value
        elif varType == VAR_INT:
            [value, nBytes] = unpackVarInt(self.binaryStr[pos:])
            self.pos += nBytes
        ....

这个用例大概是这样的:

def unserialize(self, toUnpack):
    if isinstance(toUnpack, BinaryUnpacker):
        buData = toUnpack
    else:  # assume string
        buData = BinaryUnpacker(toUnpack)

    self.var1    = buData.get(VAR_INT)
    self.var2    = buData.get(BINARY_CHUNK, 64)
    self.var3    = buData.get(UINT64)
    self.var4obj = AnotherClass().unserialize(buData)

非常感谢你的帮助。

3 个回答

0

我觉得光靠速度来判断是不太合适的。你说你能看出字符串在被复制,因为如果把它分成更小的部分,运行得就快多了。但是你没有详细说明的unpack()函数的运行时间也可能跟数据的大小有关。

另外,像这样切割字符串

unpack('<I', self.binaryStr[pos:pos+4])[0]

会创建新的字符串对象,因为字符串是不可变的对象。

3

我没有深入查看你的代码,但有一些类型,比如字符串,提供了一个叫做 buffer() 的方法。你可以通过 memoryview 对象 来访问这些类型,而不需要复制数据。这里有相关的文档

你可以使用 memoryview 对象来代替切片字符串,这样可以避免你当前代码中耗时的部分。

几天前我问过一个问题,也许对你有帮助。

4

当你从一个字符串中提取子字符串时,会创建这个字符串的副本。举个例子:

[value, nBytes] = unpackVarInt(self.binaryStr[pos:])

这段代码会从指定的位置 pos 到字符串的末尾创建一个副本,如果字符串很长,这个过程可能会花费一些时间。如果你能在提取子字符串之前确定你实际需要的字节数,那么使用 self.binaryStr[pos:pos+nBytes] 会更快,因为提取一个小的子字符串相对来说是比较快的。

需要注意的是,所花费的时间只和子字符串的长度有关,所以 self.binaryStr[pos:pos+4] 的处理时间大致是一样的,无论 self.binaryStr 的长度有多长。

撰写回答