Skip to content

值及其相应的运算

6 / 44

从结构上来看一切的计算机程序都由且只由两个最基本的成分构成

  • 运算(Evaluation)
  • 流程控制(Control Flow)

没有流程控制的是计算器而已有流程控制的才是可编程设备

看看之前我们见过的计算质数的程序:(按一下 ESC确保已经进入命令模式⇧ L 可以切换是否显示代码行号

python
def is_prime(n):            # 定义 is_prime(),接收一个参数
    if n < 2:              # 开始使用接收到的那个参数(值)开始计算……
        return False       # 不再是返回给人,而是返回给调用它的代码……
    if n == 2:
        return True
    for m in range(2, int(n**0.5)+1):
        if (n % m) == 0:
            return False
    else:
        return True

for i in range(80, 110):
    if is_prime(i):          # 调用 is_prime() 函数,
        print(i)            # 如果返回值为 True,则向屏幕输出 i
plaintext
83
89
97
101
103
107
109

if...for... 在控制流程在什么情况下运算什么在什么情况下重复运算什么

13 is_prime() 这个函数的调用也是在控制流程 —— 所以我们可以**把函数看作是子程序” **;

一旦这个函数被调用流程就转向开始执行在第 1 行中定义的 is_prime() 函数内部的代码而这段代码内部还是计算流程控制决定一个返回值 —— 返回值是布尔值再回到第 13 将返回值交给 if 判断决定是否执行第 14 ……

而计算机这种可编程设备之所以可以做流程控制是因为它可以做布尔运算它可以对布尔值进行操作而后将布尔值交给分支循环语句构成了程序中的流程控制

从本质上看程序里的绝大多数语句包含着运算(Evaluation),在对某个值进行评价这里的评价”,不是判断某人某事的好坏”,而是计算出某个值究竟是什么” —— 所以我们用中文的运算翻译这个Evaluation可能表达得更准确一些

在程序中被运算的可分为常量(Literals)变量(Variables)。

python
a = 1 + 2 * 3
a += 1
print(a)

在以上代码中

123都是常量Literal 的意思是字面的”,顾名思义常量的就是它字面上的值1 的值就是 1

a 变量顾名思义它的值将来是可变的比如在第 2 句中这个变量的发生了改变之前是 7之后变成了 8

1 句中的 +*操作符(Operators),它用来对其左右的值进行相应的运算而后得到一个值先是由操作符 * 2 3 进行运算生成一个值6然后再由操作符 + 1 6 进行运算生成一个值 7先算乘除后算加减这是操作符的优先级决定的

= 是赋值符号它的作用是将它右边的值保存到左边的变量中

是程序的基础成分(Building blocks),它就好像盖房子用的砖块一样无论什么样的房子到最后都主要是由砖块构成

常量当然有个 —— 就是它们字面所表达的值

变量必须先赋值才能使用也就是说要先把一个保存到变量中它才能在其后被运算

Python 中每个函数都有返回值即便你在定义一个函数的时候没有设定返回值它也会加上默认的返回值 None……(请注意 None 的大小写!)

python
def f():
    pass
print(f())        # 输出 f() 这个函数被调用后的返回值,None
print(print(f())) # 这一行最外围的 print() 调用了一次 print(f()),所以输出一个 None,
                  # 而后再输出这次调用的返回值,所以又输出一次 None
plaintext
None
None
None

当我们调用一个函数的时候本质上来看就相当于

我们把一个值交给某个函数请函数根据它内部的运算和流程控制对其进行操作而后返回另外一个值

比如abs() 函数就会返回传递给它的绝对值int() 函数会将传递给它的值的小数部分砍掉float() 接到整数参数之后会返回这个整数的浮点数形式

python
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

abs(-3.14159)
int(abs(-3.14159))
float(int(abs(-3.14159)))
plaintext
3.14159
3
3.0

值的类型

在编程语言中总是包含最基本的三种数据类型

  • 布尔值(Boolean Value)
  • 数字(Numbers):整数(Int)、浮点数(Float)、复数(Complex Numbers)
  • 字符串(Strings)

既然有不同类型的数据它们就分别对应着不同类型的值

运算的一个默认法则就是通常情况下应该是相同类型的值才能相互运算

显然数字与数字之间的运算是合理的但你让 + 这个操作符对一个字符串和一个数字进行运算就不行

python
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

11 + 10 - 9 * 8 / 7 // 6 % 5
'3.14' + 3                  # 这一句会报错
plaintext
20.0















plaintext
TypeError                                 Traceback (most recent call last)

<ipython-input-18-e922b7565e53> in <module>
      3
      4 11 + 10 - 9 * 8 / 7 // 6 % 5
----> 5 '3.14' + 3                  # 这一句会报错

TypeError: can only concatenate str (not "int") to str

所以在不得不对不同类型的值进行运算之前总是要事先做 Type Casting类型转换)。比如

  • 将字符串转换为数字用 int()float()
  • 将数字转换成字符串用 str()

另外即便是在数字之间进行计算的时候有时也需要将整数转换成浮点数字或者反之

  • 将整数转换成浮点数字用 float()
  • 将浮点数字转换成整数用 int()

有个函数type()可以用来查看某个值属于什么类型

python
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

type(3)
type(3.0)
type('3.14')
type(True)
type(range(10))
type([1,2,3])
type((1,2,3))
type({1,2,3})
type({'a':1, 'b':2, 'c':3})
plaintext
int
float
str
bool
range
list
tuple
set
dict

操作符

针对不同类型的数据有各自专用的操作符

数值操作符

针对数字进行计算的操作符有加减乘除商余幂+-*///%**

其中 + - 可以对单个值进行操作-3其它的操作符需要有两个值才能操作

从优先级来看这些操作符中

  • 对两个值进行操作的 +- 的优先级最低
  • 稍高的是 *///%
  • 更高的是对单个值进行操作的 +-
  • 优先级最高的是 **

完整的操作符优先级列表参见官方文档

https://docs.python.org/3/reference/expressions.html#operator-precedence

布尔值操作符

针对布尔值操作符有andornot

它们之中优先级最低的是或 or然后是与 and, 优先级最高的是非 not

python
True and False or not True
plaintext
False

最先操作的是 not因为它优先级最高所以上面的表达式相当于 True and False or (not True)即相当于 True and False or False

然后是 and所以True and False or False 相当于是 (True and False) or False即相当于 False or False

于是最终的值是 False

逻辑操作符

数值之间还可以使用逻辑操作符1 > 2 返回布尔值 False逻辑操作符有<小于)、<=小于等于)、>大于)、>=大于等于)、!=不等于)、==等于)。

逻辑操作符的优先级高于布尔值的操作符低于数值计算的操作符数值计算的操作符优先级最高其次是逻辑操作符布尔值的操作符优先级最低

python
n = -95
n < 0 and (n + 1) % 2 == 0
plaintext
True

字符串操作符

针对字符串有三种操作

  • 拼接+ ' '后者是空格
  • 拷贝*
  • 逻辑运算innot in以及<<=>>=!===
python
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

'Awesome' + 'Python'
'Awesome' 'Python'
'Python, ' + 'Awesome! ' * 3
'o' in 'Awesome' and 'o' not in 'Python'
plaintext
'AwesomePython'
'AwesomePython'
'Python, Awesome! Awesome! Awesome! '
False

字符之间字符串之间除了 == != 之外也都可以被逻辑操作符 <<=>>= 运算

python
'a' < 'b'
plaintext
True

这是因为字符对应着 Unicode 字符在被比较的时候被比较的是对应的 Unicode

python
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

'A' > 'a'
ord('A')
ord('a')
plaintext
False
65
97

当字符串被比较的时候将从两个字符串各自的第一个字符开始逐个比较,“一旦决出胜负马上停止”:

python
'PYTHON' > 'Python 3'
plaintext
False

列表的操作符

数字和字符串由字符构成的序列是最基本的数据类型而我们往往需要批量处理数字和字符串这样的时候我们需要数组(Array)。不过 Python 语言中它提供了一个容器(Container)的概念用来容纳批量的数据

Python 的容器有很多种 —— 字符串其实也是容器的一种它的里面容纳着批量的字符

我们先简单接触一下另外一种容器列表(List)。

列表的标示用方括号 []举例来说[1, 2, 3, 4, 5] ['ann', 'bob', 'cindy', 'dude', 'eric']或者 ['a', 2, 'b', 32, 22, 12] 都是一个列表

因为列表和字符串一样都是有序容器容器还有另外一种是无序容器),所以它们可用的操作符其实相同

  • 拼接+ ' '后者是空格
  • 拷贝*
  • 逻辑运算innot in以及<<=>>=!===

两个列表在比较时前提是两个列表中的数据元素类型相同),遵循的还是跟字符串比较相同的规则:“一旦决出胜负马上停止”。但实际上由于列表中可以包含不同类型的元素所以通常情况下没有实际需求对他们进行大于小于的比较。(比较时类型不同会引发 TypeError……)

python
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

a_list = [1, 2, 3, 4, 5]
b_list = [1, 2, 3, 5]
c_list = ['ann', 'bob', 'cindy', 'dude', 'eric']
a_list > b_list
10 not in a_list
'ann' in c_list
plaintext
False
True
True

更复杂的运算

对于数字进行加幂的操作对于字符串进行拼接拷贝属于的操作对布尔值进行或非的操作这些都是相对简单的运算

更为复杂一点的我们要通过调用函数来完成 —— 因为在函数内部我们可以用比单个表达式更为复杂的程序针对传递进来的参数进行运算换言之函数就相当于各种事先写好的子程序给它传递一个值它会对其进行运算而后返回一个值最起码返回一个 None)。

以下是 Python 语言所有的内建函数Built-in Functions):

现在倒不用着急一下子全部了解它们 —— 反正早晚都会的

这其中针对数字有计算绝对值的函数 abs()有计算商余的函数 divmod() 等等

python
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

abs(-3.1415926)
divmod(11, 3)
plaintext
3.1415926
(3, 2)

这些内建函数也依然只能完成基本操作”,比如对于数字我们想计算三角函数的话内建函数就帮不上忙了于是我们需要调用标准库(Standard Library)中的 math 模块(Module):

python
import math
math.sin(5)
plaintext
-0.9589242746631385

代码 math.sin(5) 这里的 .也可以被理解为操作符”,它的作用是

从其它模块中调用函数

代码 math.sin(5) 的作用是

5 这个值传递给 math 这个模块里的 sin() 函数 sin() 根据它内部的代码对这个值进行运算而后返回一个值计算结果)。

(Class)中定义的函数也可以这样被调用 —— 虽然你还不明白类(Class)究竟是什么但从结构上很容易理解它实际上也是保存在其他文件中的一段代码于是那段代码内部定义的函数也可以这样调用

比如数字其实属于一个类所以我们可以调用那个类里所定义的函数比如float.as_integer_ratio()它将返回两个值第一个值除以第二个值恰好等于传递给它的那个浮点数字参数

python
3.1415926.as_integer_ratio()
plaintext
(3537118815677477, 1125899906842624)

关于布尔值的补充

当你看到以下这样的表达式而后再看看它的结果你可能会多少有点迷惑

python
True or 'Python'
plaintext
True

这是因为 Python True 定义为

By default, an object is considered true unless its class defines either a __bool__() method that returns False or a __len__() method that returns zero, when called with the object.

https://docs.python.org/3/library/stdtypes.html#truth-value-testing

这一段文字初学者是看不懂的但下一段就好理解了

Here are most of the built-in objects considered False:

  • constants defined to be false: None and False.
  • zero of any numeric type: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
  • empty sequences and collections: '', (), [], {}, set(), range(0)

所以'Python' 是个非空的字符串不属于是 empty sequences所以它不被认为是 False它的布尔值是 True

于是这么理解就轻松了

每个变量或者常量除了它们的值之外同时还相当于有一个对应的布尔值

关于值的类型的补充

除了数字布尔值字符串以及上一小节介绍的列表之外还有若干数据类型比如 range()等差数列)、tuple元组)、set集合)、dictionary字典),再比如 Date Type日期等等

它们都是基础数据类型的各种组合 —— 现实生活中更多需要的是把基础类型组合起来构成的数据比如一个通讯簿里面是一系列字符串分别对应着若干字符串和数字

python
entry[3662] = {
    'first_name': 'Michael',
    'last_name': 'Willington',
    'birth_day': '12/07/1992',
    'mobile': {
        '+714612234',
        '+716253923'
    }
    'id': 3662,
    ...
}

针对不同的类型都有相对应的操作符可以对其进行运算

这些类型之间有时也有不得不相互运算的需求于是在相互运算之前同样要 Type Casting比如将 List 转换为 Set,或者反之

python
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

a = [1, 2, 3, 4, 5, 6, 7]
b = set(a)
c = list(b)
a
b
c
plaintext
[1, 2, 3, 4, 5, 6, 7]
{1, 2, 3, 4, 5, 6, 7}
[1, 2, 3, 4, 5, 6, 7]

总结

回到最开始从结构上来看一切的计算机程序都由且只由两个最基本的成分构成

  • 运算(Evaluation)
  • 流程控制(Control Flow)

这一章主要介绍了基础数据类型的运算细节而除了基础数据类型我们需要由它们组合起来的更多复杂数据类型但无论数据的类型是什么被操作符操作的总是该数据的所以虽然绝大多数编程书籍按照惯例会讲解数据类型”,但为了究其本质我们在这里关注的是值的类型”。虽然只是关注焦点上的一点点转换但实践证明这一点点的不同对初学者更清楚地把握知识点有巨大的帮助

针对每一种的类型无论简单复杂都有相应的操作方式

  • 操作符
    • 值运算
    • 逻辑运算
  • 函数
  • 内建函数
  • 其他模块里的函数
  • 其本身所属类之中所定义的函数

所以接下来要学习的无非就是熟悉各种数据类型及其相应的操作包括能对它们的进行操作的操作符和函数无论是操作符还是函数最终都会返回一个相应的及其相应的布尔值 —— 这么看来编程知识结构没多复杂因为换句话讲

接下来你要学习的无非是各种数据类型运算而已

另外虽然现在尚未来得及对函数进行深入讲解但最终你会发现它跟操作符一样在程序里无所不在

备注

另外以下几个链接先放在这里未来你会返回来参考它们还是不断地参考它们

另外其实所有的操作符 Python 内部也是调用函数完成的……

https://docs.python.org/3.7/library/operator.html