本文面相有 一定编程基础 的朋友学习,所以略过了 环境安装、IDE 搭建 等一系列简单繁琐的事情。
Python 英文原意为 “蟒蛇”,直到 1989
年荷兰人 Guido van Rossum (简称 Guido)发明了一种 面向对象 的 解释型 编程语言,并将其命名为 Python,才赋予了它表示一门编程语言的含义。
说到 Python 的诞生,极具戏剧色彩,据 Guido 的自述记载,Python 语言是他在圣诞节期间为了打发时间开发出来的,之所以会选择 Python 作为该编程语言的名字,是因为他是一个叫 Monty Python 戏剧团体的忠实粉丝。
作为电子元器件的 计算机,实际上 只能 识别某些 特定的二进制指令 (特殊的 01
组合),但由于 人类阅读 这些 指令 非常难以阅读,加上使用这些指令编写程序的 耗时 太过于 冗长,所以,人们在此基础上再次制定了一套规范,采用特定的 人类可阅读 的代码编写,待到要执行时再 翻译 回特定二进制指令,这样就帮助了人们更加轻松地理解和阅读程序逻辑了。
这也就是所谓现在的 "高级编程语言" 了。
上述 翻译 这个过程 (其实相当复杂,涉及语法分析、语义分析、性能优化等等..) 其实也是由一个特定程序来执行的,那 什么时候将源代码翻译成二进制指令呢?,不同的编程语言有不同的规定:
.exe
) 比如:C 语言、C++、Golang、汇编等。使用的转换工具我们称为 编译器。Java 和 C# 是一种比较奇葩的存在,它们是 半编译半解释型 的语言,源码需要先转换成一种中间文件 (字节码文件),然后再把中间文件拿到 虚拟机 中执行。Java 引领了这种风潮,它的初衷是在跨平台的同时兼顾执行效率。
上图 就展示了两种不同类型语言的执行流程的不同,两种方式对比起来总结如下:
sleep()
参数是毫秒,而 Windows 中是 Sleep()
(首字母大写) 参数是秒,这就导致了 源代码也不能跨平台;Python 属于典型的解释型语言,所以运行 Python 程序需要解释器的支持,只要你在不同的平台安装了不同的解释器,你的代码就可以随时运行,不用担心任何兼容性问题,真正的 “一次编写,到处运行”。
Python 几乎支持所有常见的平台,比如 Linux、Windows、Mac OS、Android、FreeBSD、Solaris、PocketPC 等,你所写的 Python 代码无需修改就能在这些平台上正确运行。也就是说,Python 的 可移植性 是很强的。
面向对象 和 面向过程 是我们使用计算机编程解决问题的两种不同方式的方案。
面向过程 可以说是一种 基于事件 or 过程 来描述的编码方式,譬如「把大象放进冰箱」就可以描述成那经典的三个步骤,「把牛放进冰箱」又是另一个相似的经典三步,只是这样单独的事件 or 过程多了之后,随着项目复杂度的增加,项目会变得非常难以维护。
软件危机最典型的例子莫过于 IBM 的
System/360
的操作系统开发。佛瑞德·布鲁克斯(Frederick P. Brooks, Jr.)作为项目主管,率领2000
多个程序员夜以继日的工作,共计花费了5000
人一年的工作量,写出将近100
万行的源码,总共投入5
亿美元,是美国的 “曼哈顿” 原子弹计划投入的1/4
。尽管投入如此巨大,但项目进度却一再延迟,软件质量也得不到保障。布鲁克斯后来基于这个项目经验而总结的《人月神话》一书,成了史上最畅销的软件工程书籍。
尽管 结构化的程序设计 (将一个大问题逐步划分成一个一个的小问题) 能够帮助我们解决一部分问题,但 面向过程 仍然有一些不符合人类惯有的思考方式,譬如说:我今天想去存钱,我不会说「请拿走我的银行卡和钱,然后在我卡上充值上相应的数目,最后把银行卡还给我谢谢」,而我只会说「存钱,谢谢」,因为人大部分时间都是基于 对象 (或者可以说角色) 来思考的。
对于 面向过程 最好的总结可能是:「程序 = 算法 + 数据结构」,而对于 面向对象 来说则可以更改为:「程序 = 对象 + 交互」。
上面的 漫画 很好地说明了 Python 快速构建工具的能力,这也是 Why Python
的一大理由。下面根据惯例列举一些让我们足以选择 Python 的原因。
Python 的设计足够简单和易于使用,这样使得初学者能够从中不断得获取到乐趣以继续 Python 之旅。
另外作为一种非常高级的语言,Python 读起来像英语,这减轻了编码初学者的许多语法学习压力。Python 为您处理了很多复杂性,因此它非常适合初学者,因为它使初学者可以专注于学习编程概念,而不必担心过多的细节。
Python 还一度被爆纳入高考,收编到小学课本。
作为一种 动态类型 的语言,Python 确实非常灵活。这意味着没有关于如何构建特征的硬性规则,并且使用不同的方法来解决问题将具有更大的灵活性 (尽管 Python 哲学鼓励使用明显的方法来解决问题)。此外,Python 也更宽容错误,因此您仍然可以编译并运行程序,直到遇到问题为止。
Python 在诞生之初,因为其功能不好,运转功率低,不支持多核,根本没有并发性可言,在计算功能不那么好的年代,一直没有火爆起来,甚至很多人根本不知道有这门语言。
随着时代的发展,物理硬件功能不断提高,而软件的复杂性也不断增大,开发效率越来越被企业重视。因此就有了不一样的声音,在软件开发的初始阶段,性能并没有开发效率重要,没必然为了节省不到 1ms
的时间却让开发量增加好几倍,这样划不过来。也就是开发效率比机器效率更为重要,那么 Python 就逐渐得到越来越多开发者的亲睐了。
在 12-14
年,云计算升温,大量创业公司和互联网巨头挤进云计算领域,而最著名的云核算开源渠道 OpenStack 就是基于 Python 开发的。
随后几年的备受关注的人工智能,机器学习首选开发语言也是 Python。
至此,Python 已经成为互联网开发的焦点。在 「Top 10 的编程语言走势图」 可以看到,Python 已经跃居第三位,而且在 2017
年还成为了最受欢迎的语言。
在天使榜上,Python 是需求第二高的技能,也是提供最高平均薪水的技能。
随着大数据的兴起,Python 开发人员需要作为数据科学家,尤其是因为 Python 可以轻松集成到 Web 应用程序中以执行需要机器学习的任务。
Hello World
似乎是学习编程绕不过去的东西,但使用 Python,我们来换点儿别的,Emmm.. 比如,一个 查询天气 的小程序 (效果如下图):
http://wthrcdn.etouch.cn/weather_mini?city=xxx
这个网址可以返回任意城市昨日以及 5 天内的天气预报,包括气温、指数、空气质量、风力等,你可以用浏览器试着访问一下,你会得到一个 weather_mini
的文件,里面就包含了我们想要的一些数据。
不过这里由于我们发起了网络请求用到了第三方库 requests
,所以在运行之前还需要使用 pip install requests
命令把该库下载到 Python 的安装目录下。
# -*- coding: utf-8 -*-
import requests
while True:
city = input('请输入城市,回车退出:\n')
if not city:
break
req = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=%s' % city)
print(req.text)
你可以在 当前文件夹 下执行命令: python hello_python.py
,或是使用 python <源文件路径>
运行也行,例如,如果我是 Windows 用户并且将上述源文件保存在了 D
盘下面,那就可以执行 python D:\hello_python.py
,然后你就可以看到上面的效果了。当然如果使用 IDE 将更加方便。
引入一张比较著名的图吧,可以很明显地感受到 Python 在写法上要简洁一些吧:
Python 与其他语言最大的区别就是,Python 的代码块不使用大括号 {}
来控制类,函数以及其他逻辑判断。Python 最具特色的就是用 缩进 来写模块。
# 第一个注释
# 第二个注释
'''
第三注释
第四注释
'''
"""
第五注释
第六注释
"""
print("Hello, Python!")
Python 中的变量赋值不需要类型声明。Python 有五个标准的数据类型:
int
长整型、bool
布尔、float
浮点数、complex
复数 (1 + 2j);('test1', 'test2')
[1, 2, ,3]
{a: 1, b: 2}
set
集合也属于数据结构,它是一个 无序 且 不重复 的元素序列。可以使用大括号{ }
或者set()
函数创建集合,注意:创建一个空集合必须用set()
而不是{ }
,因为{ }
是用来创建一个空字典。
str = 'Hello World!'
print str[2:5] # 输出字符串中第三个至第五个之间的字符串
list = [ 'runoob', 786 , 2.23, 'john', 70.2 ]
print list[1:3] # 输出第二个至第三个元素
tuple = ( 'runoob', 786 , 2.23, 'john', 70.2 )
print tuple[1:3] # 输出第二个至第三个的元素
tinydict = {'name': 'john','code':6734, 'dept': 'sales'}
print tinydict['name'] # 输出键为 2 的值
# 当判断条件为 1 个值时
flag = False
name = 'luren'
if name == 'python': # 判断变量否为'python'
flag = True # 条件成立时设置标志为真
print 'welcome boss' # 并输出欢迎信息
else:
print name # 条件不成立时输出变量名称
# 当判断条件为多个值时
num = 5
if num == 3: # 判断num的值
print 'boss'
elif num == 2:
print 'user'
else:
print 'roadman' # 条件均不成立时输出
在 Python 中没有 do..while
的循环
count = 0
while count < 5:
print (count, " 小于 5")
count = count + 1
else:
print (count, " 大于或等于 5")
for..in
适用于 list/ dict/ set
数据类型,如果需要遍历数字序列,我们也可以借助 range(min, max, step)
函数来生成数列。
sites = ["Baidu", "Google","Runoob","Taobao"]
for site in sites:
if site == "Runoob":
print("菜鸟教程!")
break
print("循环数据 " + site)
else:
print("没有循环数据!")
print("完成循环!")
# 输出 0/ 3/ 6/ 9
for i in range(0, 10, 3) :
print(i)
# 替换成 range(5) 则输出 0/ 1/ 2/ 3/ 4
# 替换成 range(5,9) 则输出 5/ 6/ 7/ 8
# 计算面积函数
def area(width, height):
return width * height
def print_welcome(name):
print("Welcome", name)
print_welcome("Runoob")
w = 4
h = 5
print("width =", w, " height =", h, " area =", area(w, h))
在 Python 中,类型属于对象,变量是没有类型的,例如 name = "wmyskxz"
,则 "wmyskxz"
是 String 类型,而变量 name
仅仅是一个对象的引用。
Python 中一切都是对象,严格意义我们 不能说值传递还是引用传递,我们应该说传 不可变对象 (string、tuples、number 不可变) 和 传可变对象 (list、dict 可变)。
############################################
# 传递不可变对象
def ChangeInt(a):
a = 10
b = 2
ChangeInt(b)
print b # 结果是 2
############################################
# 传递可变对象
def changeme( mylist ):
"修改传入的列表"
mylist.append([1,2,3,4])
print ("函数内取值: ", mylist) # [10, 20, 30, [1, 2, 3, 4]]
return
# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist) # [10, 20, 30, [1, 2, 3, 4]]
# 函数内外值一致,因为都同属于同一个引用
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))
# 实例化类
p = people('wmyskxz', 24, 120)
p.speak() # wmyskxz 说: 我 10 岁。
# 单继承
class DerivedClassName(BaseClassName1):
<statement-1>
.
<statement-N>
# 多继承
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>
# 方法重写演示
class Parent: # 定义父类
def myMethod(self):
print ('调用父类方法')
class Child(Parent): # 定义子类
def myMethod(self):
print ('调用子类方法')
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
# 先输出 "调用子类方法" 再输出 "调用父类方法"
一个 .py
文件就是一个模块,想要使用其他 .py
文件中的方法就需要引入进来。
import [module]
# 导入整个random模块,可以是内置/当前路径
import random
# 使用 `random` 模块下的 `randint` 方法
print(random.randint(0, 5))
from [module] import [name1, name2, ...]
# 从 `random` 模块里导入其中一个方法 `randint`
from random import randint
# 不一样的是,使用 `randint` 的就不需要先写 `random` 了
print(randint(0, 5))
import [module] as [new_name]
# 但这个名字可能跟其他地方有冲突,因此改名成 `rd`
import random as rd
# 使用 `rd` 这个名称取代原本的 `random`
print(rd.randint(0, 5))
from [module] import *
不推荐,容易造成名称冲突,降低可读性和可维护性。
# Import 所有 `random` module 底下的东西
from random import *
# 使用 `randint` 的时候也不需要先写 `random`
print(randint(0, 5))
当你导入一个模块,Python 解析器对模块位置的搜索顺序是:
PYTHONPATH
下的每个目录。/usr/local/lib/python/
。把两个 module 放在一个新的目录 sample_package
,再新增 _init__.py
(可以是空,但不能没有),宣称自己是一个 package :
sample_package
|-- __init__.py
|-- 1.py
|-- 2.py
# package_runoob 同级目录下创建 test.py 来调用 package_runoob 包
# 导入包
from package_runoob.runoob1 import runoob1
from package_runoob.runoob2 import runoob2
runoob1()
runoob2()
单个py文件就是一个 module,而当多个
.py
文件 +__init__.py
文件时,就等于 package。
代码规范 再怎么强调也不为过:
# 正确的模块名
import decoder
import html_parser
# 不推荐的模块名
import Decoder
class Farm():
pass
class AnimalFarm(Farm):
pass
class _PrivateFarm(Farm):
pass
def run():
pass
def run_with_env():
pass
_
class Person():
def _private_func():
pass
if __name__ == '__main__':
count = 0
school_name = ''
MAX_CLIENT = 100
MAX_CONNECTION = 1000
CONNECTION_TIMEOUT = 600
每行代码尽量不超过 80
个字符(在特殊情况下可以略微超过 80
,但最长不得超过 120
)
理由:
side-by-side
的 diff
时很有帮助简单说,自然语言使用双引号,机器标示使用单引号,因此 代码里 多数应该使用 单引号
"..."
,例如错误信息;很多情况还是 unicode,使用u"你好世界"...'
,例如 dict 里的 keyr"..."
"""......"""
# 正确的写法
import os
import sys
# 不推荐的写法
import sys,os
# 正确的写法
from subprocess import Popen, PIPE
# 正确的写法
from foo.bar import Bar
# 不推荐的写法
from ..bar import Bar
DocString
之后,于全局变量之前;import os
import sys
import msgpack
import zmq
import foo
from myclass import MyClass
import bar
import foo.bar
bar.Bar()
foo.bar.Bar()
DocString 的规范中最其本的两点:
def
后提供一个块注释来说明。"""Return a foobar
Optional plotz says to frobnicate the bizbaz first.
"""
"""Oneline docstring"""
app = create_app(name, options)
# =====================================
# 请勿在此处添加 get post等app路由行为 !!!
# =====================================
if __name__ == '__main__':
app.run()
# -*- coding: utf-8 -*-
"""Example docstrings.
This module demonstrates documentation as specified by the `Google Python
Style Guide`_. Docstrings may extend over multiple lines. Sections are created
with a section header and a colon followed by a block of indented text.
Example:
Examples can be given using either the ``Example`` or ``Examples``
sections. Sections support any reStructuredText formatting, including
literal blocks::
$ python example_google.py
Section breaks are created by resuming unindented text. Section breaks
are also implicitly created anytime a new section starts.
"""
# 不推荐的写法(不要写函数原型等废话)
def function(a, b):
"""function(a, b) -> list"""
... ...
# 正确的写法
def function(a, b):
"""计算并返回a到b范围内数据的平均值"""
... ...
numpy
标准, 如下所示def func(arg1, arg2):
"""在这里写函数的一句话总结(如: 计算平均值).
这里是具体描述.
参数
----------
arg1 : int
arg1的具体描述
arg2 : int
arg2的具体描述
返回值
-------
int
返回值的具体描述
参看
--------
otherfunc : 其它关联函数等...
示例
--------
示例使用doctest格式, 在`>>>`后的代码可以被文档测试工具作为测试用例自动运行
>>> a=[1,2,3]
>>> print [x + 3 for x in a]
[4, 5, 6]
"""
更多细致详细的规范可以参考: