Python 入门 —— 基本语法
前言
Python
是一种高级编程语言,以其清晰的语法和强大的灵活性而闻名。由 Guido van Rossum
在 1989
年底开始设计,并在 1991
年首次发布。Python
设计哲学强调代码的可读性和简洁的语法(尤其是使用空格缩进来区分代码块,而不是使用大括号或关键词)。因此,Python
让程序员能够用更少的代码行完成任务,相较于其他编程语言,它是一种相对容易学习且功能强大的语言。
特点
- 易于学习和使用:语法简洁清晰,非常接近自然语言,使得即使是编程新手也能快速上手。
- 解释型语言:是一种解释型语言,开发过程中无需编译,程序在运行时被解释器逐行解释执行,这使得编码-测试-修正的循环非常快速。
- 面向对象:支持面向对象的编程范式,允许数据和功能组织在一起,以便于管理复杂性。
- 强大的标准库和丰富的第三方库:拥有强大的标准库和一个活跃的社区,这为几乎任何任务提供了预先构建的模块和包。无论是网络应用、数据分析、人工智能还是科学计算,都有丰富的库可供使用。
- 可扩展性:如果需要性能上的优化,可以用
C
或C++
等语言编写Python
扩展。 - 跨平台:可以在多种平台上运行,包括
Windows
、Linux
和MacOS
等,具有良好的可移植性。
应用领域
Python
在多个领域都有广泛的应用,包括但不限于:
Web
开发:使用Django
、Flask
等框架可以快速地构建网站和Web
应用。- 数据科学与深度学习:
TensorFlow
、PyTorch
、Keras
、Pandas
和Scikit-learn
等为数据科学、机器学习、深度学习、自然语言处理等提供了强大的支持,使得构建AI
模型变得更加简单和高效。 - 自动化脚本:能够轻松完成文件管理、系统管理、网络爬虫等自动化任务。
- 软件测试:
Python
的多种测试框架支持快速开发和维护代码的测试用例。
版本
Python
有两个主要的版本系列:Python 2.x
和 Python 3.x
。
Python 3.x
在语法和内置功能上进行了大量的改进和增强,但不完全向后兼容 Python 2.x
。自 2020
年 1
月 1
日起,Python 2.x
已不再获得官方支持,因此新的开发项目都应该使用 Python 3.x
版本。
变量命名规范
Python
中变量名的命名规范与 R
中最大的不同是,不能在变量名中使用 .
符号,而且只能以字母和下划线 _
作为变量名的开头字符。
变量名不能与系统中的保留字(或关键字)一样,要查看 Python
中所有的保留字,可以导入标准库中的 keyword
模块来查看
import keyword
keyword.kwlist
# ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
注释
类似于 R
,Python
的注释也分为单行注释和多行注释
- 单行注释:以符号
#
开头的行都被认为是注释,不会被解释器解析
# 一行是注释
- 多行注释:使用三个单引号或双引号,也可以认为是一个未命名的字符串常量
'''
这是注释
单引号的那种
'''
"""
这是注释
双引号的那种
"""
基本运算
算术运算
符号 | 描述 |
---|---|
+ 、- 、* 、/ | 加、减、乘、除 |
// | 整除 |
% | 取余 |
** | 幂 |
1 + 2 * 3 / 2 - 1
# 3.0
3 / 4
# 0.75
3 // 4
# 0
3 % 2
# 1
1 + 3 ** (2 * 4 // 3)
# 10
赋值运算
赋值运算包括 =
和 :=
(海象运算符,Python 3.8
版本新增)
a = 1
b = 2
# 与算术运算符联用
a *= 3 # 相当于 a = a * 3
a
# 3
b /= a # 相当于 a = a / 3
b
# 0.6666666666666666
# 海象运算符与 R 中的赋值方式 <- 类似,但是只能在表达式中使用
(c := a * b) > 3
# False
c
# 2.0
关系运算
与 R
中的关系运算相同,但是可以进行连续比较
a > b
# True
a <= b
# False
a == b
# False
# 联用相当于与,即 a <= b and b < c
a <= b < c
# False
逻辑运算
既可以使用单词,也可以使用符号
操作符 | 描述 |
---|---|
and (&& ) | 判断两个条件是否都为真,全真为真 |
or (` | |
not (! ) | 取反 |
a > b and a > c
# True
a > b > c
# False
not b > c
# True
a > b or a > c
# True
成员运算
仅限于序列数据结构(list
、tuple
、str
)
操作符 | 描述 |
---|---|
in | 属于,判断一个值是否包含在序列数据结构中 |
not in | 不属于,判断一个值是否不包含在序列数据结构中 |
L = [1, 2, 3, 4, 5]
a, b, c
# (3, 0.6666666666666666, 2.0)
a in L
# True
b in L
# False
c not in L
# False
c in L
# True
位运算
操作符 | 描述 |
---|---|
& | 按位与,或者计算集合的交集 |
` | ` |
^ | 按位异或,或者计算集合的差集 |
~ | 按位取反 |
<< | 左移 |
>> | 右移 |
a, b = 5, 12
bin(a), bin(b) # bin 函数将整数转换为二进制表示
# ('0b101', '0b1100')
a & b
# 4
a | b
# 13
a ^ b
# 9
~a
# -6
a << 2
# 20
a >> 2
# 1
身份运算符
操作符 | 描述 |
---|---|
is | 如果两个变量引用同一个对象,返回 True ,否则返回 False |
is not | 如果两个变量不是引用同一个对象,返回 True ,否则返回 False |
a = 13
b = a
a is b
# True
b = 2
a is b
# False
a is not b
# True
代码块
Python
相较于其他编程语言,最大的一个特点便是通过代码缩进来标识代码块,而不是使用大括号 {}
。缩进的空白符数量是可变的,但是必须要保证每次缩进的空白符数量一致,一层缩进一般使用 4
个空格或一个 Tab
。冒号(:
)标识代码块开始,后面具有相同缩进的代码属于同一个代码块。
if a > b:
print(a) # print 用于打印变量的值
else:
print(b)
Python
通常每行代码一条语句,如果要在一行中使用多条语句,需要使用分号(;
)隔开,但最好不要这么做,会降低代码的可读性
a = 1; print(a)
如果一行内的语句过长,可以选择多行显示,例如
total = one + \
two + \
three
分支判断
相较于 R
,Python
的分支判断语句除大括号变为冒号和缩进,以及 else if
变成 elif
之外,其他使用方式都是一样的。此外,Python
中没有 switch
语句,要编写多分支判断,需要嵌套 if...else
,例如
age = 15
if age < 10:
degree = 1
elif 10 <= age < 20:
degree = 2
else:
degree = 3
print(degree)
# 2
if...else
有一个简写方式
num = 1 if 'a' > 'b' else 2
print(num)
# 2
循环控制
Python
中包含两种循环类型:for
和 while
,流程控制命令为 continue
和 break
-
for
循环# 打印 10 以内的偶数,range(10) 生成 0-9 的数值序列 for i in range(10): if i % 2 != 0: continue print(i, end=' ') # 打印变量后添加一个空格,默认添加的是换行符 '\n' # 0 2 4 6 8
-
while
循环# 打印斐波那契数列 n = 5 a, b = 0, 1 # 以解包的方式赋值给多个变量 while a < n: print(a, end=' ') a, b = b, a+b print() # 打印一个换行 # 0 1 1 2 3
定义函数
Python
使用 def
关键字来定义函数,我们可以将上面的斐波那契数列封装为函数
def fib(n):
a, b = 0, 1 # 以解包的方式赋值给多个变量
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
# 调用函数
fib(5)
# 0 1 1 2 3
如果函数没有使用 return
显式地返回值,默认无返回值。虽然定义函数的语法与 R
略有不同,但是函数的结构是一致的,都含有函数名、参数、函数体及返回值。而且函数参数的使用方式类似
def f(a, b=0, c=1):
return a * b + c
f(1)
# 1
f(1, 2)
# 3
f(1, c=2)
# 2
但是由于数据结构的差别,对于可变参数的使用方式存在较大差异
可变参数
在 Python
中有两种可变参数:未命名参数和关键字参数,未命名参数使用 * +
变量名的方式接收,关键字参数使用 ** +
变量名的方式接收。例如
def func(first, *args, **kwargs):
print(first)
for arg in args:
print(arg, end=' ')
print()
for k, v in kwargs.items():
print("key: %s, value: %s" %(k, v))
func('begin', 1, 2, 'a', second=2, end=9)
# begin
# 1 2 a
# key: second, value: 2
# key: end, value: 9
所有未指定参数名的参数以列表的形式存储在变量 args
中,所有关键字参数以字典的形式存储在变量 kwargs
中,这两种数据结构的将在下一节中介绍
lambda 函数
lambda
函数(可用于创建匿名函数)主要用于定义一些单行的简单函数,使得代码更加简洁,免去定义函数名的困扰。例如, filter
函数会将传递的 lambda
函数应用于列表中的每一个值,并过滤掉列表中判断为假的值,并返回一个可迭代的对象,最后使用 list
函数将结果转换为列表
list(filter(lambda x: x > 5, [1, 3, 5, 7, 9]))
# [7, 9]
# 也可以为 lambda 定义函数名
max_v = lambda a, b: a if a > b else b
max_v(1, 4)
# 4
其定义函数的方式非常简单,使用 lambda
关键字声明,然后在冒号 :
的左侧定义函数的参数,右侧定义函数体
一般来说,在外层定义的我们都称之为函数,而在类中定义的函数我们通常将其称为方法,但本质上这两个是一样的,大部分时候这两个词指代的都是同一个意思。
变量作用域
Python
中也有全局变量和局部变量,每一个函数内部都是一个封闭的空间,即局部作用域,所以在函数内部定义的变量为局部变量,函数外部为全局作用域,所以函数外定义的变量为全局变量,顶层函数也是全局变量,嵌套函数是更深一层的局部变量。
# 全局变量 total
total = 10
def do_sum(a, b):
# 局部变量 total
total = a + b
def modify():
# 嵌套函数修改值
total = 100
modify()
print(total)
return total
# 4
# 10
其中,全局变量 total
的值为 10
,函数(do_sum
)内定义的 total
变量并不会修改全局变量 total
的值,嵌套函数(modify
)也无法修改上层函数中局部变量(total
)的值
global 和 nonlocal
要修改全局变量和上层局部变量的值,需要用到两个关键字
global
:修改全局变量的值
total = 10
def do_sum(a, b):
global total
total = a + b
print(total)
return total
do_sum(1, 3)
print(total)
# 4
# 4
注意,如果不使用 global
关键字,是无法在函数内部访问全局变量的
nonlocal
:修改上层局部变量的值
total = 10
def do_sum(a, b):
total = a + b
def modify():
nonlocal total
total = 100
modify()
print(total)
return total
do_sum(1, 3)
print(total)
# 100
# 10
模块导入
在 Python
中,除了使用内置的函数外,其他不管是自带的标准库还是其他的第三方库中的函数,都要先将其导入到当前环境中。
导入包的方式有三种种:
import
:导入包
import sys
print(sys.path)
# ['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6','/usr/local/lib64/python3.6/site-packages'
# ...]
我们导入 sys
模块,并打印了模块的搜索路径,会按照顺序依次在这些路径中搜索对应的包,其中第一个路径便是当前脚本所有的目录下。
不管你执行了多少次 import
语句,所有的模块都只会导入一次,防止模块被重复导入。
from ... import
:导入包中的内容
from os import listdir, getcwd
print(listdir())
print(getcwd())
# ['R_demo.ipynb', 'python_demo.ipynb', '.ipynb_checkpoints']
# /Users/dengxsh/Documents/WorkSpace/Jupyter/Python/Data_Processing
这种方法用于导入指定包中的某些函数、类或子模块,做到按需导入,被导入的函数可以直接使用而不需要加包名
from os import *
print(listdir())
# ['R_demo.ipynb', 'python_demo.ipynb', '.ipynb_checkpoints']
该方法会导入 os
包中的所有模块、函数和类,但是不推荐使用这种方式。例如,如果两个不同的包中含有相同的函数 func
,那么在执行 func()
函数时,是无法获知该函数到底是来自哪个包中的。
- 相对导入
from . import module # 导入同目录下的模块
from .mudule import func # 导入同目录下模块中的函数
from .. import module # 导入上层目录中的模块
from ..module import func # 导入上层目录的模块中的函数
除了使用 *
导入所有成员的方式之外,其他导入方式都可以使用 as
来设置别名
import pandas as pd
from scipy import stats as sts