Python是著名的“龟叔”Guido van Rossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言。
Python是一种解释型语言,是在执行时一行一行地翻译成CPU能理解的机器码,相对的是编译型语言,在执行前编译成机器码,所以,python的第一个缺点就是运行速度慢,第二个缺点就是代码不能加密。如果要发布你的Python程序,实际上就是发布源代码。解释型的语言,都则必须把源码发布出去,但不要担心这个问题。
Python适合开发哪些类型的应用呢?首选是网络应用,包括网站、后台服务等等;其次是许多日常需要的小工具,包括系统管理员需要的脚本任务等等;另外就是把其他语言开发的程序再包装起来,方便使用。
对于编程语言,还有动态语言和静态语言之分:
动态:变量的类型是在第一次赋值给变量时根据数据类型赋类型。
静态:在编译期间就进行数据类型检查。
还有强类型定义语言和弱类型定义语言之分。
一、python的安装
python的版本演进过程:
Python的版本2.X ——2.7——3.X,版本2和版本3是不兼容的,其中2.7是特殊的中间版本,其支持2.0和3.0的语法。
Windows环境下:下载
可以看到,3.9版本是不能运行在win7及以前的操作系统下的。安装Windows版的Python,有几种版本:下面是网络上的一种流行解释:
python安装包下载 embeddable zip file 、executable、web-based 的区别:
1、embeddable zip file: zip 压缩档,就是python打包成zip压缩包。下载后拷到电脑上解压就直接用,无需安装。一般资深的程序员会用。
2、executable: 可執行文件的,既把要安装的python全部下载好在本机安装。
3、web-based: 透过网络安装的,安装过程需要网络来支持(在线安装),网速不好时可以慢慢装。
X86和X86-64的区别: 32 bit 的版本和 64 bit 的版本。
对于embeddable,其解压后与使用excutable大小比较后,发现embeddable小的多。我理解enbeddable是一种嵌入式的版本,可以理解成最小资源版本,适用于嵌入式系统。
安装后,在cmd命令窗口下运行python无法运行,在系统变量或用户变量Path中添加python路径。
在windows下安装executable版本后,在开始菜单栏中增加如下项:
上图左边是直接运行python 3.8(64-bit)的图,右边是IDLE的图,左边就相当于先打开CMD窗口,然后执行python命令
在python的交互窗口 >>>下运行python命令、函数等代码,直接解释执行
将代码保存在文本文件中,使用python d:\pythoncode\hello.txt 也可以运行代码。
另一种方法是保存为.py文件,直接双击运行,或者如上面的使用python wenjianming.py运行。
python的解析器:CPython、IPython、PyPy、Jython、IronPython。
CPython:这个解释器是用C语言开发的,所以叫CPython,是官方版本的解释器。
Python的解释器很多,但使用最广泛的还是CPython。如果要和Java或.Net平台交互,最好的办法不是用Jython或IronPython,而是通过网络调用来交互,确保各程序之间的独立性
linux上是默认自带有python的,试着装了一个centos7,里面的python是2.7版本的。
二、第一个python程序
交互窗口下:
命令窗口运行文件模式:
一般都是写成.py后缀。
文本编辑器使用Visual Studio Code!
Python在线运行代码助手:
可以以网页形式运行python代码,具体是运行一个python程序,启动一个类似web的服务,然后在本地使用IE或其他浏览器打开,下面是learning.py的完整代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
r'''
learning.py
A Python 3 tutorial from http://www.liaoxuefeng
Usage:
python3 learning.py
'''
import sys
def check_version():
v = sys.version_info
if v.major == 3 and v.minor >= 4:
return True
print('Your current python is %d.%d. Please use Python 3.4.' % (v.major, v.minor))
return False
if not check_version():
exit(1)
import os, io, json, subprocess, tempfile
from urllib import parse
from wsgiref.simple_server import make_server
EXEC = sys.executable
PORT = 39093
HOST = 'local.liaoxuefeng:%d' % PORT
TEMP = tempfile.mkdtemp(suffix='_py', prefix='learn_python_')
INDEX = 0
def main():
httpd = make_server('127.0.0.1', PORT, application)
print('Ready for Python code on port %d...' % PORT)
httpd.serve_forever()
def get_name():
global INDEX
INDEX = INDEX + 1
return 'test_%d' % INDEX
def write_py(name, code):
fpath = os.path.join(TEMP, '%s.py' % name)
with open(fpath, 'w', encoding='utf-8') as f:
f.write(code)
print('Code wrote to: %s' % fpath)
return fpath
def decode(s):
try:
return s.decode('utf-8')
except UnicodeDecodeError:
return s.decode('gbk')
def application(environ, start_response):
host = environ.get('HTTP_HOST')
method = environ.get('REQUEST_METHOD')
path = environ.get('PATH_INFO')
if method == 'GET' and path == '/':
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<html><head><title>Learning Python</title></head><body><form method="post" action="/run"><textarea name="code" style="width:90%;height: 600px"></textarea><p><button type="submit">Run</button></p></form></body></html>']
if method == 'GET' and path == '/env':
start_response('200 OK', [('Content-Type', 'text/html')])
L = [b'<html><head><title>ENV</title></head><body>']
for k, v in environ.items():
p = '<p>%s = %s' % (k, str(v))
L.append(p.encode('utf-8'))
L.append(b'</html>')
return L
if host != HOST or method != 'POST' or path != '/run' or not environ.get('CONTENT_TYPE', '').lower().startswith('application/x-www-form-urlencoded'):
start_response('400 Bad Request', [('Content-Type', 'application/json')])
return [b'{"error":"bad_request"}']
s = environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))
qs = parse.parse_qs(s.decode('utf-8'))
if not 'code' in qs:
start_response('400 Bad Request', [('Content-Type', 'application/json')])
return [b'{"error":"invalid_params"}']
name = qs['name'][0] if 'name' in qs else get_name()
code = qs['code'][0]
headers = [('Content-Type', 'application/json')]
origin = environ.get('HTTP_ORIGIN', '')
if origin.find('.liaoxuefeng') == -1:
start_response('400 Bad Request', [('Content-Type', 'application/json')])
return [b'{"error":"invalid_origin"}']
headers.append(('Access-Control-Allow-Origin', origin))
start_response('200 OK', headers)
r = dict()
try:
fpath = write_py(name, code)
print('Execute: %s %s' % (EXEC, fpath))
r['output'] = decode(subprocess.check_output([EXEC, fpath], stderr=subprocess.STDOUT, timeout=5))
except subprocess.CalledProcessError as e:
r = dict(error='Exception', output=decode(e.output))
except subprocess.TimeoutExpired as e:
r = dict(error='Timeout', output='执行超时')
except subprocess.CalledProcessError as e:
r = dict(error='Error', output='执行错误')
print('Execute done.')
return [json.dumps(r).encode('utf-8')]
if __name__ == '__main__':
main()
运行:
然后打开地址:
我测试时出现错误:
不知道什么问题。
三、输入和输出:
输出使用print()函数,在括号中加上字符串,就可以向屏幕上输出指定的文字。如print('hello, world')。也可以接受多个字符串,用逗号“,”隔开,就可以连成一串输出:
>>> print('The quick brown fox', 'jumps over', 'the lazy dog')
The quick brown fox jumps over the lazy dog
print()
会依次打印每个字符串,遇到逗号“,”会输出一个空格,因此,输出的字符串是这样拼起来的:
输入使用input(),让用户输入字符串,并存放到一个变量里。
输入完成后,不会有任何提示,Python交互式命令行又回到>>>
状态了。那刚才输入的内容到哪去了?答案是存放到name
变量里了。可以直接输入name
查看变量内容。
要注意的重点是输入的内容作为字符串类型,即使是输入的数字123,也是作为字符串,不能直接进行算数运算。
四、Python变量的命名规则:
长变量以下划线连接,(驼峰型是C#的变量写法)。变量第一个字母小写;Python中没有常量。要打印出变量的内容,除了直接写变量名
然后按回车外,还可以用print()
函数。
input()
和print()
是在命令行下面最基本的输入和输出,但是,用户也可以通过其他更高级的图形界面完成输入和输出,比如,在网页上的一个文本框输入自己的名字,点击“确定”后在网页上看到输出信息。
五、关于Python的变量赋值
name = “aaaa”
name1 = name
print(name1)
这时打印的name1是aaaa
如果修改name的值,
name = “bbbb”
这时
Print(name1)的结果还是“aaaa”
这里的关键点是name = “aaaa”,先在内存中创建aaaa,然后将这个aaaa的内存地址赋给name变量,而name1 = name是将name所指向的地址赋给了name1,当name=“bbbb”时,是在内存中创建bbbb,然后将bbbb的地址赋给name,而name1依然指向aaaa的地址。使用del 变量名 是手动删除变量。
六、编码部分:
支持中文的第一张表:GB2312
中文编码的发展:GB2312——>BGK1.0——>GB18030
Unicode 万国码,2**16 = 65535 存一个字符,统一占用2个字节
UTF-8 是unicode的扩展集,可变长的字符编码集。Ascii用1个字节保存,欧洲的字节用2个字节,其他国家字符3个字节。
Unicode是向下兼容GBK和GB2312的。
七、注释: # 单行注释
三个单引号或三个双引号 多行注释
以#
开头的语句是注释,注释是给人看的,可以是任意内容,解释器会忽略掉注释。其他每一行都是一个语句,当语句以冒号:
结尾时,缩进的语句视为代码块。
八、Python书写
缩进:缩进级别必须保持一致
一般四个空格,官方不建议使用tab,在编辑器中可使用将制表符自动换为4个空格。
Python程序是大小写敏感的
九、数据类型和变量
数据类型:
整数:正整数、负整数、零
对于很大的数,例如10000000000
,很难数清楚0的个数。Python允许在数字中间以_
分隔,因此,写成10_000_000_000
和10000000000
是完全一样的
浮点数:浮点数也就是小数,按照科学记数法表示时,一个浮点数的小数点位置是可变的,比如,1.234X和12.34x是完全相等的。浮点数可以用数学写法,如1.23
,3.14
,-9.01
,等。但是对于很大或很小的浮点数,就必须用科学计数法表示,把10用e替代,1.234x就是1.234e9
,或者12.34e8
,0.000012可以写成1.2e-5
,等等。
整数和浮点数在计算机内部存储的方式不同,整数运算永远是精确的(除法也是精确的!),而浮点数运算则可能会有四舍五入的误差。
字符串:字符串是以单引号'
或双引号"
括起来的任意文本,比如'abc'
,"xyz"
等。''
或""
本身不是字符串的一部分。如果'
本身也是一个字符,那就可以用""
括起来,比如"I'm OK"
包含的字符是I
,'
,m
,空格,O
,K
这6个字符。
如果字符串内部既包含'
又包含"
怎么办?可以用转义字符\
来标识,比如:'I\'m \"OK\"!'
表示的字符串内容是:I'm "OK"!
如果字符串里面有很多字符都需要转义,就需要加很多\
,为了简化,Python还允许用r''
表示''
内部的字符串默认不转义
如果字符串内部有很多换行,用\n
写在一行里不好阅读,为了简化,Python允许用'''...'''
的格式表示多行内容。
上图中的三个点好像理解错了,在保存为文件中的写法如下:
行之间自然回车就行,不需要三个点,上面的显示应该是为了对齐>>>,系统增加的显示符。
布尔值:布尔值和布尔代数的表示完全一致,一个布尔值只有True
、False
两种值,Python中,可以直接用True
、False
表示布尔值(请注意大小写),也可以通过布尔运算计算出来。
布尔值可以用and
、or
和not
运算。
空值:空值是Python里一个特殊的值,用None
表示。None
不能理解为0
,因为0
是有意义的,而None
是一个特殊的空值。
变量
变量在程序中就是用一个变量名表示,变量名必须是大小写英文、数字和_
的组合,且不能用数字开头。在Python中,等号=
是赋值语句,可以把任意数据类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量:
这里有一个发现,在交互模式下,使用print()函数打印字符串变量,字符串是没有夹在两个单引号之间的,如果直接打变量名,在显示的结果有两个单引号。
变量本身类型不固定的语言称之为动态语言,与之对应的是静态语言。静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配,就会报错。例如Java是静态语言
理解变量在计算机内存中的表示也非常重要:
a = ‘ABC’
时,Python解释器干了两件事情:
-
在内存中创建了一个
'ABC'
的字符串; -
在内存中创建了一个名为
a
的变量,并把它指向'ABC'
。
也可以把一个变量a
赋值给另一个变量b
,这个操作实际上是把变量b
指向变量a
所指向的数据
执行a = 'ABC'
,解释器创建了字符串'ABC'
和变量a
,并把a
指向'ABC'
:
执行b = a
,解释器创建了变量b
,并把b
指向a
指向的字符串'ABC'
:
执行a = 'XYZ'
,解释器创建了字符串'XYZ',并把a
的指向改为'XYZ'
,但b
并没有更改:
所以,最后打印变量b
的结果自然是'ABC'
了。
常量
所谓常量就是不能变的变量。在Python中,通常用全部大写的变量名表示常量,但事实上PI
仍然是一个变量,Python根本没有任何机制保证PI
不会被改变,所以,用全部大写的变量名表示常量只是一个习惯上的用法。
编码,在编写程序文件时,第一行一般用:# -*- coding: utf-8 -*-指定编码。
Python支持多种数据类型,在计算机内部,可以把任何数据都看成一个“对象”,而变量就是在程序中用来指向这些数据对象的,对变量赋值就是把数据和变量给关联起来。
inf表示无穷大。
十、字符串和编码
字符编码,关于unicode编码,参见unicode编码详解,简单来说:
- Unicode 是「字符集」
- UTF-8 是「编码规则」
其中:
- 字符集:为每一个「字符」分配一个唯一的 ID(学名为码位 / 码点 / Code Point)
- 编码规则:将「码位」转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)
广义的 Unicode 是一个标准,定义了一个字符集以及一系列的编码规则,即 Unicode 字符集和 UTF-8、UTF-16、UTF-32 等等编码……
Unicode 字符集为每一个字符分配一个码位,例如「知」的码位是 30693,记作 U+77E5(30693 的十六进制为 0x77E5)。
UTF-8 顾名思义,是一套以 8 位为一个编码单位的可变长编码。会将一个码位编码为 1 到 4 个字节:
U+ 0000 ~ U+ 007F: 0XXXXXXX
U+ 0080 ~ U+ 07FF: 110XXXXX 10XXXXXX
U+ 0800 ~ U+ FFFF: 1110XXXX 10XXXXXX 10XXXXXX
U+10000 ~ U+10FFFF: 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
根据上表中的编码规则,之前的「知」字的码位 U+77E5 属于第三行的范围:
7 7 E 5
0111 0111 1110 0101 二进制的 77E5
--------------------------
0111 011111 100101 二进制的 77E5
1110XXXX 10XXXXXX 10XXXXXX 模版(上表第三行)
11100111 10011111 10100101 代入模版
E 7 9 F A 5
这就是将 U+77E5 按照 UTF-8 编码为字节序列 E79FA5 的过程。反之亦然。
现代编码模型
在现代编码模型里要知道一个字符如何映射成计算机里比特,需要经过如下几个步骤:
知道一个系统需要支持哪些字符,这些字符的集合被称为字符表(Character repertoire)
给字符表里的抽象字符编上一个数字,也就是字符集合到一个整数集合的映射。这种映射称为编码字符集(CCS:Coded Character Set), unicode 是属于这一层的概念,unicode 跟计算机里的什么进制啊没有任何关系,它是完全数学的抽象的。
将 CCS 里字符对应的整数转换成有限长度的比特值,便于以后计算机使用一定长度的二进制形式表示该整数。这个对应关系被称为字符编码表(CEF:Character Encoding Form)UTF-8, UTF-16 都属于这层。
对于 CEF 得到的比特值具体如何在计算机中进行存储,传输。因为存在大端小端的问题,这就会跟具体的操作系统相关了。这种解决方案称为字符编码方案(CES:Character Encoding Scheme)。
平常我们所说的编码都在第三步的时候完成了,并没有涉及到 CES。
关于字符集(character set)和编码(encoding),某几篇答案中似乎有些混淆。
对于 ASCII、GB 2312、Big5、GBK、GB 18030 之类的遗留方案来说,基本上一个字符集方案只使用一种编码方案。
比如 ASCII 这部标准本身就直接规定了字符和字符编码的方式,所以既是字符集又是编码方案;而 GB 2312 只是一个区位码形式的字符集标准,不过实际上基本都用 EUC-CN 来编码,所以提及「GB 2312」时也说的是一个字符集和编码连锁的方案;GBK 和 GB 18030 等向后兼容于 GB 2312 的方案也类似。
于是,很多人受这些遗留方案的影响而无法理解字符集和编码的关系。
对于 Unicode,字符集和编码是明确区分的。Unicode/UCS 标准首先是个统一的字符集标准。而 Unicode/UCS 标准同时也定义了几种可选的编码方案,在标准文档中称作「encoding form」,主要包括 UTF-8、UTF-16 和 UTF-32。
所以,对 Unicode 方案来说,同样的基于 Unicode 字符集的文本可以用多种编码来存储、传输。
所以,用「Unicode」来称呼一个编码方案不合适,并且误导。
[1] Windows 里说的「ANSI」其实是 Windows code pages,这个模式根据当前 locale 选定具体的编码,比如简中 locale 下是 GBK。把自己这些 code page 称作「ANSI」是 Windows 的 臭毛病。在 ASCII 范围内它们应该是和 ASCII 一致的。
[2] 把带有 BOM 的小端序 UTF-16 称作「Unicode」也是 Windows 的 臭毛病。Windows 从 Windows 2000 开始就已经支持 surrogate pair 了,所以已经是 UTF-16 了,「UCS-2」这个说法已经不合适了。UCS-2 只能编码 BMP 范围内的字符,从 1996 年起就在 Unicode/ISO 标准中被 UTF-16 取代了(UTF-16 通过蛋疼的 surrogate pair 来编码超出 BMP 的字符)。都十多年了,求求大家别再误称了……
[3] 把带 BOM 的 UTF-8 称作「UTF-8」又是 Windows 的 臭毛病。如果忽略 BOM,那么在 ASCII 范围内与 ASCII 一致
Python的字符串
在最新的Python 3版本中,字符串是以Unicode编码的,也就是说,Python的字符串支持多语言。这里,个人感觉不能说Unicode编码,应该说Unicode码点,即字符串是以Unicode的码点保存的。这里还是有疑惑的,因为Unicode的码点范围是从0~10FFFF,超过FFFF的码点怎么表示?现在看到的网上资料基本上举例都是\u1e45这种样子,没有超过两个字节的,Unicode码点有100多万个,现在使用的有13万多个,分成17个平面,13万用二进制表示,也是超过两个字节了,怎么表示?
对于单个字符的编码,Python提供了ord()
函数获取字符的整数表示(就是Unicode码点),chr()
函数把编码转换为对应的字符。
关于Python的字符串以及编码,看这里吧——Python中的字符串与字符编码
字符集、编码等的知识还是很复杂的,慢慢积累吧。
十一、格式化
如何输出格式化的字符串。在Python中,采用的格式化方式和C语言是一致的,用%
实现
%
运算符就是用来格式化字符串的。在字符串内部,%s
表示用字符串替换,%d
表示用整数替换,有几个%?
占位符,后面就跟几个变量或者值,顺序要对应好。如果只有一个%?
,括号可以省略。变量的使用与C不同,需要一个%再加变量列表,多于一个变量,需要使用括号。
常见的占位符有:
占位符 | 替换内容 |
---|---|
%d | 整数 |
%f | 浮点数 |
%s | 字符串 |
%x | 十六进制整数 |
其中,格式化整数和浮点数还可以指定是否补0和整数与小数的位数:
些时候,字符串里面的%
是一个普通字符怎么办?这个时候就需要转义,用%%
来表示一个%
format()
另一种格式化字符串的方法是使用字符串的format()
方法,它会用传入的参数依次替换字符串内的占位符{0}
、{1}
……,
f-string
最后一种格式化字符串的方法是使用以f
开头的字符串,称之为f-string
,它和普通字符串不同之处在于,字符串如果包含{xxx}
,就会以对应的变量替换
更多推荐
Python入门自学——python简介
发布评论