Python 中的元组、打包和解包性能

问题描述 投票:0回答:1

使用元组的两个类,拆包和打包。 为什么这两个类的性能如此不同 - 2000 倍。这条线这么贵吗?

*self.stack, outitem = self.stack

from time import time


class StackT:
    def __init__(self):
        self.stack = tuple()

    def push(self, otheritem):
        self.stack = (*self.stack, otheritem)

    def pop(self):
        *self.stack, outitem = self.stack
        return outitem


class Stack:
    def __init__(self):
        self._items = None
        self._size = 0

    def push(self, item):
        self._items = (item, self._items)

    def pop(self):
        (item, self._items) = self._items
        return item


def timer(func):
    def wrapper(*args, **kwargs):
        print("starting count.")
        now = time()
        result = func(*args, **kwargs)
        print(f"counted {time() - now} seconds")
        return result
    return wrapper


@timer
def f(cls, times):
    print(f"class {cls.__name__}, {times} times")
    stack = cls()
    for i in range(times):
        stack.push(i)
    for i in range(times):
        stack.pop()
f(StackT, 100_000)
f(Stack, 100_000)

# starting count.
# class StackT, 100000 times
# counted 63.61870002746582 seconds
# starting count.
# class Stack, 100000 times
# counted 0.02500009536743164 seconds
python tuples
1个回答
0
投票

您的

Stacks
具有不同类型的属性。我的意思是:

  • StackT.stack
    items
  • 的元组
  • Stack.items
    是元组的元组

你的直觉和@zvone 的评论是正确的。

push/pop
StackT
函数更昂贵,因为您使用
* operator
来取消列出
tuple
StackT.stack
的元素,成本高昂,因为它具有与元组循环相同的复杂性。

备注

StackT
更加灵活且易于操作,因为每个元素都在一个元组中,访问元素相当于拥有其索引/顺序,但在实现时计算量很大。

  • Stack
    更优化,但具有更复杂的属性来操作,因为仅拥有其索引是不够的。您需要使用一些循环机制。
  • 当遇到此类问题时,分析是 @cards 提出的一个很好的做法,Python 上有很多选择。我个人使用 cProfile + Snakeviz(用于可视化目的)。
© www.soinside.com 2019 - 2024. All rights reserved.