Python是某种象征简易观念的语言,其语法相比简易,特别容易入门。然而,假如此后小视Python语法的精妙和深邃,那便大错特错了。文中细致挑选了最能体现Python语法之精妙的十个知识要点,并另附完整的实例代码。如能在实战中融汇贯通、灵活采用,必定会使代码更加精炼、高效,并且也会非常大提升代码B格,使之看上去更老练,读上去更优雅。
1.for-else
什么?并不是if和else才算是原配吗?No,你也许不清楚,else是个脚踏两只船的混蛋,for和else也是一对,并且是合法的。十大装B语法,for-else肯定称得上南无湾!不相信,请看下边:>> for i in [1,2,3,4]:
print(i)
else:
print(i, '我是else')
1
2
3
4 我是else
假如在for和else相互之间(循环体内)有第三者if插足,也不会干扰for和else的关系。是因为for的级别比if高,else更是一个攀附权贵的混蛋,关键不在意能否有if,还有能否执行了符合if条件的语句。else的眼里唯有for,如果for顺当执行完毕,else就会屁颠儿屁颠儿地跑一遍:>>> for i in [1,2,3,4]:
if i > 2:
print(i)
else:
print(i, '我是else')
4 我是else
那样,怎样拆散for和else这对冤家呢?唯有当for循环被break语句中断过后,才会跳出else语句:>>> for i in [1,2,3,4]:
if i>2:
print(i)
break
else:
print(i, '我是else')
3
2.一颗星(*)和两颗星(**)
是否有发现,星(*)简直一个神奇的符号!想想,不存在它,C语言还有啥好玩的?一样,是因为有它,Python才会这般的仪态万方、风姿绰约、楚楚动人!Python函数支持默认参数和可变参数,一颗星体现不限数量的单值参数,两颗星体现不限数量的键值对参数。
大家也是举个例子吧:制定一个函数,返还多个输入数值的和。大家固然能够把这种输入数值制成一个list传给函数,但这种方法,远不存在采用一颗星的可变参数来得优雅:>>> def multi_sum(*args):
s = 0
for item in args:
s += item
return s
>>> multi_sum(3,4,5)
12
Python函数准许并且整个或部分采用固定参数、默认参数、单值(一颗星)可变参数、键值对(两颗星)可变参数,采用时需要遵循前述顺序书写。>>> def do_something(name, age, gender='男', *args, **kwds):
print('姓名:%s,年龄:%d,性别:%s'%(name, age, gender))
print(args)
print(kwds)
>>> do_something('xufive', 50, '男', 175, 75, math=99, english=90)
姓名:xufive,年龄:50,性别:男
(175, 75)
{'math': 99, 'english': 90}
此外,一颗星和两颗星还可用来列表、元组、字典的解包,看上去更像C语言:>>> a = (1,2,3)
>>> print(a)
(1, 2, 3)
>>> print(*a)
1 2 3
>>> b = [1,2,3]
>>> print(b)
[1, 2, 3]
>>> print(*b)
1 2 3
>>> c = {'name':'xufive', 'age':51}
>>> print(c)
{'name': 'xufive', 'age': 51}
>>> print(*c)
name age
>>> print('name:{name}, age:{age}'.format(**c))
name:xufive, age:51
3.三元表达式
熟悉C/C++的程序员,初入门python时,肯定会怀念经典的三元操作符,是因为想体现一样的观念,用python写上去貌似更麻烦。例如:
111
实际上,python是能够三元表达式的,仅仅略微怪异了某些,差不多我们山东人发言。比如说,山东人最感兴趣用倒装句:打球去吧,假如不下雨的情况下;下雨,咱便去自习室。转译成三元表达式便是:
打球去吧if不下雨else去自习室
来了解一下三元表达式详细的采用:>>> y = 5
>>> if y
print('y是一个负数')
else:
print('y是一个非负数')
y是一个非负数
4.with-as
with这种词儿,英文里边容易翻译,但在Python语法中怎么翻译,我都真想不出来,大体上是一类上下文管理协议。身为初学者,无需关注with的各类方法还有机制怎样,只必须熟知它的应用场景就可以了。with语句适合某些事前必须准备,事后必须处理的任务,比如说,文件操作,必须先打开文件,操作完成后必须关闭文件。如果不采用with,文件操作一般得这种:fp = open(r"D:\CSDN\Column\temp\mpmap.py", 'r')
try:
contents = fp.readlines()
finally:
fp.close()
假如采用with-as,那么就优雅多了:>>> with open(r"D:\CSDN\Column\temp\mpmap.py", 'r') as fp:
contents = fp.readlines()
5.列表推导式
在各类千奇百怪的语法中,列表推导式的采用频率应当时最高的,针对代码的简化作用也比较突出。比如说,求列表各元素的平方,一般应当这种写(自然也会有其余写法,比如说采用map函数):>>> a = [1, 2, 3, 4, 5]
>>> result = list()
>>> for i in a:
result.append(i*i)
>>> result
[1, 4, 9, 16, 25]
假如采用列表推导式,看上去就舒服多了:>>> a = [1, 2, 3, 4, 5]
>>> result = [i*i for i in a]
>>> result
[1, 4, 9, 16, 25]
实际上,推导式不但能够列表,也能够字典、集合、元组等对象。有兴致的情况下,能够自行研究。我们有一篇博文《一行Python代码能完成什么丧心病狂的功能?》,里边的事例,全是列表推导式完成的。
6.列表索引的各类骚操作
Python引入负整数身为数组的索引,这肯定是喜大普奔之举。想个办法,在C/C++中,需要数组最后一个元素,得先获得数组长度,减一过后做索引,严重影响了思维的连贯性。Python语言往往取得胜利,我本人认为,在众多原因里边,列表操作的便捷性是不可忽视的一点。可以看:>>> a = [0, 1, 2, 3, 4, 5]
>>> a[2:4]
[2, 3]
>>> a[3:]
[3, 4, 5]
>>> a[1:]
[1, 2, 3, 4, 5]
>>> a[:]
[0, 1, 2, 3, 4, 5]
>>> a[::2]
[0, 2, 4]
>>> a[1::2]
[1, 3, 5]
>>> a[-1]
5
>>> a[-2]
4
>>> a[1:-1]
[1, 2, 3, 4]
>>> a[::-1]
[5, 4, 3, 2, 1, 0]
假如说,这种你都很熟知,也时常用,那样接下来这种采用,你必定会感觉很神奇:>>> a = [0, 1, 2, 3, 4, 5]
>>> b = ['a', 'b']
>>> a[2:2] = b
>>> a
[0, 1, 'a', 'b', 2, 3, 4, 5]
>>> a[3:6] = b
>>> a
[0, 1, 'a', 'a', 'b', 4, 5]
7.lambda函数
lambda听起来很高大上,实际上便是匿名函数(熟知js的同学一定很熟知匿名函数)。匿名函数的应用场景是什么呢?便是仅在定义匿名函数的地方采用这种函数,其余地方用不上,故此就无需给它取个阿猫阿狗之类的名称了。接下来是一个求和的匿名函数,输入参数有两个,x和y,函数体便是x+y,省略了return关键字。>>> lambda x,y: x+y
>>> (lambda x,y: x+y)(3,4) # 因为匿名函数没有名字,使用的时候要用括号把它包起来
匿名函数通常并不会单独使用,反而是搭配其余方法,为其余方法带来内置的算法或判断情况。比如说,使用排序函数sorted对多维数组或是字典排序时,就可以特定排序规则。>>> a = [{'name':'B', 'age':50}, {'name':'A', 'age':30}, {'name':'C', 'age':40}]
>>> sorted(a, key=lambda x:x['name']) # 按姓名排序
[{'name': 'A', 'age': 30}, {'name': 'B', 'age': 50}, {'name': 'C', 'age': 40}]
>>> sorted(a, key=lambda x:x['age']) # 按年龄排序
[{'name': 'A', 'age': 30}, {'name': 'C', 'age': 40}, {'name': 'B', 'age': 50}]
再举一个数组元素求平方的事例,此次用map函数:>>> a = [1,2,3]
>>> for item in map(lambda x:x*x, a):
print(item, end=', ')
1, 4, 9,
8.yield还有生成器和迭代器
yield这词儿,真不好翻译,翻词典也无用。我干脆就读作“一爱得”,算作外来词汇吧。要掌握yield,得先了解generator(生成器)。要了解generator,得先知道iterator(迭代器)。呵呵呵呵,绕晕了吧?算啦,我还是说白话吧。
话说py2时代,range()返还的是list,但比如range(10000000)的时候,会损耗大量内存资源,故此,py2又搞了一个xrange()来处理这个问题。py3则只保留了xrange(),但写作range()。xrange()返还的便是一个迭代器,它还可以像list那样被遍历,但又不占据多少内存。generator(生成器)是某种特殊的迭代器,仅能被遍历一次,遍历结束,就自然消失了。总而言之,无论是迭代器或是生成器,全是想要避免使用list,故而节省内存。那样,如何获得迭代器和生成器呢?
python内置了迭代函数iter,用来生成迭代器,用法给出:>>> a = [1,2,3]
>>> a_iter = iter(a)
>>> a_iter>>> for i in a_iter:
print(i, end=', ')
1, 2, 3,
yield则是用来构造生成器的。比如说,我们要写一个函数,返还从0到某正整数的全部整数的平方,传统的代码写法是这种的:>>> def get_square(n):
result = list()
for i in range(n):
result.append(pow(i,2))
return result
>>> print(get_square(5))
[0, 1, 4, 9, 16]
可是比如计算1亿之内的全部整数的平方,这个函数的内存开销会特别大,这也是yield就可以大展身手了:
比如再次遍历,则并不会有输出了。
9.装饰器
刚弄搞清楚迭代器和生成器,这又来个装饰器,Python咋这么多器呢?确实,Python为大家带来了众多的武器,装饰器便是最强有力的武器之一。装饰器很强大,我就在这里试着从可以的角度,用一个简便的事例,反映装饰器的使用方法和制造工艺。
比如大家可以定义众多个函数,在各个函数运行的情况下要展现这个函数的运行时长,处理方案有很多。比如说,还可以在调用各个函数事先读一下时间戳,各个函数运行结束后再读一下时间戳,求差就可以;也能够在各个函数体内的开始和结束位置上读时间戳,最终求差。但是,这两个方法,还没有使用装饰器那样简单、优雅。下边的事例,非常好地展现了这一点。>>> import time
>>> def timer(func):
def wrapper(*args,**kwds):
t0 = time.time()
func(*args,**kwds)
t1 = time.time()
print('耗时%0.3f'%(t1-t0,))
return wrapper
>>> @timer
def do_something(delay):
print('函数do_something开始')
time.sleep(delay)
print('函数do_something结束')
>>> do_something(3)
函数do_something开始
函数do_something结束
耗时3.077
timer()是大家定义的装饰器函数,应用@把它附带在任何一个函数(例如do_something)定义以前,就等同于把新定义的函数,变成了装饰器函数的输入参数。运行do_something()函数,能够明白为执行了timer(do_something)。细节尽管繁杂,但是如此明白不会偏差过大,且更容易把握装饰器的制造和应用。
10.巧用断言assert
说白了断言,也就是声明表达式的布尔值一定为真的判定,要不然将触发AssertionError异常。严格而言,assert是调试手段,不适合应用在生产环境中,但这并不影响大家用断言来完成一些特定功能,例如,输入参数的格式、类型验证等。>>> def i_want_to_sleep(delay):
assert(isinstance(delay, (int,float))), '函数参数必须为整数或浮点数'
print('开始睡觉')
time.sleep(delay)
print('睡醒了')
>>> i_want_to_sleep(1.1)
开始睡觉
睡醒了
>>> i_want_to_sleep(2)
开始睡觉
睡醒了
>>> i_want_to_sleep('2')
Traceback (most recent call last):
File "", line 1, in i_want_to_sleep('2')
File "", line 2, in i_want_to_sleep
assert(isinstance(delay, (int,float))), '函数参数必须为整数或浮点数'
AssertionError: 函数参数必须为整数或浮点数