python基础

主要参考廖雪峰

安装参考:Windows 系统安装 Python 3.8 详解

一、介绍

面向对象、解释型语言,跨平台的脚本语言。

可以做 日常任务(eg  自动备份MP3)、做网站(eg youtube、豆瓣)、做网络游戏的后台。

python为我们提供了非常完美的代码库,包括网络、文件、gui、数据库、文本等大量内容。

定位:优雅、明确、简单。代码越少,开发效率越高。

python的好处:

1、学习容易

Python是一门比较容易学习的语言,因为它是非常高级的语言,比C和C++这样的语言,还要高级几个层次。它不需要管理内存分配,不需要定义变量的类型即可使用,内置了很多数据类型直接使用,而不需要考虑怎么样创建这些类型,比如列表、字典、字符串这样高级的功能。

另外,用它写出的代码,可以直接运行,不需要进行编译的操作。

还有一点,用它写出的代码非常短。

2、开发效率高

Python是一门开发效率最高的语言,它比C有6倍的开发效率,简单来说,如果一个C开发人员工作6天,使用python的开发人员只需要工作一天即可,意味着做Python开发人员可一周只上一天班。

它比C++有2倍的开发效率,它比Java和C#也有1.5倍的开发效率。有这么高的开发效率,当然是用性能换来的代价,不过从目前硬件技术进步来看,目前的CPU计算能力普遍是过剩的,并且越来越多硬件成本降低,但人工的成本越来越贵。其实从社会进步来看,也是工具越来越先进,但人的大脑管理复杂程度并没有跟着提高,显然要提高起来就比较困难了。

目前在嵌入式系统都慢慢走向多核的CPU,在手机方面,都已经进入64位的8核时代了。在嵌入式系统方面,也有Pyboard这样的开源项目来进行了,这样的嵌入式Python主要适用于机器人控制方面。

3、调试运行方便

无论是在Windows平台,还是Linux平台,都一样开发和调试。跨平台运行更加方便,如果没有使用平台差别的API接口,只要写一遍代码,就可以在Windows平台或Linux平台上运行。

4、开源免费

Python无论在商业上,还是教育上,都是免费使用,意味可以零成本进入学习它,使用它。Python拥有众多功能完善的开发库可以使用。

5、测试领域需求

测试是软件开发里有相当大的工作量,比如模块测试,当开发人员把一个模块功能完成之后,需要测试这个模块是否正确,就需要搭建一堆测试代码,才可以验证的。这时,如果使用C++或Java来写这些功能,显然没有使用Python来得快,从前面效率就可以看到。

因此,通常就会变成这样的开发模式:发布的软件是使用C++或Java开发,但测试的代码使用Python来开发。

比如嵌入式系统涉及网络通讯方面,需要不断地向嵌入式系统发送网络数据和接收网络数据,就可以使用Python搭建一个测试环境出来,这样花费很少的时间,就可以对嵌入式系统进行验证,提高代码的质量,减少嵌入式系统与其它系统的调试时间,以及以后维护时间。

另外,通过使用Python语言编写众多的脚本,就可以提高自动化测试水平,每发布一个版本,就可以把以前的测试用例,全自动化测试一遍,这样会大大提高对软件快速发布的要求。像我所见过的测试用例,就有几万个,如果靠手工方式测试,验证起来是非常慢的,并且并不全面。目前采用全自动化测试之后,每天24小时运行,一台电脑相当于10个测试员工的工作量,可见带来多大效率的提升。在可以预见的将来,在测试领域里,Python的工作需求会持续增加,要求所有测试人员都会掌握这个好用的工具。

二、.py文件

  • windows中不能像.exe文件那样直接运行.py文件。
  • linux中可以,只需在文件最上方加一行 #!/usr/bin/env python3,执行时直接 ./01.py   否则就需要python 01.py

参考:#!/usr/bin/env python 有什么用?

第一部分是 #! (叫做Sha-bang,有的翻译组将它译作 释伴,即“解释伴随行”的简称。后接解释器的绝对路径,用于指明执行这个脚本文件的解释器。)

第二部分是 /usr/bin/env python

执行python程序的三种方式

1、解释器:cpython 解释器,将程序代码转换成cpu能够执行的机器码,装完python后就有

2、交互式:ipython软件,执行类似1,都是在终端中 python 01.py

3、IDE:pycharm中执行  【我的Pycharm,我做主

三、基础

1、注释

  单行注释 #  多行注释 """(3个引号)

2、大小写敏感,语句结尾分号可以省略,主要通过换行来识别语句的结束

3、4个空格(tab)的缩进

4、数据类型:

  • 整数(大小没有限制,超出一定范围为inf 无限大)
  • 浮点数(除法的结果是浮点数,9/3=3.0 。地板除则是返回整数9//3=3,整数的地板除结果永远是整数 即使除不尽
  • 字符串
  • 布尔值(True、False)
  • 空值(None)

5、变量:大小写英文、数字和_   ,但不能数字开头。【py文件也不要以数字开头】

  查看一个变量的类型用type()

6、字符串(str、bytes)

  在最新的Python 3版本中,字符串是以Unicode编码的,也就是说,Python的字符串支持多语言,print('包含中文的str')

  对于单个字符的编码,Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符

 eg:ord('A')=65  chr(25991)='文'

Python的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes

Python对bytes类型的数据用带b前缀的单引号或双引号表示:x = b'ABC'

要计算str包含多少个字符,可以用len()函数。如果换成byteslen()函数就计算字节数

Python 3 字符串中的 STR 和 Bytes 究竟有什么区别

  • Python2的字符串有两种:str和Unicode,Python3的字符串也有两种:str和Bytes
  • Python2里面的str和Unicode是可以混用的,在都是英文字母的时候str和unicode没有区别。
  • Python3严格区分文本(str)和二进制数据(Bytes),文本总是Unicode,用str类型,二进制数据则用Bytes类型表示。

 

由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;

第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。

格式化

在Python中,采用的格式化方式和C语言是一致的,用%实现。

>>> 'Hello, %s' % 'world'
'Hello, world'
>>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have $1000000.'

%运算符就是用来格式化字符串的

小数点:保留两位有效小数

>>> a = 12.345
>>> print("%.2f" % a) 

7、高级变量类型

  • list 列表,有序集合 []
classmates = ['Michael', 'Bob', 'Tracy']

list是个可变列表 [ ] ,元素类型可以不同。索引从0开始,最后一个元素的索引是len(classmates) - 1 。如果要取最后一个元素,除了计算索引位置外,还可以用-1做索引,直接获取最后一个元素

添加元素:追加到末尾 append()    添加到指定位置 insert(index,str)

删除元素:删除末尾元素  pop()     删除指定位置的元素,用pop(i)方法,其中i是索引位置

list元素也可以是另一个list,eg:s = ['python', 'java', ['asp', 'php'], 'scheme']

  • tuple元组,有序列表 ()

一经定义 元素不能改变,代码更安全,元素类型可以不同。如果可能,能用tuple代替list就尽量用tuple。

classmates = ('Michael', 'Bob', 'Tracy')

定义只有1个元素的tuple定义时必须加一个逗号,  t = (1,)

元组添加元素,其实是新建一个元组:

new_classmates =classmates +(5,)

8、循环

 Python的循环有两种,一种是for...in循环,依次把list或tuple中的每个元素迭代出来

 Python提供一个range()函数,可以生成一个整数序列,再通过list()函数可以转换为list.

range(101)就可以生成0-100的整数序列.

sum = 0
for x in range(101):
    sum = sum + x
print(sum)

for循环其实可以同时使用两个甚至多个变量,比如dictitems()可以同时迭代key和value:

>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> for k, v in d.items():
...     print(k, '=', v)
...
y = B
x = A
z = C

第二种循环是while循环

9、dict 字典 {}

 Python内置了字典:dict的支持,dict全称dictionary

d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}

判断一个key是否存在:一是通过in判断key是否存在;二是通过dict提供的get()方法,如果key不存在,可以返回None,或者自己指定的value:

'Thomas' in d  不存在则返回 False

d.get('Thomas') 或者 d.get('Thomas',-1)

dict可以用在需要高速查找的很多地方,在Python代码中几乎无处不在,正确使用dict非常重要,需要牢记的第一条就是dict的key必须是不可变对象

在Python中,字符串、整数、None空对象 等都是不可变的,因此,可以放心地作为key。而list是可变的,就不能作为key

在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象

10、set 集合

  set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key,无序的不重复元素序列。

要创建一个set,需要提供一个list作为输入集合:s = set([1, 2, 3])

可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。

四、函数

1、定义函数

 使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。eg:

def my_abs(x):
    if x >= 0:
        return x
    else:
        return -x

返回多个值,直接在return中定义 return nx, ny   

x, y = move(100, 100, 60, math.pi / 6)

但其实这只是一种假象,Python函数返回的仍然是单一值:原来返回值是一个tuple

 r = move(100, 100, 60, math.pi / 6)
print(r)=(151.96152422706632, 70.0)

2、函数的参数

  • 位置参数:

def power(x, n): 函数有两个参数:xn,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数xn

  • 默认参数:

def power(x, y, n=2):设置默认参数时,有几点要注意:

一是必选参数在前,默认参数在后,否则Python的解释器会报错(思考一下为什么默认参数不能放在必选参数前面);

因为会产生歧义。例如 def foo(p1, p2=6, p3)  若调用函数foo(1, 2),系统会调用foo(1, 2)其中p1 = 1 p2重新复制成了2 p2 = 2,第三个位置参数就会不见了,这时候系统就会报出错了

二是如何设置默认参数。当函数有多个参数时,把变化大的参数放前面,变化小(不怎么变化)的参数放后面。变化小的参数就可以作为默认参数。

使用默认参数有什么好处?最大的好处是能降低调用函数的难度

注意:定义默认参数要牢记一点:默认参数必须指向不变对象

  • 可变参数

可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。eg:

def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

调用 calc(1,2,3)   

而允许把list或tuple的元素变成可变参数传进去:

nums = [1, 2, 3]    calc(*nums)

*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。

五、高级特性

在Python中,代码不是越多越好,而是越少越好。代码不是越复杂越好,而是越简单越好。

基于这一思想,我们来介绍Python中非常有用的高级特性,1行代码能实现的功能,决不写5行代码。

切片

取一个list或tuple的部分元素是非常常见的操作。取前3个元素,应该怎么做?

可以 [L[0], L[1], L[2]]  或者用循环,但都太麻烦

Python提供了切片(Slice)操作符,能大大简化这种操作:L[0:3]  从索引0开始取,直到索引3为止,但不包括索引3。索引0可以省略,L[:3]

每两个取一个:L[:10:2]

字符串也有切片操作

总结:

切片的书写形式:[i : i+n : m] ;其中,i 是切片的起始索引值,为列表首位时可省略;i+n 是切片的结束位置,为列表末位时可省略;m 可以不提供,默认值是1,不允许为0 ,当m为负数时,列表翻转。注意:这些值都可以大于列表长度,不会报越界。

切片的基本含义是:从序列的第i位索引起,向右取到后n位元素为止,按m间隔过滤 。

迭代

如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。

还可以作用在其他可迭代对象上。eg dict字典、str字符串

>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> for key in d:
...     print(key)
...
a
c
b

 默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()

>>> for ch in 'ABC':
...     print(ch)
...
A
B
C

那么,如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:

>>> from collections import Iterable
>>> isinstance('abc', Iterable) # str是否可迭代
True
>>> isinstance([1,2,3], Iterable) # list是否可迭代
True
>>> isinstance(123, Iterable) # 整数是否可迭代
False

还有,同时引用两个变量,在Python里是很常见的,比如下面的代码:

>>> for x, y in [(1, 1), (2, 4), (3, 9)]:
...     print(x, y)
...
1 1
2 4
3 9

列表生成式

运用列表生成式,可以快速生成list,可以通过一个list推导出另一个list

例如,list(rang(1,11)) 

>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

写列表生成式时,把要生成的元素表达式(x * x)放到前面,后面跟for循环,就可以把list创建出来,十分有用.

for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:

>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

还可以使用两层循环,可以生成全排列:

>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

例如,列出当前目录下的所有文件和目录名,可以通过一行代码实现:

>>> import os # 导入os模块,模块的概念后面讲到
>>> [d for d in os.listdir('.')] # os.listdir可以列出文件和目录
['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads']

把一个list中所有的字符串变成小写:

>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']

注意:如果list中既包含字符串,又包含整数,由于非字符串类型没有lower()方法,所以列表生成式会报错,

正确做法,使用内建的isinstance函数可以判断一个变量是不是字符串

>>> x = 'abc'
>>> y = 123
>>> isinstance(x, str)
True
>>> isinstance(y, str)
False
L1 = ['Hello', 'World', 18, 'Apple', None]
L2 = [x.lower() for x in L1 if isinstance(x,str)]
# 测试:
print(L2)
if L2 == ['hello', 'world', 'apple']:
    print('测试通过!')
else:
    print('测试失败!')
View Code

生成器与yield

1、通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator

2、要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>

如果要一个一个打印出generator的元素来,可以通过next()函数获得generator的下一个返回值,即 next(g)

3、generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

不过,基本上永远不会调用next(),而是通过for循环来迭代(因为generator也是可迭代对象)它,并且不需要关心StopIteration的错误。

>>> g = (x * x for x in range(10))
>>> for n in g:
...     print(n)

4、generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

比如,著名的斐波拉契数列(Fibonacci),可用普通函数实现也可以用generator实现。

#!/usr/bin/env python
# encoding: utf-8

# file: Fibonacci.py

# 斐波拉契数列
#著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
#1, 1, 2, 3, 5, 8, 13, 21, 34, ...

 # 普通函数
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b  # 先计算右边,再赋值
        n = n + 1
    return 'done'

print(fib(1))
print(fib(3))
print(fib(6))


# 生成器,,只需要把print(b)改为yield b
def fibg(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b  # 先计算右边,再赋值
        n = n + 1
    return 'done'

f = fibg(6)
# 我们在循环过程中不断调用yield,就会不断中断。
# 当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。
for n in fibg(6):
    print(n)
View Code

最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

请注意区分普通函数和generator函数,普通函数调用直接返回结果;

generator函数的“调用”实际返回一个generator对象。

yield与return 的区别

  • return:就是在程序中返回某个值,返回之后程序就不再往下运行了。
  • yield:把它看做一个是生成器(generator)的一部分(带yield的函数才是真正的迭代器)

带yield的函数是一个生成器,而不是一个函数了,这个生成器有一个函数就是next函数,next就相当于“下一步”生成哪个数,这一次的next开始的地方是接着上一次的next停止的地方执行的,所以调用next的时候,生成器并不会从foo函数的开始执行,只是接着上一步停止的地方开始,然后遇到yield后,return出要生成的数,此步就结束。

迭代器

迭代对象(ITerable):可以直接作用于for循环的对象,注意有两类

  • 一类是集合数据类型,如listtupledictsetstr等;
  • 一类是generator,包括生成器和带yield的generator function。

迭代器 (ITerator):可以被next()函数调用并不断返回下一个值的对象【它表示的是一个惰性计算的序列】,只有一类

  • 生成器generator是迭代器

 可以使用isinstance()判断一个对象是否是Iterator对象:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True

listdictstrIterable变成Iterator可以使用iter()函数

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
    pass

实际上完全等价于:

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break

六、模块

1、介绍

在Python中,一个.py文件就称之为一个模块(Module)。

好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。

使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,但是也要注意,尽量不要与内置函数名字冲突。点这里查看Python的所有内置函数。

你也许还想到,如果不同的人编写的模块名相同怎么办?为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)。也就是模块的父目录

请注意,每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。__init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是mycompany

创建自己的模块时,要注意:

  • 模块名要遵循Python变量命名规范,不要使用中文、特殊字符
  • 模块名不要和系统模块名冲突,最好先查看系统是否已存在该模块,检查方法是在Python交互环境执行import abc,若成功则说明系统存在此模块。

2、使用模块

以内建的sys模块为例,编写一个hello的模块:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

' a test module '

__author__ = 'Michael Liao'

import sys

def test():
    args = sys.argv
    if len(args)==1:
        print('Hello, world!')
    elif len(args)==2:
        print('Hello, %s!' % args[1])
    else:
        print('Too many arguments!')

if __name__=='__main__':
    test()
View Code

注意:代码中的下划线都是两根

第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;

第6行使用__author__变量把作者写进去,这样当你公开源代码后别人就可以瞻仰你的大名;

以上就是Python模块的标准文件模板,当然也可以全部删掉不写,但是,按标准办事肯定没错。

import sys  导入sys模块后,我们就有了变量sys指向该模块,利用sys这个变量,就可以访问sys模块的所有功能。

也可以: from 模块名 import 变量或者函数 ,eg:from math import pi   代码中就可以直接使用pi变量了【而不用写math.pi 】。也可以from math import *

最后,注意到这两行代码:

if __name__=='__main__':
    test()

当我们命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__;而如果在其他地方导入该hello模块时,这个if判断将失败,不会执行test()方法。

【__name__ 是当前模块名,当模块被直接运行时模块名为 __main__ 。这句话的意思就是,当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。】

因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。参考下文

3、模块作用域

外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。

正常的函数和变量名是公开的(public),可以被直接引用,比如:abcx123PI等;

类似【字母前后是双下划线】__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的__author____name__就是特殊变量,hello模块定义的文档注释也可以用特殊变量__doc__访问,我们自己的变量一般不要用这种变量名;

类似【字母前是单/双下划线】_xxx__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc__abc等;

4、安装第三方模块

以前用pip,现在推荐直接使用Anaconda【开源的Python包管理器】,这是一个基于Python的数据处理和科学计算平台,它已经内置了许多非常有用的第三方库,我们装上Anaconda,就相当于把数十个第三方模块自动安装好了,非常简单易用。

可以从Anaconda官网下载GUI安装包,安装包有500~600M,所以需要耐心等待下载。网速慢的同学请移步国内镜像。下载后直接安装,Anaconda会把系统Path中的python指向自己自带的Python,并且,Anaconda安装的第三方模块会安装在Anaconda自己的路径下,不影响系统已安装的Python目录。

安装好Anaconda后,重新打开命令行窗口,输入python,可以看到Anaconda的信息。

5、import与from...import的区别

彻底搞懂Python 中的 import 与 from import

Python 导入其他模块的方式:

  • 什么时候用import xxx
  • 什么时候用from xxx import yyy
  • 什么时候用from xxx.yyy import zzz
  • 什么时候用from xxx import *

1、系统自带的模块

以正则表达式模块re为例:

import re
target = 'abc1234xyz'
re.search('(d+)', target)
from re import search
target = 'abc1234xyz'
search('(d+)', target)

查看他们的类型

>>> import re
>>> type(re)
<class 'module'>
>>> from re import search
>>> type(search)
<class 'function'>

可以看到,直接使用import re导入的re它是一个module类,也就是模块。我们把它成为正则表达式模块。而当我们from re import search时,这个search是一个function类,我们称呼它为search 函数

一个模块里面可以包含多个函数。

如果在你的代码里面,你已经确定只使用search函数,不会再使用正则表达式里面的其他函数了,那么你使用两种方法都可以,没什么区别。但是,如果你要使用正则表达式下面的多个函数,或者是一些常量,那么用第一种方案会更加简洁清晰。

2、第三方模块

例如lxml它既能处理xml的数据,又能处理html的数据,于是这种库会划分子模块,lxml.html模块专门负责html相关的数据。

你可以:from lxml import html

但是不能 import lxml

注:你只能导入一个模块或者导入一个函数或者类,你不能导入一个文件夹 

无论你使用的是import xxx还是from xxx.yyy.zzz.www import qqq,你导入进来的东西,要不就是一个模块(对应到.py 文件的文件名),或者是某个.py 文件中的函数名、类名、变量名。

无论是import xxx还是from xxx import yyy,你导入进来的都不能是一个文件夹的名字。

总结:

  • 无论是使用import还是from import,第一个要求是代码能够正常运行,其次,根据代码维护性,团队编码风格来确定选择哪一种方案。
  • 如果我们只会使用到某个模块下面的一个函数(或者常量、类)并且名字不会产生混淆,可识别性高,那么from 模块名 import 函数名这没有什么问题。
  • 如果我们会用到一个模块下面的多个函数,或者是我们将要使用的函数名、常量名、类名可能会让人产生混淆(例如 re.S、re.I),那么这种情况下,import 模块名 然后再 模块名.xxx来调用会让代码更加清晰,更好维护。
  • 但无论什么情况下,都禁止使用from xxx import * 这种写法,它会给你带来无穷无尽的噩梦。【因为不知道你导入进了啥,写程序这个事情,几乎在任何情况下,白名单都优于黑名单。白名单是可控的,黑名单是总会有漏网之鱼的。】

七、程序入口与__name__

1、程序入口

对于很多编程语言来说,程序都必须要有一个入口,比如 C,C++,以及完全面向对象的编程语言 Java,C# 等。C 和 C++ 都需要有一个 main 函数来作为程序的入口,同样,Java 和 C# 必须要有一个包含 Main 方法的主类来作为程序入口。

Python 则有不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口

一个 Python 源码文件除了可以被直接运行外,还可以作为模块(也就是库)被导入。不管是导入还是直接运行,最顶层的代码都会被运行(Python 用缩进来区分代码层次)。而实际上在导入的时候,有一部分代码我们是不希望被运行的。

举一个例子来说明一下,假设我们有一个 const.py 文件,内容如下:

PI = 3.14

def main():
    print "PI:", PI

main()
View Code

我们在这个文件里边定义了一些常量,然后又写了一个 main 函数来输出定义的常量,最后运行 main 函数就相当于对定义做一遍人工检查,看看值设置的都对不对。然后我们直接执行该文件(python const.py),输出:

PI: 3.14

现在,我们有一个 area.py 文件,用于计算圆的面积,该文件里边需要用到 const.py 文件中的 PI 变量,那么我们从 const.py 中把 PI 变量导入到 area.py 中:

from const import PI

def calc_round_area(radius):
    return PI * (radius ** 2)

def main():
    print "round area: ", calc_round_area(2)

main()
View Code

运行 area.py,输出结果:

PI: 3.14
round area:  12.56

可以看到,const 中的 main 函数也被运行了,实际上我们是不希望它被运行,提供 main 也只是为了对常量定义进行下测试。这时,if __name__ == '__main__' 就派上了用场。把 const.py 改一下:

PI = 3.14

def main():
    print "PI:", PI

if __name__ == "__main__":
    main()
View Code

然后再运行 area.py,输出如下:

round area:  12.56

再运行下 const.py,输出如下:

PI: 3.14

这才是我们想要的效果。

if __name__ == '__main__' 就相当于是 Python 模拟的程序入口Python 本身并没有规定这么写,这只是一种编码习惯。由于模块之间相互引用,不同模块可能都有这样的定义,而入口程序只能有一个。

到底哪个入口程序被选中,这取决于 __name__ 的值。

2、__name__

  __name__ 是内置变量,用于表示当前模块的名字,同时还能反映一个包的结构。来举个例子,假设有如下一个包:

a
├── b
│   ├── c.py
│   └── __init__.py
└── __init__.py

目录中所有 py 文件的内容都为:

print __name__

我们执行 python -c "import a.b.c", 【-c 指定要执行的命令】输出结果:

a
a.b
a.b.c

由此可见,__name__ 可以清晰的反映一个模块在包中的层次。其实,所谓模块名就是 import 时需要用到的名字,例如:

import tornado
import tornado.web

这里的 tornado 和 tornado.web 就被称为模块的模块名。

如果一个模块被直接运行,则其没有包结构,其 __name__ 值为 __main__。例如在上例中,我们直接运行 c.py 文件(python a/b/c.py),输出结果如下:

__main__

而被其它模块导入执行的值为该模块(a.py)的名字a

所以,if __name__ == '__main__' 我们简单的理解就是: 如果模块是被直接运行的,则代码块被运行,如果模块是被导入的,则代码块不被运行

原文地址:https://www.cnblogs.com/peterYong/p/10926510.html