简介
迄今为止我们已经学习了python中的大多数常用知识。本章中我们会接触到更多的知识,使得我们更全面的掌握python。
传递元组
你是否希望过从函数返回两个不同的值?做到这点使用元组即可。
>>> def get_error_details():
... return (2, 'second error details')
...
>>> errnum, errstr = get_error_details()
>>> errnum
2
>>> errstr
'second error details'
注意a, b = <某些表达式>的使用,它会将表达式的结果解释为带有两个值的元组。
如果你希望将结果解释成(a, <其它值>)的形式,那么你要做的就象在函数形参中的那样:
>>> a, *b = [1, 2, 3, 4]
>>> a
1
>>> b
[2, 3, 4]
这种语法也暗示出在python中快速交换两个变量值的方法:
>>> a = 5; b = 8
>>> a, b = b, a
>>> a, b
(8, 5)
特殊方法
有一些诸如__intit__和__del__的方法在类中拥有特殊的含义。特殊方法用于模拟某些内建类型的行为。
例如,你希望为你的类使用x[key]索引操作(就像在列表和元组中那样),那么你仅仅需要实现__getitem__方法就可以了。
顺便思考一下,python正是这样实现list类的!
一些有用的特殊方法列在下表中。如果你想了解所有的特殊方法,详见(http://docs.python.org/py3k/reference/datamodel.html#special-method-names)。
方法名 | 解释 |
__init__(self, ...) | 在对象被返回以变的可用前调用 |
__del__(self) | 在对象被销毁前调用 |
__str__(self) | 在使用print函数或str()时调用 |
__lt__(self, other) | 在使用小于运算符时(<)调用。 类似的其它运算符也存在对象的特殊方法(+, >等) |
__getitem__(self, key) | 当使用x[key]索引操作时调用 |
__len__(self) | 当使用内建len()函数时调用。 |
单语句块
我们已经看到每个语句块都根据它的缩进级别将彼此区分开。不过有一个例外。
如果某语句块只包含单条语句,你可以把它放到同一行,例如条件语句或循环语句。
下面的例子清楚的说明了这点:
>>> flag = True
>>> if flag: print 'Yes'
...
Yes
注意上面的单条语句被放置到同一行而没有作为单独的块。
虽然你利用这点可以让程序变的更短,但我强烈建议你避免之(除了错误检测),主要原因是使用适当的缩进可以更方便的添加额外的语句。
Lambda表达式
lambda语句用于在运行时创建并返回新的函数对象。
#!/usr/bin/python
# Filename: lambda.py
def make_repeater(n):
return lambda s: s * n
twice = make_repeater(2)
print(twice('word'))
print(twice(5))
输出:
$ python lambda.py
wordword
10
代码如何工作:
在运行时我们利用函数make_repeater创建一个新的函数对象并返回它。其中一条lambda语句用于创建函数对象。
本质上这条lambda需要一个参数后跟一个相当于函数体的单表达式,这个表达式的值将成为函数的返回值。
注意就算print这样的语句也不能出现在lambda中,只能是表达式。(注:py3k中print是个函数,作者out了)。
思考一下
我们能否利用lambda创建一个比较函数并将其提供给list.sort()?
points = [ { 'x' : 2, 'y' : 3 }, { 'x' : 4, 'y' : 1 } ]
# points.sort(lambda a, b : cmp(a['x'], b['x']))
列表解析(List Comprehension)
列表解析用于从一个现有的列表派生出一个新的列表。
假设你有一个数字列表,你想让其中所有大于2的元素乘以2并组成一个新的列表。
类似问题正是使用列表解析的理想场合。
#!/usr/bin/python
# Filename: list_comprehension.py
listone = [2, 3, 4]
listtwo = [2*i for i in listone if i > 2]
print(listtwo)
输出:
$ python list_comprehension.py
[6, 8]
代码如何工作:
当某些条件满足时(if i > 2)我们执行某些操作(2 * i),由此产生一个新列表。注意原始列表并不会被改变。
使用列表解析的好处在于当我们使用循环遍历元素并将其存储到新列表时可以减少样板代码量。
函数接收元组和列表
这里有一种特殊的方法可以将函数的形参当做元组或字典,那就是分别使用*和**前缀。
当需要在函数内得到可变数量的实参时这个方法很有用。
>>> def powersum(power, *args):
... '''Return the sum of each argument raised to specified power.'''
... total = 0
... for i in args:
... total += pow(i, power)
... return total
...
>>> powersum(2, 3, 4)
25
>>> powersum(2, 10)
100
因为args变量带有*前缀,因此所有额外的实参都会被当做一个元组存入args中并传给函数。
如果这里的*换成**,则所有额外的形参都会被当做一个字典的键/值对。
exec和eval
exec函数用于执行python语句,不过这些语句储存在字符串或文件中而不是程序自身中。
例如,我们可以在运行时产生一个包含python代码的字符串,然后利用exec执行之。
>>> exec('print("Hello World")')
Hello World
与之类似,eval函数用于执行合法的存储在字符串中的python表达式。下面是一个简单的例子。
>>> eval('2*3')
6
assert语句
assert用于断言一个表达式为真。
例如,你需要确保正在使用的列表至少有一个元素,否则引发一个错误,这正是使用assert的理想场合。
当assert语句断言失败,则引发一个AssertError。
>>> mylist = ['item']
>>> assert len(mylist) >= 1
>>> mylist.pop()
'item'
>>> mylist
[]
>>> assert len(mylist) >= 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
assert应当慎重使用。多数时候用于捕获异常,处理问题或是向用户显示错误后随即终止程序。
repr函数
repr函数用于获得对象的正规字符串表示。有趣的是多数时候eval(repr(object))等于object。
>>> i = []
>>> i.append('item')
>>> repr(i)
"['item']"
>>> eval(repr(i))
['item']
>>> eval(repr(i)) == i
True
基本上,repr函数用来获得一个对象的可打印形式。你可以通过在类中定义__repr__方法控制repr的返回值。
小结
本章我们介绍了更多的python特性,虽然没有引入python的所有特性但足以应付实践中的大多数应用了。
接下来我们考虑如何进一步学习python。