问题 想从iterable中解压N个元素,但iterable元素可能多于N个,会导致“to many values to unpack”的异常。 解决方法 Python的 表达式(star expression)可被用来解决这个问题。举例,假如你课程并决定在学期结束时放弃最高和最低分,只取剩下的平均分,如
问题
想从iterable中解压N个元素,但iterable元素可能多于N个,会导致“to many values to unpack”的异常。
解决方法
Python的 表达式(star expression)可被用来解决这个问题。举例,假如你课程并决定在学期结束时放弃最高和最低分,只取剩下的平均分,如果只有4门课程,你可以简单的加压所有的4门,但是如果有24门课程呢? 表达式可以容易的做到:
def drop_first_last ( grades ): first , * middle , last = grades return avg ( middle )
另一个用例,假如你有包含姓名、电子邮件和电话号码的用户记录,你可以这样加压记录:
>>> record = ( 'Dave' , 'dave@example测试数据' , '773-555-1212' , '847-555-1212' ) >>> name , email , * phone_numbers = user_record >>> name 'Dave' >>> email 'dave@example测试数据' >>> phone_numbers [ '773-555-1212' , '847-555-1212' ] >>>
值得注意的是,变量 phone_numbers 将永远是个列表,不管解压多少电话号码(包括None),因此任何使用 phone_numbers 的代码不会考虑是否是列表或者任何额外的类型检查。
*变量也可以在列表的开始。举例,假如你有一个反映公司过去8个季度的销售记录的序列,如果你想看最近一个季度的记录是否比前7个季度的平均值高,你可以这么做:
* trailing_qtrs , current_qtr = sales_record trailing_avg = sum ( trailing_qtrs ) / len ( trailing_qtrs ) return avg_comparison ( trailing_avg , current_qtr )
在Python的解释器里,可以看到以下结果:
>>> * trailing , current = [ 10 , 8 , 7 , 1 , 9 , 5 , 10 , 3 ] >>> trailing [ 10 , 8 , 7 , 1 , 9 , 5 , 10 ] >>> current 3
讨论
扩展的迭代解包是专为位置或任意长度的迭代序列解包的,通常情况下,这些迭代序列在结构上有已知的组件或者模式(比如数字1后面的会是电话号码)*表达式可以让开发者很容易解压这些模式,而不是想杂耍那样得到迭代序列中的元素。
值得注意的是,*语法对未知长度的元组序列尤其有用。假如有一个标记过的元组序列:
records = [ ( 'foo' , 1 , 2 ), ( 'bar' , 'hello' ), ( 'foo' , 3 , 4 ), ] def do_foo ( x , y ): print ( 'foo' , x , y ) def do_bar ( s ): print ( 'bar' , s ) for tag , * args in records : if tag == 'foo' : do_foo ( * args ) elif tag == 'bar' : do_bar ( * args )
*解压在和处理特定字符串结合使用时也很有用,比如:
>>> line = 'nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false' >>> uname , * fields , homedir , sh = line . split ( ':' ) >>> uname 'nobody' >>> homedir '/var/empty' >>> sh '/usr/bin/false' >>>
有时你可能会想解压一些值然后抛弃掉。你不能在解压时只指定一个*,你可以使用普通的要丢弃掉的变量名,比如 _ 或者 ign (ignore)。举例:
>>> record = ( 'ACME' , 50 , 123.45 , ( 12 , 18 , 2012 )) >>> name , * _ , ( * _ , year ) = record >>> name 'ACME' >>> year 2012 >>>
*解压和列表处理在不同的功能语言上有一定相似性。例如,你有一个列表,你可以很容易的将其分解为头尾部件:
>> items = [ 1 , 10 , 7 , 4 , 5 , 9 ] >>> head , * tail = items >>> head 1 >>> tail [ 10 , 7 , 4 , 5 , 9 ] >>>
有人可能会想写这么一个函数,为了完成某种聪明的递归算法而执行这样的分割:
>>> def sum ( items ): ... head , * tail = items ... return head + sum ( tail ) if tail else head ... >>> sum ( items ) 36 >>>
然而,要注意的是,因为固有的限制,递归真的不是Python的强项。因此上述代码在实现中只能算是有学术价值。
查看更多关于1.2.从任意长度的迭代中解压元素的详细内容...