本文对Python最基础最常用的语言特性进行了整理总结,方便初学者在短时间内快速上手Python。
一、环境搭建
1.1 安装Python
Python官网下载安装:Python官网(本文以3.x版本为例进行讲解)
此外,还可以选择安装:
- Jupyter Notebook:一个 Web 应用程序,便于创建和共享文学化程序文档,支持实时代码,数学方程,可视化和 markdown。用途包括:数据清理和转换,数值模拟,统计建模,机器学习等等。
- Anaconda(推荐):一个开源的包、环境管理器,可以用于在同一个机器上安装不同版本的软件包及其依赖,并能够在不同的环境之间切换。Anaconda包括Conda、Python以及一大堆安装好的工具包,比如:numpy、pandas等;Miniconda包括Conda、Python。
- Anaconda集成了很多Python开发工具。如果你是在学习Python或者边撸边测试代码,推荐使用JupyterLab或Qt Console:
安装完成后,可以在命令行启动Python,也可以打开交互式命令行工具IDLE,或者使用jupyter等工具
- Anaconda集成了很多Python开发工具。如果你是在学习Python或者边撸边测试代码,推荐使用JupyterLab或Qt Console:
1.2 安装TensorFlow(及numpy)
对于要学习机器学习的童鞋,可以把TensorFlow库和numpy也安装一下。这一步很简单,用python的包管理器pip一行命令就搞定了
pip3 install tensorflow -i https://pypi.tuna.tsinghua.edu.cn/simple/
tensorflow依赖numpy,因此安装完tensorflow,numpy也就自动安装好了
至此,环境准备工作就搞定了,是不是很easy ?
二、Hello World
老规矩,先来个hello world程序。操作步骤:
- 创建hello_world.py(如果你是用Jupyter或者在命令行模式,也可以省掉这一步)
- 输入以下语句后保存退出(其中print为Python中用于打印输出的函数)
#(井号后是单行注释)print的用法,python2.x版本和python3.x版本有所不同。在2.x中,print是个操作符而非函数。 print("hello, world")
- 命令行执行python hello_world.py
搞定~
此外,细心的你在看别人的Python脚本时,可能会在文件头位置经常看到类似下边的两行注释语句:
#!/usr/bin/python
# -*- coding: utf-8 -*-
print("hello, world")
其中:
#!/usr/bin/python的
作用是告诉Linux系统,这个可执行文件是个脚本文件,需要用可执行程序/usr/bin/python来解析执行;# -*- coding: utf-8 -*-
的作用是告诉Python解释器,此源文件是utf8编码。它还有一种等价的写法:# coding=utf-8
三、基本语法
1. 变量
1.1 变量的声明
# 定义变量,并初始化为字符串"hello, world"
s = "hello, world"
# 使用
print(s)
不同于C++而类似于大多数脚本型(解释型)语言,Python变量初始化赋值即声明。
1.2 变量的类型
虽然Python的变量在声明时不需要指定类型,但Python不同于PHP,它属于强类型语言,其类型是在赋值时隐含指定的。
Python中的数据类型包括:
-
基本数据类型:
类型 说明 示例 备注 int 整型数值 a = 10 float 浮点数(python中没有double) a = 2.34 str 字符串 s = “hello, world” 类似于多数脚本语言,Python中字符串用单引号或双引号都可以 unicode unicode编码的字符串 s = u’你好,世界’ 注: 基本数据类型都是不可更改(immutable)的,当我们对基础类型的变量赋以新值时,实际上python会创建新的对象来保存新值。
-
复合数据类型:
类型 说明 示例 是否可更改 基本用法 备注 list 数组 arr = [1, 2.3, “hello, world”] 是(mutable) arr.append(4) # 追加
arr[2:4] # 截取片段
arr[2:2] = [3,4] #插入tuple 元组,类似于list,但是值不可修改 t = (1, 2.3, “hello, world”) 否(immutable) t = (1,2,3) dict 字典,类似于C++或GoLang中的map d = {“Jack”: 23, “Tom”: 25} 是(mutable) d = {}
d[‘hello’] = ‘world’ #添加
del(d[‘hello’] #删除
【注】在Python内部,所有的变量都是以对象的形式维护的,变量的拷贝默认都是浅拷贝。因此,下述语句会同时改变a和b的值:
a = ([1,2],[2,3]) b = a b[0].append(3) # a和b的值都会改变
PS:看到这里的第三行代码你可能会感到困惑,元组不是不可更改的吗?没错,元组的确是immutable的,但是list是mutable的。更改它的list元素并不会直接更改它,因此上边第三条语句是合法的。
1.3 预定义常量
Python中有一些预定义的常量
常量 | 说明 | 备注 |
---|---|---|
None | 表示空对象 | |
True | 布尔真值 | 注意首字母为大写 |
False | 布尔假值 | 注意首字母为大写 |
1.4 变量的格式化输出
- 方法一:类C方法
s = "name: %s age: %d score: %5.2f" % ("hello,world", 123, 456.789) print(s)
- 方法二:format方法
# format()是Python的str类内置的一个成员方法,其参数的传递有两种方法 # 方法1: s = "name: {name} age: {age} score: {score}".format(name="hello,world", age = 123, score = 456.789) # 方法2:此方法实际上利用了Python的一个特性, **d的作用是把字典对象d展开 d = {"name":"Jack", "age":23, "score":95.5} s = "name: {name} age: {age} score: {score}".format(**d) # 打印输出s print(s)
2. 语句
2.1 运算符
a = 1
b = 2
# 加减乘除
c = a + b
c = a - b
a += 1 # 自增,注意:Python不支持++a, a++, --a, a--
a -= 1 # 自减
c = a * b
c = a / b
# 幂乘
c = a ** b # a的b次方
2.2 条件判断
a = 1
b = 10
c = 20
# python里只能用and(与)和or(或)组合多个条件,不能使用 && 和 ||
# is用于精确判断两个对象是否为同一个
if a > 0 and (b > 10 or c < 30) and type(a) is int:
print("yes")
2.3 循环
# for 循环
for i in range(10): # 这里用到了range()函数/类,其作用是生成一个0~10范围(不含10)的数字序列。更多用法可查看help(range)
print(i)
# while循环
i = 0
while i < 10:
print(i)
i += 1
2.4 三元运算
Python中没有类似? : 的三元运算符,但是if else有类似的替代用法
a = 10
b = 1 if a > 10 else 2 # 等价于C语言中的 b = a > 10 ? 1 : 2
2.5 语句块
# for 循环
for i in range(10):
s = "i = %d" % i
print(s)
3. 函数
3.1 命名函数
# 定义函数,函数名为function_name,其支持3个参数:arg1, arg2, arg3。其中arg3具有默认值1.0
def function_name(arg1, arg2, arg3=1.0):
print("arg1 = %s, arg2 = %s, arg3 = %s\n" % (arg1, arg2, arg3))
# 调用函数
function_name("11", 22, 3.0)
注:不同于C++、GoLang、Java等的花括号{},Python通过缩进来限定语句块。
3.2 匿名函数(lambda)
python中,匿名函数用lambda表达式声明
# 使用lambda创建匿名函数,形式:lambda [arg1 [,arg2,.....argn]]:expression
mysum = lambda a, b : a + b # lambda函数不需要显式return,其表达式的结果即是函数返回值
c = mysum(1, 2)
print(c)
4. 类
4.1 类的定义
# 定义类ClassA
class ClassA:
# 构造函数,其中self参数相当于C++中的this指针。就是说,类似与GoLang,Python的类里,this指针不是隐含的,需要显式定义。
def __init__(self, param1):
self._param1 = param1
# 定义一个名为display_with_msg的类方法(即成员函数)
def display_with_msg(self, msg):
print(self._param1, msg)
# 定义ClassB,其继承ClassA
class ClassB(ClassA):
# 构造函数
def __init__(self, param1, param2):
# 先调用父类的构造函数进行初始化
ClassA.__init__(self, param1)
# 再做自己的初始化
self._param2 = param2
# 重载display_with_msg方法
def display_with_msg(self, msg):
print(self._param1, self._param2, msg)
# 创建类对象
c = ClassB("Jack", 23)
# 调用类方法
c.display_with_msg("Hello") #等价于ClassB.display_with_msg(c, "hello")
4.2 魔术方法
python提供一些开发者可自定义的方法,以自定义类的一些行为,如:
# 定义类ClassA
class ClassA:
# 构造函数
def __init__(self, param1):
self._param1 = param1
# 当将类对象进行【显式】类型转换为str时自动调用
def __str__(self):
return "{'param1': '%s'}" % self._param1
# 当将类对象进行【隐式】类型转换为str时自动调用
def __repr_(self):
return "ClassA{'param1': '%s'}" % self._param1
# 创建类对象
c = ClassB("Jack")
print(str(c)) # 自动调用__str__方法进行类型转换
print(c) # 自动调用__repr__方法进行类型转换
其他魔术方法有:
__init__
: 构造函数,在生成对象时调用__del__
: 析构函数,释放对象时使用__repr__
: 打印,转换__setitem__
: 按照索引赋值__getitem__
: 按照索引获取值__len__
: 获得长度__cmp__
: 比较运算__call__
: 函数调用__add__
: 加运算__sub__
: 减运算__mul__
: 乘运算__truediv__
: 除运算__mod__
: 求余运算__pow__
: 乘方
利用这些魔术方法可以实现类似C++里操作符重载的效果。
5. 模块(包)
Python 模块(Module),可以是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句。也可以是一个目录(包),包含若干个.py文件。
5.1 模块的引用
- import 语句
句法: import … [as …]import os import sys as s
- from … import语句
from os import path
5.2 查看使用文档
当我们引入了一个模块,并尝试使用时,模块的用法是摆在我们面前的第一个问题。Python提供了非常便利的文档管理和查看方式:
- 方法一:打开本地Python docs【IDLE => Help菜单 => Python Docs】
- 方法二:打开在线文档 https://docs.python.org/3/
- 方法三:命令行内使用help函数和dir函数(也可用于查看函数的使用说明)
# 导入模块(包) import os # 查看模块的完整使用文档 help(os) # 查看模块包含哪些成员 dir(os)
5.3 模块的使用
# 导入模块(包)
import os
if os.path.exists("/"):
print("path exists")
5.4 模块属性
- name:模块名。当源文件作为模块被其他Python模块/源文件引入时,模块的__name__属性包含了本模块的模块名。而当源文件作为可执行文件被执行时,__name__的取值则为"main"。
5.5 常用模块
- os: 提供了一组与操作系统交互的方法集。
- sys: 与python交互的方法集。
更多可以参考官方文档
6. 文件操作
# 打开文件
f = open("~/hello.txt", "r")
# 读取方式一:一次性读出全部文件内容
data = f.read()
# 读取方式二:按行遍历
for line in f:
print(line.rstrip('\n')) # 打印行。line默认会带上换行符,line.rstrip()方法的作用是去掉末尾的换行符。
# 写入文件,方式1
f.write("hello, world")
# 写入文件,方式2
print("hello, world", file=f) # python2.7中的写法是 print >>f, "hello, world"
# 关闭文件对象
f.close()
7. 其他
import os
import sys
# 1)向错误输出打印
print("hello, world", file=sys.stderr)
# 2)获取命令行参数
params = sys.argv
print(params)
# 3) 获取变量类型
s = "hello, world"
if type(s) is str:
print("type(s) is str")
四、Python的神奇特性
Python有很多体现其独特魅力的神奇特性,这里简单列举一二。
for else语句
Python中,for语句可以选择性附加一个else语句块。for 中的语句和普通的没有区别,else 中的语句会在循环正常执行完(即 for 不是通过 break 跳出而中断的)的情况下执行,while … else 也是一样。
or num in range(10,20): # 迭代 10 到 20 之间的数字
for i in range(2,num): # 根据因子迭代
if num%i == 0: # 确定第一个因子
j=num/i # 计算第二个因子
print '%d 等于 %d * %d' % (num,i,j)
break # 跳出当前循环
else: # 循环的 else 部分
print num, '是一个质数
4.2 牛掰的yield
yield语句使得python函数可以具备按需执行/生成的能力
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b # 使用 yield
# print b
a, b = b, a + b
n = n + 1
for n in fab(5):
print n
list的骚操作
- 1)list的生成:
# 用range创建list: lst = [ i for i in range(100) ] # 创建一个长度为10,元素值全为1的list lst = [1] * 10
- 2)list的切片
# 用range创建list: lst = [ i for i in range(100) ] print(lst[2:6]) # 截取lst第2 至 第5(6-1)个元素的片段 print(lst[1:-2:2]) # 间隔2,截取lst第2 至 倒数第3(2+1)个元素的片段
- 3)list的插入,替换与拼接
# 用range创建list: lst = [ i for i in range(100) ] lst[2:2] = [11,22,33] # 在第2个位置插入3个元素 lst[2:4] = [11,22,33] # 删除第2~3个元素,并插入3个新元素 lst += [11,22,33] # 在lst末尾追加3个新元素
除此之外,还有很多很多,各位慢慢探索吧~~~
五、浅谈GIL
Python为人广为诟病的一点就是其性能。Python的性能之所以糟糕,和GIL有很大关系。GIL即Global Interpreter Lock(全局解释器锁),它是CPython(C版本的Python解释器,也是使用最广泛的解释器)引入的一个概念和组件。它是造成Python多线程并发其实是「伪并行」的核心原因。
在CPython中,每一个Python线程执行前都需要去获得GIL锁 ,获得该锁的线程才可以执行,没有获得的只能等待 ,当具有GIL锁的线程运行完成后,其他等待的线程就会去争夺GIL锁,这就造成了,在Python中使用多线程,但同一时刻下依旧只有一个线程在运行 ,所以Python多线程其实并不是「并行」的,而是「并发」 。
六、代码示例
示例陆续补充中,先随便来个最简单的吧~~~
- 示例一:
# 导入模块(包) import sys import json class Person: def __init__(self, attrs): self._name = attrs['name'] self._age = attrs['age'] self._score = attrs['score'] def __str__(self): return 'name: {_name}, age: {_age}, score: {_score}'.format(**self) if __name__ == '__main__': # 通过sys.argv可以获取所有命令行参数 d = json.loads(sys.argv[1]) # 调用json模块的loads()函数,对字符串进行解析。详见help(json.loads) person = Person(d) print(str(person))
Python的魅力远远不是短短一篇文章可以道尽的,大家在漫漫编码路中尽情探索、慢慢体会吧~~~