tongsiying

阅读|运动|自律

0%

第2篇:Pyhon快速上手

本节目标

学习Python最基础的语法知识,可以用代码快速实现一些简单的功能

内容概要

  • 输入和输出

  • 初识数据类型

  • 变量

  • 注释

  • 运算符

  • 格式化输出

一、输入和输出

1. 输出——print

1
print(self, *args, sep=' ', end='\n', file=None): # known special case of print

1.1 将结果或内容呈现给用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
print("                           _ooOoo_  ")
print(" o8888888o ")
print(" 88 . 88 ")
print(" (| -_- |) ")
print(" O\\ = /O ")
print(" ____/`---'\\____ ")
print(" . ' \\| |// `. ")
print(" / \\||| : |||// \\ ")
print(" / _||||| -:- |||||- \\ ")
print(" | | \\\\\\ - /// | | ")
print(" | \\_| ''\\---/'' | | ")
print(" \\ .-\\__ `-` ___/-. / ")
print(" ___`. .' /--.--\\ `. . __ ")
print(" ."" '< `.___\\_<|>_/___.' >'"". ")
print(" | | : `- \\`.;`\\ _ /`;.`/ - ` : | | ")
print(" \\ \\ `-. \\_ __\\ /__ _/ .-` / / ")
print(" ======`-.____`-.___\\_____/___.-`____.-'====== ")
print(" `=---=' ")
print(" ")
print(" ............................................. ")
print(" 佛祖镇楼 BUG辟易 ")
print(" 佛曰: ")
print(" 写字楼里写字间,写字间里程序员; ")
print(" 程序人员写程序,又拿程序换酒钱。 ")
print(" 酒醒只在网上坐,酒醉还来网下眠; ")
print(" 酒醉酒醒日复日,网上网下年复年。 ")
print(" 但愿老死电脑间,不愿鞠躬老板前; ")
print(" 奔驰宝马贵者趣,公交自行程序员。 ")
print(" 别人笑我忒疯癫,我笑自己命太贱; ")
print(" 不见满街漂亮妹,哪个归得程序员?")

1.2 关于输出

  • 默认print在尾部会加换行符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    print('文能提笔安天下,')
    print('武能上马定乾坤。')
    print('心存谋略何人胜,')
    print('古今英雄唯是君。')

    输出:
    文能提笔安天下,
    武能上马定乾坤。
    心存谋略何人胜,
    古今英雄唯是君。
  • 想要不换行,则可以这样做

    1
    2
    3
    4
    5
    6
    7
    print('文能提笔安天下,', end='')
    print('武能上马定乾坤。', end='')
    print('心存谋略何人胜,', end='')
    print('古今英雄唯是君。', end='')

    输出:
    文能提笔安天下,武能上马定乾坤。心存谋略何人胜,古今英雄唯是君。
    1
    2
    3
    4
    5
    6
    7
    print('文能提笔安天下', end=',')
    print('武能上马定乾坤', end='。')
    print('心存谋略何人胜', end=',')
    print('古今英雄唯是君', end='。')

    输出:
    文能提笔安天下,武能上马定乾坤。心存谋略何人胜,古今英雄唯是君。

2. 输入——input

1
input(*args, **kwargs)
  • 可以实现程序与用户之间的交互

    1
    2
    3
    4
    5
    6
    7
    8
    9
     #1.使用input获取必要的信息
    name =input("请输入名字:")
    qq=input("请输入qq:")

    #2.使用print来打印名片
    print("="*20)
    print("姓名:%s"%name)
    print("qq:%s"%qq)
    print("="*20)
  • 输入密码时,如果想要不可见,需要利用getpass 模块中的 getpass方法,即:

    1
    2
    3
    4
    5
    import getpass

    username = input('请输入用户名:')
    pwd = getpass.getpass('请输入密码:')
    print(username,pwd)
  • 特别注意:用户输入的任何内容本质上都是字符串。

二、初识数据类型

上学时,老师叫我们数字、拼音、汉字、真假判断等,然后我们根据学到的内容写作文,老师来检查并打分。现在学编程,教大家int、str、bool等,然后大家根据这些内容来写代码,写完代码交给Python解释器去运行。Python中的数据类型很多,而且也允许我们自定义新的数据类型(这一点在后面会讲到),我们先介绍几种常用的数据类型。

  • 整型:Python中可以处理任意大小的整数(Python 2.x中有intlong两种类型的整数,但这种区分对Python来说意义不大,因此在Python 3.x中整数只有int这一种了),而且支持二进制(如0b100,换算成十进制是4)、八进制(如0o100,换算成十进制是64)、十进制(100)和十六进制(0x100,换算成十进制是256)的表示法。
  • 浮点型:浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如123.456)之外还支持科学计数法(如1.23456e2)。
  • 复数型:形如3+5j,跟数学上的复数表示一样,唯一不同的是虚部的i换成了j。实际上,这个类型并不常用,大家了解一下就可以了。
  • 字符串型:字符串是以单引号或双引号括起来的任意文本,比如'hello'"hello",字符串还有原始字符串表示法、字节字符串表示法、Unicode字符串表示法,而且可以书写成多行的形式(用三个单引号或三个双引号开头,三个单引号或三个双引号结尾)。
  • 布尔型:布尔值只有TrueFalse两种值,要么是True,要么是False,在Python中,可以直接用TrueFalse表示布尔值(请注意大小写),也可以通过布尔运算计算出来(例如3 < 5会产生布尔值True,而2 == 1会产生布尔值False)。

1. Number(数字)

Python3 支持 int、float、complex(复数)。在Python 3里,只有一种整数类型 int,表示为长整型,没有 python2 中的 Long。像大多数语言一样,数值类型的赋值和计算都是很直观的。内置的 type() 函数可以用来查询变量所指的对象类型。

  • 定义:

    1
    2
    3
    4
    5
    6
    7
    # 整型 int
    print(666)
    # 小数 float
    print(11.11)
    # 复数 complex
    print(complex(2, -4))
    print(2 - 4j)
  • 整型的运算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 整型加法
    print(2 + 10)
    # 整型减法
    print(10 - 2)
    # 整型乘法
    print(2 * 10)
    # 整型除法
    print(10 / 2)
    # 整型求商/取整
    print(10 // 2)
    # 整型取余/取模
    print(10 % 3)
    # 幂运算 x ** y x的y次方
    print(2 ** 4)

    注意:

    • 1、Python可以同时为多个变量赋值,如a, b = 1, 2。
    • 2、一个变量可以通过赋值指向不同类型的对象。
    • 3、数值的除法包含两个运算符:/ 返回一个浮点数,// 返回一个整数。
    • 4、在混合计算时,Python会把整型转换成为浮点数。
  • 判断类型

    1
    2
    3
    4
    a, b, c = 20, 5.5, 4+3j
    print(type(a), type(b), type(c))
    # 输出
    # <class 'int'> <class 'float'> <class 'bool'> <class 'complex'>

    此外还可以用 isinstance 来判断:

    1
    2
    3
    a = 111
    print(isinstance(a, int))
    # True

    isinstancetype 的区别在于:

    • type()不会认为子类是一种父类类型。
    • isinstance()会认为子类是一种父类类型。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class A:
    pass
    class B(A):
    pass

    print(isinstance(A(), A))
    # True
    print(type(A()) == A)
    # True
    print(isinstance(B(), A))
    # True
    print(type(B()) == A)
    # False

2. 字符串(str)

字符串,其实就是生活中的文本信息,例如:姓名、地址、自我介绍等。

字符串有一个特点,他必须由引号引起来,引号可以是’x’、”x”、’’’x’’’、”””x”””如:

  • 单行字符串

    1
    2
    3
    4
    print('我是张亚飞')
    print("我是张亚飞")
    print("我是'张亚飞'")
    print('我是"张亚飞"')
  • 多行字符串

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    print("中国山西晋中市")
    print('''中国山西晋中市
    xxxxxxxxx
    xxxxxxxx
    xxxxxxx
    ''')
    print("""中国山西晋中市
    xxxxxxxxx
    xxxxxxxx
    xxxxxxx
    """)

对于字符串

  • 加,两个字符串可以通过加好拼接起来。

    1
    print("君子"  + "成人之美")
  • 乘,整型和字符串相乘,以实现让字符串重复出现N次并拼接起来。

    1
    2
    3
    4
    5
    6
    print("我想吃饺子我想吃饺子我想吃饺子我想吃饺子")
    print('我想吃饺子' * 4)

    输出
    我想吃饺子我想吃饺子我想吃饺子我想吃饺子
    我想吃饺子我想吃饺子我想吃饺子我想吃饺子

3. 布尔类型

布尔类型中共有两个值:True/False

1
2
3
4
5
print(1 > 2)
print(False)

print(1 == 1)
print(True)
  • 补充
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
print('hello' > 'world')

print( int('100') * 3 )
print( int('123') + int('456') )
print( str(111) + str(222) )
print( str(111) * 3 )
print( int('8') * 7 )
print( str(111) == 111 )
print( bool(-1) )
print( bool(0) )
print( bool('') )
print( bool('你好') )
print( True == True )
print( True == False )
print( bool('') == bool(0) )
  • 进行逻辑判断(比如if)时,Python当中等于False的值并不只有False一个,它也有一套规则。对于基本类型来说,基本上每个类型都存在一个值会被判定为False。大致是这样:

    • 布尔型,False表示False,其他为True
    • 整数和浮点数,0表示False,其他为True
    • 字符串和类字符串类型(包括bytes和unicode),空字符串表示False,其他为True
    • 序列类型(包括tuple,list,dict,set等),空表示False,非空表示True
    • None永远表示False
  • 自定义类型则服从下面的规则:

    • 如果定义了nonzero()方法,会调用这个方法,并按照返回值判断这个对象等价于True还是False
    • 如果没有定义nonzero方法但定义了len方法,会调用len方法,当返回0时为False,否则为True(这样就跟内置
    • 类型为空时对应False相同了)
    • 如果都没有定义,所有的对象都是True,只有None对应False
  • 注意:在 Python2 中是没有布尔型的,它用数字 0 表示 False,用 1 表示 True。到 Python3 中,把 True 和 False 定义成关键字了,但它们的值还是 1 和 0,它们可以和数字相加。

    1
    True + True  # 1 + 1 = 2

4. 类型转换

上文对数据类型int/str/bool有了初步了解,他们都有自己的定义方式:

  • int,整数定义时,必须是数字且无引号,例如:5,8,9
  • str,字符串定义时,必须用双引号括起来,例如:”中国”,”陈月”,”666”
  • bool,布尔值定义时,只能写True和False

不同数据类型有不同的功能,例如:整型可以加减乘除而字符串只能加(拼接)和乘法。

如果想要做转换可遵循一个基本规则:想转换什么数据类型就让他包裹一层该数据类型。

例如:str(666) == “666”是让整型咋混换为字符串,int(‘888’) == 888是字符串转整型。

  • 转换为整型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 字符串转换为整型(渡可渡之人)
    int('666')
    int('999')

    '6' + '9' == '69'
    int('6') + int('9') == 15

    int('今天天气真好') # 报错

    # 布尔类型转换为整型
    int(True) 转换完等于1
    int(False) 转换完等于0
  • 转换为字符串

    1
    2
    3
    4
    5
    6
    7
    # 整型转字符串
    str(234)
    str(666) + str(999) 结果为 '666999'

    # 布尔类型转换为字符串
    str(True) "True"
    str(False) "False"
  • 转换为布尔类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 整型转布尔
    bool(1) True
    bool(2) True
    bool(0) False
    bool(-10) True

    # 字符串转布尔
    bool('nice') True
    bool('自作自受') True
    bool('') False
    bool(' ') True
  • 三句话搞定类型转换

    • 其他所有类型转换为布尔类型时,除了空字符串、0以为其他都是True。
    • 字符串转整型时,只有那种”888”格式的字符串才可以转换为整型,其他都报错。
    • 想要转换为哪种类型,就用这类型的英文包裹一下就行。
    1
    2
    3
    str(...)
    int(...)
    bool(...)

三、变量

在程序设计中,变量是一种存储数据的载体。计算机中的变量是实际存在的数据或者说是存储器中存储数据的一块内存空间,变量的值可以被读取和修改,这是所有计算和控制的基础。变量,其实就是我们生活中起别名和外号,让变量名指向某个值,格式为:【变量名=值】,以后可以通过变量名来操作其对应的值。

1
2
name = '张亚飞'
print(name) # 张亚飞
1
2
3
4
5
6
7
8
age = 18
name = 'xiaoming'
flag = 1 > 18
address = '山西太原' + '迎泽'
addr = '山西太原' + '迎泽' + name

print(addr)
print(flag)

注意:

  • 给变量赋值age = 18
  • 让age代指值age = 18

1. 变量名的规范

1
2
3
4
age = 18
name = 'xiaoming'
flag = 1 > 18
address = '山西太原' + '迎泽'

1.1 硬性规范:(不符合规范会报错)

  • 变量名只能有字母、数字、下划线组成

  • 不能以数字开头

  • 不能用Python内置关键字

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    In [3]: help('keywords')

    Here is a list of the Python keywords. Enter any keyword to get more help.

    False def if raise
    None del import return
    True elif in try
    and else is while
    as except lambda with
    assert finally nonlocal yield
    break for not
    class from or
    continue global pass

1.2 PEP8变量命名建议:

  • 用小写字母拼写,多个单词用下划线连接。

    1
    2
    3
    4
    englishScore = 100  #小驼峰
    english_score = 100 #下划线,推荐
    EnglishScore = 100 #大驼峰
    englishscore = 100 #不推介
  • 受保护的实例属性用单个下划线开头(后面会讲到)

  • 私有的实例属性用两个下划线开头(后面会讲到)。

其他规范:

  • 当然,作为一个专业的程序员,给变量(事实上应该是所有的标识符)命名时应做到见名知意。

2. 变量的使用

下面通过几个例子来说明变量的类型和变量使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 不使用变量
print(1 + 2 + 43 + 5 + 56)
print((1 + 2 + 43 + 5 + 56) * 2 / 3)
print((((1 + 2 + 43 + 5 + 56) * 2 / 3) + 100) / 5)

# 使用变量
x = 1 + 2 + 43 + 5 + 56
y = x * 2 / 3
z = (y + 100) / 5
print(z)
# 同时为多个变量赋值
a = b = c = 1
# 以上实例,创建一个整型对象,值为 1,从后向前赋值,三个变量被赋予相同的数值。
# 为多个对象指定多个变量
e, d, f = 1, 2, 'Python'
# 两个整型对象 1 和 2 的分配给变量 a 和 b,字符串对象 "Python" 分配给变量 c。

# 变量的含义
score = 100 # 定义了一个变量,这个变量的名字叫做score,它里面存储了一个数值100
high = 180 # 单位是cm

appleprice = 3.5 # 苹果的价格 元/斤
weight = 7.5 # 购买的苹果的重量 斤

money = appleprice * weight # 如果money是第一次的话,那么就表示定义这个变量

money = money - 10 # 如果money=xxxx不是第一次出现,那么就不是定义一个变量,而是给这个变量附上一个新的值

# 变量的类型 可以是Python中任何合法的类型
num = 666
string = 'Life is short,I use Python'
flag = 1 > 10
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

在Python中可以使用type函数对变量的类型进行检查。程序设计中函数的概念跟数学上函数的概念是一致的,数学上的函数相信大家并不陌生,它包括了函数名、自变量和因变量。如果暂时不理解这个概念也不要紧,我们会在后续的章节中专门讲解函数的定义和使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
"""
使用type()检查变量的类型
"""
a = 100
b = 12.345
c = 1 + 5j
d = 'hello, world'
e = True
print(type(a)) # <class 'int'>
print(type(b)) # <class 'float'>
print(type(c)) # <class 'complex'>
print(type(d)) # <class 'str'>
print(type(e)) # <class 'bool'>

可以使用Python中内置的函数对变量类型进行转换。

  • int():将一个数值或字符串转换成整数,可以指定进制。
  • float():将一个字符串转换成浮点数。
  • str():将指定的对象转换成字符串形式,可以指定编码。
  • chr():将整数转换成该编码对应的字符串(一个字符)。
  • ord():将字符串(一个字符)转换成对应的编码(整数)。

下面的代码通过键盘输入两个整数来实现对两个整数的算术运算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"""
使用input()函数获取键盘输入(字符串)
使用int()函数将输入的字符串转换成整数
使用print()函数输出带占位符的字符串
"""
a = int(input('a = '))
b = int(input('b = '))
print('%d + %d = %d' % (a, b, a + b))
print('%d - %d = %d' % (a, b, a - b))
print('%d * %d = %d' % (a, b, a * b))
print('%d / %d = %f' % (a, b, a / b))
print('%d // %d = %d' % (a, b, a // b))
print('%d %% %d = %d' % (a, b, a % b))
print('%d ** %d = %d' % (a, b, a ** b))

说明:上面的print函数中输出的字符串使用了占位符语法,其中%d是整数的占位符,%f是小数的占位符,%%表示百分号(因为百分号代表了占位符,所以带占位符的字符串中要表示百分号必须写成%%),字符串之后的%后面跟的变量值会替换掉占位符然后输出到终端中,运行上面的程序,看看程序执行结果就明白啦。

3. 变量内存指向关系

学习上述变量知识让我们对变量有了初步认识,接下来我们从稍微高级点的角度来学习变量。即内存指向(在电脑内存中是怎么存储的)。

3.1 情景一:

1
name = 'zhangyafei'

在计算机内存中创建一块区域保存字符串“zhangyafei”,name变量名则指向这块区域。

3.2 情景二:

1
2
name = 'zhangyafei'
name = 'xiaoming'

在计算机内存中创建一块区域保存字符串‘zhangyafei’,name变量名则指向这块区域。然后又再向内存中创建了一块区域保存字符串‘’xiaoming”,name变量名则指向”xiaoming“所在的区域,不再指向”zhangyafei“所在区域(无人指向的数据会被标记为垃圾,由解释器自动化回收)

变量内存指向-情景2

3.3 情景三:

1
2
name = 'zhangyafei'
new_name = name

在计算机内存中创建一块区域保存字符串‘zhangyafei’,name变量名则指向这块区域。new_name变量名指向name变量,因为被指向的是变量名,所以自动转指向到name变量代表的内存区域。

变量内存指向-情景3

3.4 情景四:

1
2
3
name = 'zhangyafei'
new_name = name
name = 'xiaoming'

在计算机内存中创建一块区域保存字符串‘zhangyafei’,name变量名则指向这块区域。new_name变量名指向name所指向的内存区域,最后又创建了一个区域存放’xiaoming‘,让name变量指向xiaoming’所在区域。

变量内存指向-情景4

3.5 情景五:

1
2
num = 18
age = str(num)

在计算机的内存中创建一块区域保存整型18,name变量名则指向这块区域。通过类型转换依据整型18再在内存中创建一个字符串“18”,age变量指向保存这个字符串的内存区域。

变量内存指向-情景5

四、注释

写代码时候如果想要对某内容进行注释处理,及:解释器忽略不会按照代码去执行

  • 单行注释:# 注释内容

    1
    2
    3
    4
    5
    6
    # 声明一个name含量
    name = 'xiaoming'

    age = 19 # 当前用户年龄

    注意:快键键 command + ? 和ctrl + ?
  • 多行注释:三个单引号或三个双引号内添加多行注释内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 声明一个name含量
    # 声明一个name含量
    # 声明一个name含量
    name = 'xiaoming'

    """
    多行注释内容
    多行注释内容
    多行注释内容
    """
    age = 19 # 当前用户年龄

五、运算符

什么是运算符呢?

1
4 + 5 = 9

例子中,45 被称为操作数+ 称为运算符

Python支持多种运算符,本节内容将包含以下内容:

  • 算数运算符
  • 比较运算符
  • 赋值运算符
  • 逻辑运算符
  • 位运算符
  • 成员运算符
  • 身份运算符
  • 运算符优先级

1. 算数运算符

运算符 描述 实例
+ 加 - 两个对象相加 a + b 输出结果 31
- 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -11
* 乘 - 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 210
/ 除 - x 除以 y b / a 输出结果 2.1
% 取模 - 返回除法的余数 b % a 输出结果 1
** 幂 - 返回x的y次幂 a**b 为10的21次方
// 取整除 - 向下取接近商的整数 >>> 9//2 4 >>> -9//2 -5

2. 比较运算符

运算符 描述 实例
== 等于 - 比较对象是否相等 (a == b) 返回 False。
!= 不等于 - 比较两个对象是否不相等 (a != b) 返回 True。
> 大于 - 返回x是否大于y (a > b) 返回 False。
< 小于 - 返回x是否小于y。 (a < b) 返回 True。
>= 大于等于 - 返回x是否大于等于y。 (a >= b) 返回 False。
<= 小于等于 - 返回x是否小于等于y。 (a <= b) 返回 True。

比较运算符有的地方也称为关系运算符,包括==!=<><=>=,我相信没有什么好解释的,大家一看就能懂,唯一需要提醒的是比较相等用的是==,请注意这个地方是两个等号,因为=是赋值运算符,我们在上面刚刚讲到过,==才是比较相等的比较运算符。比较运算符会产生布尔值,要么是True要么是False

3. 赋值运算符

运算符 描述 实例
= 简单的赋值运算符 c = a + b 将 a + b 的运算结果赋值为 c
+= 加法赋值运算符 c += a 等效于 c = c + a
-= 减法赋值运算符 c -= a 等效于 c = c - a
*= 乘法赋值运算符 c *= a 等效于 c = c * a
/= 除法赋值运算符 c /= a 等效于 c = c / a
%= 取模赋值运算符 c %= a 等效于 c = c % a
**= 幂赋值运算符 c *= a 等效于 c = c * a
//= 取整除赋值运算符 c //= a 等效于 c = c // a
:= 海象运算符,可在表达式内部为变量赋值。

海象运算符的三种用法

  • 用法1:if/else

    在 Golang 中的条件语句可以直接在 if 中运算变量的获取后直接对这个变量进行判断,可以让你少写一行代码

    1
    2
    3
    4
    5
    6
    7
    import "fmt"

    func main() {
    if age := 20;age > 18 {
    fmt.Println("已经成年了")
    }
    }

    若在 Python 3.8 之前,Python 必须得这样子写

    1
    2
    3
    age = 20
    if age > 18:
    print("已经成年了")

    但有了海象运算符之后,你可以和 Golang 一样(如果你没学过 Golang,那这里要注意,Golang 中的 := 叫短变量声明,意思是声明并初始化,它和 Python 中的 := 不是一个概念)

    1
    2
    if (age:= 20) > 18:
    print("已经成年了")
  • 用法2:while

    在不使用 海象运算符之前,使用 while 循环来读取文件的时候,你也许会这么写

    1
    2
    3
    4
    5
    6
    file = open("demo.txt", "r")
    while True:
    line = file.readline()
    if not line:
    break
    print(line.strip())

    但有了海象运算符之后,你可以这样

    1
    2
    3
    file = open("demo.txt", "r")
    while (line := file.readline()):
    print(line.strip())

    使用它替换以往的无限 while 循环写法更为惊艳

    比如,实现一个需要命令行交互输入密码并检验的代码,你也许会这样子写

    1
    2
    3
    4
    while True:
    p = input("Enter the password: ")
    if p == "youpassword":
    break

    有了海象运算符之后,这样子写更为舒服

    1
    2
    while (p := input("Enter the password: ")) != "youpassword":
    continue
  • 用法3:推导式

    这个系列的文章,几乎每篇都能看到推导式的身影,这一篇依旧如此。

    在编码过程中,我很喜欢使用推导式,在简单的应用场景下,它简洁且不失高效。

    如下这段代码中,我会使用列表推导式得出所有会员中过于肥胖的人的 bmi 指数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    members = [
    {"name": "小五", "age": 23, "height": 1.75, "weight": 72},
    {"name": "小李", "age": 17, "height": 1.72, "weight": 63},
    {"name": "小陈", "age": 20, "height": 1.78, "weight": 82},
    ]

    count = 0

    def get_bmi(info):
    global count
    count += 1

    print(f"执行了 {count} 次")

    height = info["height"]
    weight = info["weight"]

    return weight / (height**2)

    # 查出所有会员中过于肥胖的人的 bmi 指数
    fat_bmis = [get_bmi(m) for m in members if get_bmi(m) > 24]

    print(fat_bmis)

    输出如下

    1
    2
    3
    4
    5
    执行了 1
    执行了 2
    执行了 3
    执行了 4
    [25.88057063502083]

    可以看到,会员数只有 3 个,但是 get_bmi 函数却执行了 4 次,原因是在判断时执行了 3 次,而在构造新的列表时又重复执行了一遍。

    如果所有会员都是过于肥胖的,那最终将执行 6 次,这种在大量的数据下是比较浪费性能的,因此对于这种结构,我通常会使用传统的for 循环 + if 判断。

    1
    2
    3
    4
    5
    6
    7
    fat_bmis = []

    # 查出所有会员中过于肥胖的人的 bmi 指数
    for m in members:
    bmi = get_bmi(m)
    if bmi > 24:
    fat_bmis.append(bmi)

    在有了海象运算符之后,你就可以不用在这种场景下做出妥协。

    1
    2
    # 查出所有会员中过于肥胖的人的 bmi 指数
    fat_bmis = [bmi for m in members if (bmi := get_bmi(m)) > 24]

    最终从输出结果可以看出,只执行了 3 次

    1
    2
    3
    4
    执行了 1
    执行了 2
    执行了 3
    [25.88057063502083]

4. 逻辑运算符

运算符 逻辑表达式 描述 实例
and x and y 布尔”与” - 如果 x 为 False,x and y 返回 x 的值,否则返回 y 的计算值。 (a and b) 返回 20。
or x or y 布尔”或” - 如果 x 是 True,它返回 x 的值,否则它返回 y 的计算值。 (a or b) 返回 10。
not not x 布尔”非” - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 not(a and b) 返回 False

and、or运算规则

  • x or y 的值只可能是x或y. x为真就是x, x为假就是y
  • x and y 的值只可能是x或y. x为真就是y, x为假就是x
1
2
3
4
v1 = 0 or 4 and 3 or 7 or 9 and 6
= 0 or 3 or 7 or 6
= 3 or 7 or 6
= 3

逻辑运算符有三个,分别是andornotand字面意思是“而且”,所以and运算符会连接两个布尔值,如果两个布尔值都是True,那么运算的结果就是True;左右两边的布尔值有一个是False,最终的运算结果就是False。相信大家已经想到了,如果and左边的布尔值是False,不管右边的布尔值是什么,最终的结果都是False,所以在做运算的时候右边的值会被跳过(短路处理),这也就意味着在and运算符左边为False的情况下,右边的表达式根本不会执行。or字面意思是“或者”,所以or运算符也会连接两个布尔值,如果两个布尔值有任意一个是True,那么最终的结果就是True。当然,or运算符也是有短路功能的,在它左边的布尔值为True的情况下,右边的表达式根本不会执行。not运算符的后面会跟上一个布尔值,它的作用是得到与该布尔值相反的值,也就是说,后面的布尔值如果是True运算结果就是False,而后面的布尔值如果是False则运算结果就是True

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"""
比较运算符和逻辑运算符的使用
"""
flag0 = 1 == 1
flag1 = 3 > 2
flag2 = 2 < 1
flag3 = flag1 and flag2
flag4 = flag1 or flag2
flag5 = not (1 != 2)
print('flag0 =', flag0) # flag0 = True
print('flag1 =', flag1) # flag1 = True
print('flag2 =', flag2) # flag2 = False
print('flag3 =', flag3) # flag3 = False
print('flag4 =', flag4) # flag4 = True
print('flag5 =', flag5) # flag5 = False

说明:比较运算符的优先级高于赋值运算符,所以flag0 = 1 == 1先做1 == 1产生布尔值True,再将这个值赋值给变量flag0print函数可以输出多个值,多个值之间可以用,进行分隔,输出的内容之间默认以空格分开。

5. 位运算符

运算符 含义 示例
& 按位与(AND):参与运算的两个值的两个相应位都为1,则该位的结果为1;否则为0 x & y
` ` 按位或(OR):参与运算的两个值的两个相应位有一个为1,则该位的结果为1;否则为0
~ 按位翻转/取反(NOT):对数据的每个二进制位取反,即把 1 变为 0 ,把 0 变为 1 ~x
^ 按位异或(XOR):当两个对应的二进制位相异时,结果为1 x ^ y
>> 按位右移 :运算数的各个二进制位全部右移若干位 x >> 2
<< 按位左移:运算数的各个二进制位全部左移若干位,高位丢弃,地位不补 0 x << 2

6. 成员运算符

运算符 描述 实例
in 如果在指定的序列中找到值返回 True,否则返回 False。 x 在 y 序列中 , 如果 x 在 y 序列中返回 True。
not in 如果在指定的序列中没有找到值返回 True,否则返回 False。 x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。

7. 身份运算符

运算符 含义 示例
is 如果对象的引用指向同一片内存,则为 True(引用同一个对象) x is True
is not 如果对象的引用不相同,则为 True(引用不同的对象) x is not True

8. 运算符优先级

上述所有运算符优先级从高到低总结:算数运算符 > 位运算符 > 比较运算符 > 身份运算符 > 成员运算符 > 逻辑运算符 > 赋值运算符。具体如下:

运算符 描述
[] [:] 下标,切片
** 指数
~ + - 按位取反, 正负号
* / % // 乘,除,模,整除
+ - 加,减
>> << 右移,左移
& 按位与
^ ` `
<= < > >= 小于等于,小于,大于,大于等于
== != 等于,不等于
is is not 身份运算符
in not in 成员运算符
not or and 逻辑运算符
= += -= *= /= %= //= **= &= ` 赋值运算符

说明: 在实际开发中,如果搞不清楚运算符的优先级,可以使用加括号来确保运算的执行顺序。

9. 练习

9.1 练习1:

华氏温度转换为摄氏温度

提示:华氏温度到摄氏温度的转换公式为:C=(F−32)÷1.8C=(F−32)÷1.8。

参考答案:

1
2
3
4
5
6
"""
将华氏温度转换为摄氏温度
"""
f = float(input('请输入华氏温度: '))
c = (f - 32) / 1.8
print('%.1f华氏度 = %.1f摄氏度' % (f, c))

说明:在使用print函数输出时,也可以对字符串内容进行格式化处理,上面print函数中的字符串%1.f是一个占位符,稍后会由一个float类型的变量值替换掉它。同理,如果字符串中有%d,后面可以用一个int类型的变量值替换掉它,而%s会被字符串的值替换掉。除了这种格式化字符串的方式外,还可以用下面的方式来格式化字符串,其中{f:.1f}{c:.1f}可以先看成是{f}{c},表示输出时会用变量f和变量c的值替换掉这两个占位符,后面的:.1f表示这是一个浮点数,小数点后保留1位有效数字。

1
print(f'{f:.1f}华氏度 = {c:.1f}摄氏度')

9.2 练习2:

输入圆的半径计算计算周长和面积

参考答案:

1
2
3
4
5
6
7
8
"""
输入半径计算圆的周长和面积
"""
radius = float(input('请输入圆的半径: '))
perimeter = 2 * 3.1416 * radius
area = 3.1416 * radius * radius
print('周长: %.2f' % perimeter)
print('面积: %.2f' % area)

9.3 练习3:

输入年份判断是不是闰年

参考答案:

1
2
3
4
5
6
7
8
"""
输入年份 如果是闰年输出True 否则输出False
"""
year = int(input('请输入年份: '))
# 如果代码太长写成一行不便于阅读 可以使用\对代码进行折行
is_leap = year % 4 == 0 and year % 100 != 0 or \
year % 400 == 0
print(is_leap)

说明:比较运算符会产生布尔值,而逻辑运算符andor会对这些布尔值进行组合,最终也是得到一个布尔值,闰年输出True,平年输出False

六、格式化输出

格式化输出又叫字符串格式化,使用更便捷的形式实现字符串的拼接。格式化字符串时,Python使用一个字符串作为模板。模板中有格式符,这些格式符为真实值预留位置,并说明真实数值应该呈现的格式。Python用一个tuple将多个值传递给模板,每个值对应一个格式符。

  • 格式化占位符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    %s    字符串 (采用str()的显示)
    %r 字符串 (采用repr()的显示)
    %c 单个字符
    %b 二进制整数
    %d 十进制整数
    %i 十进制整数
    %o 八进制整数
    %x 十六进制整数
    %e 指数 (基底写为e)
    %E 指数 (基底写为E)
    %f 浮点数
    %F 浮点数,与上相同
    %g 指数(e)或浮点数 (根据显示长度)
    %G 指数(E)或浮点数 (根据显示长度)
    %% 字符"%
  • 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
name = '张亚飞'
age = 18
job = '学生'
hobby = '打篮球'

# %
print('我叫%s,我的年龄是%d,我是一名%s,我的爱好是%s' % (name, age, job, hobby))

# format
print('我叫{0},我的年龄是{1},我是一名{2},我的爱好是{3}'.format(name, age, job, hobby))

# f-string
print(f'我叫{name},我的年龄是{age},我是一名{job},我的爱好是{hobby}')

1. %

1.1 整数输出

  • %o —— oct 八进制
  • %d —— dec 十进制
  • %x —— hex 十六进制
1
2
3
4
5
6
7
In [1]: print('%o'%10)
12

In [2]: print('%x'%10)
a

In [3]: print('%x'%20)

1.2 浮点数

  • %f ——默认保留小数点后面六位有效数字
    • %.3f,保留3位小数位
  • %e ——默认保留小数点后面六位有效数字,指数形式输出
    • %.3e,保留3位小数位,使用科学计数法
  • %g ——在保证六位有效数字的前提下,使用小数方式,否则使用科学计数法
    • %.3g,保留3位有效数字,使用小数或科学计数法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
In [11]: print('%f' % 1.11)  # 默认保留6位小数
1.110000


In [12]: print('%.1f' % 1.11) # 取1位小数
1.1

In [13]: print('%e' % 1.11) # 默认6位小数,用科学计数法
1.110000e+00

In [14]: print('%.3e' % 1.11) # 取3位小数,用科学计数法
1.110e+00

In [15]: print('%g' % 1111.1111) # 默认6位有效数字
1111.11

In [16]: print('%.7g' % 1111.1111) # 取7位有效数字
1111.111

In [17]: print('%.2g' % 1111.1111) # 取2位有效数字,自动转换为科学计数法
1.1e+03

1.3 字符串输出

  • %s
  • %10s——右对齐,占位符10位
  • %-10s——左对齐,占位符10位
  • %.2s——截取2位字符串
  • %10.2s——10位占位符,截取两位字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
In [18]: print('%s' % 'hello world')  # 字符串输出
hello world

In [19]: print('%20s' % 'hello world') # 右对齐,取20位,不够则补位
hello world

In [20]: print('%-20s' % 'hello world') # 左对齐,取20位,不够则补位
hello world

In [21]: print('%.2s' % 'hello world') # 取2位
he

In [22]: print('%10.2s' % 'hello world') # 右对齐,取2位
he

In [23]: print('%-10.2s' % 'hello world') # 左对齐,取2位
he

1.4 示例

1
2
3
4
5
# 格式的字符串与被格式化的字符串必须一一对应,需格式化的字符串多时,容易搞混
print('我叫%s,我的年龄是%d,我是一名%s,我的爱好是%s' % (name, age, job, hobby))
# 通过字典方式格式化,哪个字符将会格式化到哪里,清晰命了
print('我叫%(name)s,我的年龄是%(age)d,我是一名%(job)s,我的爱好是%(hobby)s' % {"name": name, "age": age, "job": job, "hobby":hobby})
print('我叫%(name)s,我的年龄是%(age)d,我是一名%(job)s,我的爱好是%(hobby)s' % {"name": name, "age": age, "job": job, "hobby":hobby})

2. format

2.1 使用位置参数

1
2
print('我叫{0},我的年龄是{1},我是一名{2},我的爱好是{3}'.format(name, age, job, hobby))
print('我叫{1},我的年龄是{0},我是一名{3},我的爱好是{2}'.format(age, name, hobby, job))

2.2 字典格式化

1
2
3
print('我叫{name},我的年龄是{age},我是一名{job},我的爱好是{hobby}'.format(name=name, age=age, job=job, hobby=hobby))
args = {"name": name, "age": age, "job": job, "hobby":hobby}
print('我叫{name},我的年龄是{age},我是一名{job},我的爱好是{hobby}'.format(**args))

2.3 填充与格式化

1
2
3
print('{0:*<10}'.format('张亚飞'))
print('{0:*>10}'.format('张亚飞'))
print('{0:*^10}'.format('张亚飞'))

2.4 精度与进制

1
2
3
4
5
print('{0:.2f}'.format(1232132.12321))  #精确到小数点后两位
print('{0:b}'.format(10)) #二进制
print('{0:o}'.format(10)) #八进制
print('{0:x}'.format(10)) # 十六进制
print('{0:,}'.format(123232244324)) #千分位格式化

3. f-string

到Python3.6版本,更便捷。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
print(f'我叫{name},我的年龄是{age},我是一名{job},我的爱好是{hobby}')

# 进制转换
print(f"小明今年{22}岁")
print(f"小明今年{22:#b}岁")
print(f"小明今年{22:#o}岁")
print(f"小明今年{22:#x}岁")

# 填充与格式化
print(f'{name:*<10}')
print(f'{name:*>10}')
print(f'{name:*^10}')

# 精度
print(f"小明今年{22:6.3f}岁")

# python3.8引入
text = f"小明的有一只猫名字叫喵喵,今年{19 + 2=}岁"
print(text)

如果需要进一步控制格式化语法中变量值的形式,可以参照下面的表格来进行字符串格式化操作。

变量值 占位符 格式化结果 说明
3.1415926 {:.2f} '3.14' 保留小数点后两位
3.1415926 {:+.2f} '+3.14' 带符号保留小数点后两位
-1 {:+.2f} '-1.00' 带符号保留小数点后两位
3.1415926 {:.0f} '3' 不带小数
123 {:0>10d} 0000000123 左边补0,补够10位
123 {:x<10d} 123xxxxxxx 右边补x ,补够10位
123 {:>10d} ' 123' 左边补空格,补够10位
123 {:<10d} '123 ' 右边补空格,补够10位
123456789 {:,} '123,456,789' 逗号分隔格式
0.123 {:.2%} '12.30%' 百分比格式
123456789 {:.2e} '1.23e+08' 科学计数法格式

4. 模板字符串

来看一个例子

1
2
3
4
from string import Template
t = Template('Hey, $name!')
t.substitute(name=name)
Out[280]: 'Hey, ZhangYafei!'

你可以看到我们需要先从Python的内建 string 模块中导入 Template 类。模板字符串并不是核心的语言特征,但是它们由Python标准库的string提供的。

1
2
3
4
from string import Template

t = Template('我叫$name,我的年龄是$age,我是一名$job,我的爱好是$hobby')
print(t.substitute(name=name, age=age, job=job, hobby=hobby))

但是该什么时候才在你的代码中使用模板字符串呢?

其他一些复杂的字符串格式化技巧的可能会给你的程序带来安全漏洞,例如,格式化字符串可以访问你程序里任意的变量。这意味着,如果一个恶意用户可以提供一个格式化字符串,他们就有可能泄露安全密匙以及其他敏感的信息!下面是一个简单的例子证明这些可能可以用来影响你的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
""" format安全漏洞 """
SECRET = 'this-is-a-secret'

class Event:
def __init__(self):
pass

user_input = '{event.__init__.__globals__[SECRET]}'
event = Event()
print(user_input.format(event=event))

""" 模板字符串 """
from string import Template

user_input = '${event.__init__.__globals__[SECRET]}'
print(Template(user_input).substitute(event=event))

5. 应用场景

Python字符串格式化经验法则:如果你的格式化字符串是由用户提供的,那么就是用模板字符串(#4)避免安全问题。不然如果是Python 3.6+的话,就使用字符串插值/f-Strings,如果不是就使用“新式”字符串格式化(str.format)。

赞赏一下吧~