1. 变量

1.1 常见问题

  1. 变量名不能包含空格,但能使用下划线来分割其中的单词

  2. 错误情况 NameError : name ‘mesage’ is not defined
    类似这种变量为定义的一般分两种情况:

    • 使用变量前忘给它赋值
    • 输入变量名时拼写不正确
  3. 任意两个数相除时,结果总是浮点数;无论是哪种运算,只要有操作数是浮点数,得到的结果就是浮点数

  4. 通常使用全大写来指出应将某个变量视为常量

  5. 注释用井号(#)标识

  6. 数字分组

    数字中的下划线可以方便阅读,且不影响结果

1
2
age=14_000_000_000
print(age) # 14000000000

1.2 保留字

保留字是 Python 语言中一些已经被赋予特定意义的单词,这就要要求开发者在开发程序时,不能用这些保留字作为标识符给变量、函数、类、模板以及其他对象命名。

Python 包含的保留字可以执行如下命令进行查看:

1
2
import keyword
keyword.kwlist

保留字

2. 输入输出

2.1 print( ) 函数

使用 print( ) 函数时,不仅可以输出了一个变量,实际上 print( ) 函数完全可以同时输出多个变量,而且它具有更多丰富的功能。

print( ) 函数的详细语法格式如下:

1
print (value, ..., sep='', end='\n', file=sysstdout, flush=False)
  • end 参数
1
2
3
4
5
6
7
"""
将三行print语句用空格连接到一行中
输出:a b c
"""
print("a", end=" ")
print("b", end=" ")
print("c")
  • 写文件
1
2
3
4
5
6
7
"""
通过print写入demo.txt文件
"""
f = open("demo.txt", "w")
print('hello world', file=f)
print('gdx study python', file=f)
f.close()
  • 分隔符
1
2
3
4
5
6
"""
按照':'进行分隔
"""
name = "张三"
age = 18
print(name, age, sep=":") # 张三:18

2.2 input( ) 函数

input( ) 是 Python 的内置函数,用于从控制台读取用户输入的内容。

input( ) 函数的用法为:str=input(tipmsg)

说明:

  • str 表示一个字符串类型的变量,input 会将读取到的字符串放入 str 中。
  • tipmsg 表示提示信息,它会显示在控制台上,告诉用户应该输入什么样的的内容;如果不写 tipmsg,就不会有任何提示信息。
1
2
message = input("Tell me something, and i will repeat it back to you:")
print(message)
  • 类型转换
1
2
3
4
5
"""
用input()获得的值是由字符串表示,如果想将输入转化为数值的话要用到int()函数
"""
height = input()
height = int(height)

Tips:

如果获取到一个 int 类型和一个 float 类型变量,并让两个变量相加,则最后得到的是 float 类型的结果。

3. 运算符

3.1 比较运算符

比较运算符,也称关系运算符,用于对常量、变量或表达式的结果进行大小比较。如果这种比较是成立的,则返回 True(真),反之则返回 False(假)。Python 支持的比较运算符如下表所示。

比较运算符 说明
> 大于,如果 > 前面的值大于后面的值,则返回 True,否则返回 False。
< 小于,如果 < 前面的值小于后面的值,则返回 True,否则返回 False。
== 等于,如果 == 两边的值相等,则返回 True,否则返回 False。
>= 大于等于(等价于数学中的 ≥),如果 >= 前面的值大于或者等于后面的值,则返回 True,否则返 False。
<= 小于等于(等价于数学中的 ≤),如果 <= 前面的值小于或者等于后面的值,则返回 True,否则返 False。
!= 不等于(等价于数学中的),如果 != 两边的值不相等,则返回 True,否则返回 False。
is 判断两个变量所引用的对象是否相同,如果相同则返回 True,否则返回 False。
is not 判断两个变量所引用的对象是否不相同,如果不相同则返回 True,否则返回 False。

Tips:

当 False 和 True 被当做数值来处理时,会分别转换成 0 和 1 进行运算。

1
2
3
4
5
6
7
8
9
10
11
print("100是否大于100:", 100 > 100)        # False
print("200是否大于等于100:", 200 >= 100) # True
print("100是否等于100:", 100 is 100) # True

print("34是否等于34.0:", 34 == 34.0) # True
print("34是否是34.0:", 34 is 34.0) # False

print("False是否小于True:", False < True) # True
print("True是否小于True:", True == True) # True
print("True是否大于等于1:", True >= 1) # True
print("True是否大于等于2:", True >= 2) # False

Tips:== 和 is 的区别
== 用来比较两个变量的值是否相等,而 is 则用来比对两个变量引用的是否是同一个对象。
- == 是 Python 标准操作符中的比较操作符,用来比较判断两个对象的 value (值) 是否相等。
- is 也被叫做同一性运算符,这个运算符比较判断的是对象间的唯一身份标识,也就是 id 是否相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# a和b为整形类型
a = 1
b = 1
print(a is b) # True
print(a == b) # True

# a和b为元组类型
a = (1, 2, 3)
b = (1, 2, 3)
print(a is b) # True
print(a == b) # True

# a和b为列表类型
a = [1, 2, 3]
b = [1, 2, 3]
print(a is b) # False
print(a == b) # True

Tips:可变对象和不可变对象

  • 整形、浮点数、字符串和元组都属于不可变对象,不可变对象是指创建后其值不能被修改的对象。如果要修改不可变对象的值,实际上会创建一个新的对象,并将变量重新指向这个新对象。
  • 列表、字典和集合属于可变对象,可变对象是指在创建后可以扩展修改其值或内容的对象。

因此,创建两个可变对象后,它们并不属于同一个地址,所以在 is 判断时会返回 False。

1
2
3
4
5
6
7
# 对于列表
my_list = [1, 2, 3]
my_list.append(4) # 可以直接修改列表

# 对于字符串
my_str = "hello"
my_str += " world" # 这里实际上创建了一个新的字符串对象

3.2 逻辑运算符

高中数学中我们就学过逻辑运算,例如 A1 为真命题,A2 为假命题,那么 “A1 且 A2” 为假,”A1 或 A2” 为真,” 非 A2” 为真。Python 也有类似的逻辑运算,如下表:

逻辑运算符 含义 基本格式 说明
and 逻辑与运算,等价于数学中的 “ 且 “ a and b 当 a 和 b 两个表达式都为真时,a and b 的结果才为真,否则为假.
or 逻辑与运算,等价于数学中的 “ 或 “ a or b 当 a 和 b 两个表达式都为假时,a or b 的结果才是假,否则为真。
not 逻辑与运算,等价于数学中的 “ 非 “ not a 如果 a 为真,那么 not a 的结果为假;如果 a 为假,那么 not a 的结果为真。相当于对 a 取反。

Tips:

在 a and b 中,如果 a 为假,那么 b 就不会再去判断,整个表达式直接判定为假。
在 a or b 中,如果 a 为真,那么 b 不同也不会去判断,整个表达式直接判定为真。

4. 字符串

4.1 格式化输出

  • 来自 C 语言的 % 方式

% 号格式化字符串的方式继承自古老的 C 语言,这在很多编程语言都有类似的实现。%s 是一个占位符,它仅代表一段字符串,并不是拼接的实际内容。实际的拼接内容在一个单独的 % 号后面,放在一个元组里。

1
print('%s %s' % ('Hello', 'world'))    # Hello world

类似的占位符还有:%d(代表一个整数)、%f(代表一个浮点数)、%.2f(代表一个保留小数点后两位的浮点数)、%o(代表一个 8 进制数)、%x(代表一个 16 进制数)等等。% 占位符既是这种拼接方式的特点,同时也是其限制因为每种占位符都有特定意义,实际使用起来较为麻烦。

  • format( ) 拼接方式
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
34
35
username = "gdx"
age = 22

# 正常用法
s1 = 'Hello! My name is {}, i am {}.'.format(username, age)
print(s1) # Hello! My name is gdx, i am 22.

# 带数字编号
print('{0} {1}'.format(username, age)) # gdx 22
print('{0} {1} {0}'.format(username, age)) # gdx 22 gdx

# 带关键字
print('{name} {age} {name}'.format(name='gdx', age=22)) # gdx 22 gdx

# 转换成百分比 - 也适用于下面f-string的方法
total = 100
score = 83
print("your score: {}".format(score/total)) # your score: 0.83
print("your score: {:.1%}".format(score/total)) # your score: 83.0%

# 转换成百分比 - 也可以通过.xf的形式转换
print("your score: {}".format(1/3*100)) # your score: 33.33333333333333
print("your score: {:.2f}%".format(1/3*100)) # your score: 33.33%

# 转换进制
print('{}'.format(10)) # 十进制 - 10
print('{:o}'.format(10)) # 八进制 - 12
print('{:x}'.format(10)) # 十六进制 - a

# 获取字典元素
info = {
'name': '张三',
'age': 19
}
print("名称:{info[name]},年级:{info[age]}".format(info=info))

我们还可以通过 format 格式化输出来完成一些小 demo,例如下面我打印一个乘法口诀表,就可以通过 format 很方便的打印出来。

1
2
3
4
5
for i in range(1, 10):
line = ""
for j in range(1, i + 1):
line += "{left} * {right} = {result} ".format(left=i, right=j, result=i * j)
print(line)

  • f-string 方法(推荐)

f-string 方式出自 PEP 498(Literal String Interpolation,字面字符串插值),从 Python3.6 版本引入。其特点是在字符串前加 f 标识,字符串中间则用花括号 { } 包裹其他字符串变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 常规使用
name = 'world'
myname= 'python_cat'
words = f'Hello {name}. My name is {myname}.'
print(words) # Hello world. My name is python_cat.

# 打印字典值
one_dict = {"name": "gdx", "age": 22}
print(f"姓名:{one_dict.get('name')},年龄:{one_dict.get('age')}") # 姓名:gdx,年龄:22

# 进制转换
print(f'{10}') # 十进制 - 10
print(f'{10:o}') # 八进制 - 12
print(f'{10:x}') # 十六进制 - a
print(f'{10:b}') # 二进制 - 1010

除了可以做字符串格式化操作,还可以进行简单的运算,甚至可以是函数方法。

1
2
3
4
5
6
# 打印表达式
print(f'A total number of {20 * 8 + 10}') # A total number of 170

# 调用函数
name = "GDX"
print(f'My name is {name.lower()}') # My name is gdx

也可以直接获取包中的常量值。

1
2
3
import math
print(f"{math.pi}") # 3.141592653589793
print(f"{math.pi:.3f}") # 3.142

或者通过 <、> 和 ^ 号来左右快速填充字符。

1
2
3
4
5
6
7
8
9
10
str_format = "hello world"
# 用空格填充
print(f'{str_format:>20}')
print(f'{str_format:<20}')
print(f'{str_format:^20}')

# 用?号填充
print(f'{str_format:?<20}')
print(f'{str_format:?>20}')
print(f'{str_format:?^20}')

4.2 改变字符串的大小

name=’Jack tom’

函数 结果
name.upper( ) JACK TOM
name.lower() jack tom
name.title() Jack Tom

Tips:

上面这些函数并不会修改初始值。

4.3 删除空白

函数 功能
name.lstrip() 去开头空白
name.rstrip() 去尾部空白
name.strip() 去开头和尾部空白

5. 枚举类型

从 Python3.x 开始提供了 enum 模块来提供权举的功能,使用时通过 from enum import Enum 来引入。

枚举的主要优点包括:

  1. 提高代码的可读性和可维护性:使用有意义的名称来表示常量值,而不是直接使用数字或字符串,使代码更易于理解。
  2. 类型安全:枚举值具有特定的类型,减少了错误使用不相关值的可能性。

例如,我下面定义了一个 Color 的枚举类型,其中包含了自定义名称的三个枚举成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from enum import Enum

class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3

def print_color(color):
if color == Color.RED.value:
print('红色')
elif color == Color.GREEN.value:
print('绿色')
elif color == Color.BLUE.value:
print('蓝色')

print(Color.RED) # Color.RED
print(Color.RED.name) # RED
print(Color.RED.value) # 1

Tips:

枚举值不能修改。

6. 静态与动态语言

  • 静态语言:数据类型是在编译期间检查的
  • 动态语言:运行期间才去做数据类型检查的语言

6.1 静态语言

静态类型语言在编译时就会确定变量的数据类型,类型检查是在编译时进行的。这就意味着在编写代码时,必须明确声明每个变量的类型,而且一旦声明,类型就不能改变。

代表性的静态语言:C、C++、Java、C# 等

优点:

  1. 类型检查在编译阶段进行,能够更早地发现类型错误,减少运行时错误的出现,提高程序的可靠性。
  2. 由于在编译时就确定了变量的类型和内存占用,所以程序的运行效率通常较高,特别是在处理大量数据和复杂计算时。
  3. 代码的可读性和可维护性较好,因为明确的类型声明使得代码的意图更加清晰。

缺点:

  1. 开发过程相对较为繁琐,学习难度稍大,需要在编写代码时明确指定类型,可能会增加一些代码量。
  2. 灵活性相对较差,修改类型可能需要进行大量的代码重构。

下面举一个 java 实现两数相加的例子,可以发现需要定义的东西比较多,代码量也比较大。

1
2
3
4
5
6
7
8
public class main {
public static void main(String[] args) {
int a = 1;
int b = 2;
int sum = a + b;
System.out.println(sum)
}
}

6.2 动态语言

动态类型语言则在运行时才确定变量的类型,即类型检查在代码运行时才进行。在这类语言中,变量的类型可以随时改变,编写代码时更加灵活,但也可能会在运行时出现一些难以预料的类型错误。

代表性的动态语言:Python、JavaScript、PHP、ruby、lua 等

优点:

  1. 编写代码更加灵活自由,不需要事先声明变量的类型,可以快速开发和迭代。
  2. 能够更轻松地实现一些高级编程概念,如元编程和动态派发。
  3. 对于一些小型项目或者快速原型开发,能够提高开发效率。

缺点:

  1. 由于类型检查在运行时进行,可能会在运行时出现一些难以发现的类型错误。
  2. 运行效率可能相对较低,因为需要在运行时进行类型推断和转换。
  3. 代码的可读性在某些情况下可能会受到影响,因为不明确的类型可能会让其他人理解代码的意图变得困难。

7. 类型标注

typing

官方文档:https://docs.python.org/zh-cn/3/library/typing.html

Python 是一门弱类型的语言,很多时候我们可能不清楚函数参数类型或者返回值类型,很有可能导致一些类型没有指定方法,typing 模块可以很好的解决这个问题。它的作用主要有以下几点:

  • 类型检查:在编译时进行类型检查,防止运行时出现参数和返回值类型不符合的情况。
  • 开发文档附加说明:作为开发文档的一部分,方便使用者调用时传入和返回参数类型。
  • 提高代码可读性:让开发者在阅读代码时更容易理解变量或对象的类型,从而提高代码的可读性和可维护性。

Tips:

typing 不会影响程序的运行,它只是用作提醒,不会产生类型的错误。

类型标注的语法:

1
2
3
4
5
6
# 函数类型标注
def 函数名(参数: 数据类型) -> 返回值类型:
pass

# 变量类型标注
变量名: 数据类型=值

typing 模块只有在 Python3.5 以上的版本中才可以使用,Pycharm 目前支持 typing 检查。

1
2
3
4
5
6
7
8
9
10
11
12
from typing import List, int, Dict

# 没有类型标注,不清楚变量a的类型及函数返回值类型是什么
def len_list1(a):
return len(a)

# 添加了类型标注,明确说明变量和函数返回值是一个List的类型
def len_list2(a: List) -> int:
return len(a)

print(len_list2([1, 2, 3])) # 3
print(len_list2("123")) # 3

我们看上面这个例子的打印结果也印证了上面 typing 不会影响程序运行的结果,但是我们可以在 print(len_list2("123")) 这行代码下看到一条黄线提示,当鼠标放在这行代码上就能看到 typing 的提示信息,提醒你当前传入的值不是期望的 list 类型。

类型标注的用法还有很多,我们再来看一些其它类型标注的例子。

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
34
35
36
# 复合类型标注
def test1(id: int, score: List[int], name: Dict[str: str]):
pass

# 指定序列类型
def test2(seq: Sequence):
for i in seq:
print(i)

# 类型别名定义 - 简化类型名称
Vector = list[float]
def test3(id, names: Vector) -> Vector:
return [id * name for name in names]

# 明确说明函数无返回值
def test4(id: int) -> NotReturn:
pass

# 明确说明变量可接受任意类型
def test5(a: Any):
print(a)

# 针对无传入参数场景
# 下列arg2类型标注为str类型,但arg2这个参数是可以不传递值的,且如果不传递,它将是None
def test6(arg1: int, agr2: Optional[str]=None):
pass

# 联合类型 - 允许多类型
# 下列arg2指明传入的参数类型可以是List和Dict中的任意一种
def test7(arg1: int, agr2: union[List, Dict]):
pass

# 自定义多类型
MyType = TypeVar("MyType", int, str, List) # 允许是int、str和List中的类型
def test8(a: MyType):
pass

Tips:

Python 中常见的序列类型包括:列表(list)、元组(tuple)、字符串(str)、字节序列(bytes)和字节数组(bytearray)。