我在Python中有一段逻辑,涉及基于条件的元组解包。
代码示例化两个变量,并将元组的解包值赋给这些变量。
这个元组是有条件定义的:如果conditional_expression为true,则函数执行返回元组,否则提供并分配默认值。
我的理解是有两种简单的方法来实现这一点,如下所示:
# Method 1 #
if conditional_expression:
processed_data, context = tuple_returner(raw_data)
else:
processed_data, context = raw_data[0], None
# Method 2 #
processed_data, context = (
tuple_returner(raw_data)
if conditional_expression
else raw_data[0], None
)
现在我已经尝试了两种方法,两者都像预期的那样工作得很好。
我的问题是双重的:
1.这两种方法中的任何一种可能比另一种更性能吗(在标准CPython实现中)?在运行timeit
测试时,我没有注意到任何实质性的差异(尽管方法2似乎稍微慢了一点- * 请参阅底部代码片段 *),但我想知道是否有更深层次的事情发生在我不知道的幕后。
1.这两种方法中的哪一种比另一种更Pythonic,更受社区的青睐?我在PEP 8里面看不到任何具体的东西来指导我。两者对我来说都是可读的,但这个代码库将持续很长时间,并由几个贡献者工作,所以希望坚持最佳实践。
FWIW实际代码是一个大型Django项目的一部分,涉及Celery任务中的一些复杂业务逻辑,并且在我们处理数据和维护上下文 * 的任务中经常重复这种范式(有时我们解包的值远远不止两个)。因此,如果有Django特定的风格考虑,那么知道这一点会很有用!
对于那些想看我的timeit
评估的人,请看下面:
import timeit
import random
def tuple_returner(data):
return data * 2, data * 3
def method1():
conditional_expression = random.choice([True, False])
raw_data = random.randint(1, 1000)
if conditional_expression:
processed_data, context = tuple_returner(raw_data)
else:
processed_data, context = raw_data, None
def method2():
conditional_expression = random.choice([True, False])
raw_data = random.randint(1, 1000)
processed_data, context = tuple_returner(raw_data) if conditional_expression else (raw_data, None)
time1_a = timeit.timeit(method1, number=10000000)
time1_b = timeit.timeit(method1, number=10000000)
time1_c = timeit.timeit(method1, number=10000000)
time1_d = timeit.timeit(method1, number=10000000)
time1_e = timeit.timeit(method1, number=10000000)
time1_mean = (time1_a + time1_b + time1_c + time1_d + time1_e) / 5
time1_median = sorted([time1_a, time1_b, time1_c, time1_d, time1_e])[2]
time2_a = timeit.timeit(method2, number=10000000)
time2_b = timeit.timeit(method2, number=10000000)
time2_c = timeit.timeit(method2, number=10000000)
time2_d = timeit.timeit(method2, number=10000000)
time2_e = timeit.timeit(method2, number=10000000)
time2_mean = (time2_a + time2_b + time2_c + time2_d + time2_e) / 5
time2_median = sorted([time2_a, time2_b, time2_c, time2_d, time2_e])[2]
print("Method 1: mean = {0}, median = {1}".format(time1_mean, time1_median))
## -> Output: Method 1: mean = 10.77958505996503, median = 10.693453999934718
print("Method 2: mean = {0}, median = {1}".format(time2_mean, time2_median))
## -> Output: Method 2: mean = 11.350917899981141, median = 11.356302100000903
1条答案
按热度按时间yc0p9oo01#
这个问题似乎可以归结为:
是传统的多线
if/else
倍快于单线等效其次,
一个比另一个更好。
这里是我的观点,但我更喜欢
method2()
(单行)而不是method1()
,只要意图仍然清楚。让我看看我是否可以解决第一部分,虽然采取了一些噪音的系统
首先,让我们将
raw_data
的定义移出方法调用,因为它只会增加噪声。让我们定义第二个tuple_returner()
方法并调用它,这样可以确保两个分支所做的“工作”是相同的。比如:
这对我来说产生了一个结果,如:
这向我暗示,在没有分支预测的情况下,性能可能没有有效的差异。如果我们搬家呢
在允许分支预测的更好可能性的方法中
我看到的结果如下:
这再次向我表明,这两种策略之间几乎没有有效的性能差异。对于什么是值得的,虽然,你可以看看dissembley,看看你是否看到任何可能暗示的差异
方法一:
方法二:
虽然第一个更长,但两种情况下的最终结果似乎相同,除了第二个中的分支将
JUMP_FORWARD
作为额外指令执行。我想从技术上讲,第二个更慢。