【python教程入门学习】基础篇: 7. Python基础语句与函数

Python语句关键词都比较简单,但又有很多灵活的使用方式。

  1. 缩进和文件头

1.1. 缩进

说语句之前,先谈谈之前一直没有谈过的Python文件的缩进,Python文件不是以花括号{}来分割代码块,而是以缩进(英文是indent)来分割,一般都是推荐4个空格。函数体和语句块都会用缩进4个空格来表示,但除了空格还可以用tab来缩进,但这两种缩进后又无法用肉眼可以看到,但如果出现混用就很容易报错和混乱。在缩进这个问题上,我的建议是以下:

尽量全部用4个空格
需要修改别人编写的Python文件,其中缩进是以tab的,建议也遵循原来的tab,或者全部转换成空格。但切记不要混用,在sublime text可以选定这些空白字符,点就是空格,横线就是tab,可以统一转换。
没说空格就比tab高人一等,也没有说空格就低人一等。我觉得统一是减少争执和问题的有效办法。
复制代码

1.2. 文件头

文件头之前简略提过,现在来详细说说,先把统一的文件头放出来,以后无脑用它就好。

#! /usr/bin/env python

-- coding: utf-8 --

指定了使用linux环境变量$PATH里某个路径下名为python的解释器来打开.py文件

  echo $PATH

告诉Python解释器,这个文件是以utf-8的格式保存的。这个有什么意义呢?Python默认是以ASCII来打开文件,但中文字却是不在ASCII字符编码的范围内,这样打开的话会无法解析中文字,如下例:

  print('我')
  # 运行后就会报错
  SyntaxError: Non-ASCII character '\xe6' in file noheader.py on line 1,
复制代码

1.3. 小技巧

每次创建python文件的时候可以自动生成这些文件头,免得每次都要复制粘贴。而sublime可以使用下面一个snippet:

vim: et sw=4 ts=4

]]> code source.python

创建文件后输入code然后按tab就会自动转换为文件头具体内容了,记得是py结尾的文件才能触发。上面的例子还可以举一反三,在平时十分常用的代码块可以保存下来,那样每次不用重新手动码字。 2. 语句 2.1. if-else语句

if-else语句是python最主要的条件判断语句,没有switch-case,所以一旦碰到需要条件判断的情况,就上if-else就好。例子如下:

name = "Tom" if "CAT" == name: print("name is CAT") elif "MARY" == name: print("name is MARY") elif "TOM" == name : print("name is TOM") else: print("default")

if后面冒号前是测试条件,如果是True,就会执行冒号后面的语句。
建议这种常量测试条件放在前面,这样更方便地看到每个条件的要求。
else建议是必备,因为这样避免缩进错误了,导致执行错了代码。有些资深的开发因为没写一个默认的else,常常因为某些异常摸不着头脑。如果不需要任何语句逻辑,可以写pass表示空白省略,也不会导致报错
复制代码

这里特别提一提一行的if-else语句,先举例子:

flag = 1 name = "Tom" if flag else "MARY"

非常类似其他语言的三元操作符name = flag?"Tome":"MARY",如果flag是真,就赋值"Tom"给name,否则就赋值给"MARY"。这个特别简洁易看,但如果flag过于复杂,还是最好用完整的if语句块,这样看起来更清晰。要记着代码是写给人看的,而不是写给机器看的,能维护易改才是真正的好代码。 2.2. while语句

循环语句,格式如下:

i = 1 while i <= 100: if i == 10: break print("i = {0}".format(i)) i += 1

while和冒号之间是测试条件,是真的话会一直执行下面的循环体。

但i=10的时候,会执行break语句,跳出循环。所以用while循环的时候,必须要考虑死循环的问题。

记得要自增i,经常出现没有if条件的判断,只有while语句的判断,但忘记自增i,出现多次执行。对于新手小白想更轻松的学好Python基础,Python爬虫,web开发、大数据,数据分析,人工智能等技术,这里给大家分享系统教学资源,架下我尉♥: 2763177065 【教程/工具/方法/解疑】

如果while循环里面写了很多重要逻辑,建议可以增加一些调试语句,在生产环境执行的时候先执行一次或者数次,避免一次过完全执行造成大锅。可以先看执行一次的结果是否如你所愿,我就是这样试过避免了很多次内外网不一致导致的问题。

其实while还有个else语句,例子如下:

while 0:
    print("0")
else:
    print("else")

这种用法我很多同事都几乎看不懂,而且非常容易出错。我个人认为一门语言,吸收其最好的80%精华已经很不错了,这种特殊罕见的例子用在生产上会让很多人迷惘,一旦迷惘就会出现生产事故。我觉得可以忽略不用,在规则下面怎么方便就怎么来。
复制代码

2.3. for语句

for循环语句,与while不一样的,for循环比较难出现死循环,因为一般在for循环里面都会定下终止条件和达到终止条件的逻辑操作。同样for也有else语句,我个人认为还是与上面一样,太少用了。先看例子:

for i in xrange(100): print(i)

对比两个语句的差别,for一般用于遍历可迭代对象,最常用的就是list了而while要指定终止条件,然后在循环体里面逐步达到终止条件。对比最明显的就是for循环不容易造成死循环。后面会说到的高深魔法,生成器就一般使用for循环比较多。当然了,还是养成个人编程习惯,习惯用哪个熟悉就多使用,这样编写的代码你会更有信心,有自己的节奏。 3.函数 3.1. 基本介绍

函数是以def 函数名(参数, 默认参数=默认值,*可变参数,**关键词参数):这样的定义,python函数真的非常灵活,因为没有强制类型,所以其灵活性是他一大优势,当然出错率也肯定高,但我觉得出错这个东西只要维持一定习惯,可以把出错尽量减少,就是熟悉就会减少出错。例子:

def test(name, default=2, *args, **kwargs): print(name) print(default) print(args) print(kwargs)

name是指定参数
default是带有默认值的参数,注意这里有个大坑,后面详细说说。
*args表示多个可变参数,星号表示解包操作。
**args表示多个可变关键词参数,两个星号同样是解包操作。
复制代码

3.2. 解包星号

传入函数的时候,用一个星号的话,表示对后续的参数进行解包操作,列表解包变成一个一个值,我们可以调用看一看

对列表或者元组进行解包

a= range(10) test(*a) 0 1 (2, 3, 4, 5, 6, 7, 8, 9) {}

可以看到是按顺序传入对应的参数。

name赋值为0
default赋值为1
args赋值为元组(2, 3, 4, 5, 6, 7, 8, 9
kwargs赋值为空字典
复制代码

假如我们解包一个字典呢:

b = {"a":1, "b":2, "c":3, "d":4} test(*b) a c ('b', 'd') {}

= test(*b.keys())

可以看到其实就是把字典的keys()传进去而已。

双星号按上面规律就知道是用来专门解包字典的,把字典解包成key=value的方式,直接看例子:

b = {"a":1, "b":2, "c":3, "d":4} test("Tom", **b) "Tom" 2 () {'a': 1, 'c': 3, 'b': 2, 'd': 4}

= test("Tom", a=1, b=2, c=3, d=4)

name赋值为Tom
default用默认值2
args赋值为()空元组
kwargs赋值为{'a': 1, 'c': 3, 'b': 2, 'd': 4}
可以看到最后给出另一个方式,解包可以认为是这样的赋值方式,更直观,用在format里面也很方便。
复制代码

3.3. 如何传参

默认值传参和可变参数混在一起通常比较混乱,首先args是可以传入可变参数,但用上解包和默认值传参的是,要注意args是按位置赋值,例子如下:

def test1(a, b, c, d=1, args, **kwargs): print a,b,c,d,args,kwargs test1(1,[2,3,4]) 1 2 3 4 () {}

如果先赋值默认值d呢:

test1(d=10,*[2,3,4]) 2 3 4 10 () {}

如果数量不够就会报错,下面例子只传了两个参数,c是必须要传参的

test1(*[2,3]) TypeError: test1() takes at least 3 arguments (2 given)

传参数量多了,明显可以看出,是按照位置赋值的,所以如果默认参数如果赋值了,那就不要再传了

不传默认参数

test1(*[1,2,3,4,5])

传默认参数,

test1(d=3, *[1,2,3,4,5]) TypeError: test1() got multiple values for keyword argument 'd'

这样还是会报错

test1(1, 2, 3, d=3, *[1,2,3,4,5]) TypeError: test1() got multiple values for keyword argument 'd'

不明确指出变量名来赋值就正确了

test1(1, 2, 3, 3, *[1,2,3,4,5]) 1 2 3 3 (1, 2, 3, 4, 5) {}

数量缺少

test1(d=3, *[1,2,3]) 1 2 3 3 () {}

总结:

对于必传参数,最好还是明确一个一个按位置传进去。如果确实需要添加可变参数args,那就在args前面不要指明key=value的方式赋值,否则可能会报错。

key=value赋值后,就不要再kwargs再次赋值,否则也会报多次赋值异常

test1(1,2,3,d=4,**{"d": 4})
复制代码

3.4. 默认值的坑

函数默认值传入一个dict和list是很正常的事情,但往往这里会出巨坑,发现下次调用list的时候,list或者dict还保存着上次函数调用的信息,这就非常坑了。从官方文档也可以看到,它特别提醒了,以下是官方文档的一段话:

Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. This is generally not what was intended. A way around this is to use None as the default, and explicitly test for it in the body of the function

函数在Python的世界里面也是一个函数,所以它定义的时候就会被生成一个对象,同样其中的的默认参数会被生成。如果参数是一个可变对象,例如list或者dict,如果在函数中被修改,默认值也会被修改。我们看看例子

#! /usr/bin/env python

-- coding: utf-8 --

def test(val, data = []): data.append(val) return data def main(): for i in xrange(10): print(test(i)) if name == 'main': main()

想象的输出:

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

实际输出如下:

[0] [0, 1] [0, 1, 2] [0, 1, 2, 3] [0, 1, 2, 3, 4] [0, 1, 2, 3, 4, 5] [0, 1, 2, 3, 4, 5, 6] [0, 1, 2, 3, 4, 5, 6, 7] [0, 1, 2, 3, 4, 5, 6, 7, 8] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

可以看得出函数的默认值一直引用都是同一个对象,所以传入参数的时候修改的还是同一个对象。所以要避免在默认值定义可变的对象。那一定要传入有个默认值list呢?官方文档给出了个例子:

def whats_on_the_telly(penguin=None): if penguin is None: penguin = [] penguin.append("property of the zoo") return penguin

默认值定义为None,如果是None就初始化,这样就不会导致修改的是同一个对象了。还可以用or来简化,我也是从lua那边看到的,表示如果penguin是真值就直接赋值,否则创建一个list对象。最后,如果你的时间不是很紧张,并且又想快速的python提高,最重要的是不怕吃苦,建议你可以架尉♥信(同音):276 3177 065 ,那个真的很不错,很多人进步都很快,需要你不怕吃苦哦!大家可以去添加上看一下~

penguin = penguin or []

3.5. lambda表达式

lambda表达式定义一个匿名函数,多用于作为参数传入给函数。先看个例子,数组排序的sorted()

def main(): datas = {"Tom":10, "Mary":3, "Faker": 5, "Doinb": 100} sorted_list = sorted(datas.items(), key=lambda v: v[1], reverse=True) for name, vote_num in sorted_list: print(name, vote_num)

if name == 'main': main()`

datas是保存着主播对应的票数,现在想对他们进行排序后按降序打印出来。下面对上面代码进行解释:

datas.items()把字典转化为一个数组,里面元素是一个二元的tuple,如d = ("Tom", 10), d[0]=>Tom, d[1] => 10。
key=lambda v: v[1]其中key表示传入一个函数,参数v是传入一个个二元数组,然后函数的返回值是v[1]就是对应的票数,连起来看就是每个二元组经过key对应的匿名函数后,返回了票数作为排序字段。
复制代码

lambda表达式一般用在这种情况,函数简单易懂,又不会影响调用者查看代码,如果要复杂了,sorted的调用就很容易出错,还不如另外定义一个函数更直观更保险。 4. 总结

写完这篇之后,突然感慨Python还是有很多小东西要注意的,回想起那段刚进前公司的时光,留下了都是奋斗的记忆,也很感谢那时候刚起步的部门和新人的我一起成长,能有更多机会去遇坑填坑。

おすすめ

転載: juejin.im/post/7047087093721333791