美文网首页那年夏天
Python3学习记录

Python3学习记录

作者: 坚持到底v2 | 来源:发表于2017-10-26 17:59 被阅读87次

一. 安装

1. windows下的安装

(自行去官网或镜像网下载)

注意: 安装的时候 勾上Add Python 3.5 to PATH ,然后点“Install Now”即可完成安装

Windows下开发建议使用 pyCharm 集成 pylint 开发
或者 vscode , IDLE

1.1 基本操作:

Windows 下建议使用 IDLE 编辑器

# 查看版本
python -V
python --version

# 进入交互模式
python # 或 py
 

2. CentOS7 下安装

# 安装 python3.5 可能使用的依赖
yum install -y openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel gcc

# 下载
tarVersion="3.6.2"
tarName="Python-${tarVersion}.tgz"
dirName=`tar -tf "${tarName}" | head -1`
dirName=${dirName%%\/*}

wget "https://www.python.org/ftp/python/${tarVersion}/${tarBallName}"
tar xf ${tarBallName}
cd ${dirName}
mkdir /usr/local/python3

# 编译
./configure --prefix=/usr/local/python3
make && make install

# 拷贝到PATH中
cp /usr/local/python3/bin/python3.6 /usr/bin/

以下是可选步骤

# 备份旧版本python,链接新版本python 
mv /usr/bin/python /usr/bin/python.bak
ln -s /usr/local/python3/bin/python3  /usr/bin/python

# 修改yum配置文件
vi /usr/bin/yum
将第一行指定的python版本改为python2.7(#!/usr/bin/python 改为 #!/usr/bin/python2.7)

二. 简单的示例

1. 脚本

脚本规范

"""
module 描述
"""

` # -*- coding: utf-8 -*-`

# import 不允许使用 from xx import *
# 只允许使用下面的格式
import xx
from yy import zz

# 每级缩进用 4 个空格
# 绝不要混合使用 tab 和空格

# 限制所有行的最大行宽为 79 字符

# 用两行空行分割顶层函数和类的定义

# 包和模块名 必须遵循小写蛇形格式
# 函数名 必须遵循小写蛇形格式

# 类名使用大驼峰格式
# 内部使用的类使用一个额外的前导下划线


def example_func(a_str,b_str): 
    """
    func 描述

    :param a_str: 
    :param b_str: 
    :return: 
    """

    print(a_str,b_str)
    


三. 语法1 - 通用语法

1. 注释

注释 使用 # 开头 ,或使用 '''""" 进行 多行注释

2. 结尾的 ; 是可选的

Python 通常是一行写完一条语句,语句结尾的 ; 是可选的
但是有时确实语句很长, 需要多行写完, 怎么办? 使用 \ 转义回车符,
例如

total=item_one + \
     item_two

同时,有的结构中本身就允许多行输入, 例如 [] {}()

total=[1,
  2]

当然, 同一行也可以写多个语句,以 ; 隔开即可

print("Hello");print("World");

3. 代码块

: 结尾时, "缩进" 的语句视为代码块

空行也是程序代码的一部分!!
函数之间或类的方法之间用 空行 分隔,表示一段新的代码的开始

4. 大小写敏感

5. python中的保留字

查看python中的保留字

交互模式下

import keyword

print(keyword.kwlist)

# 输出
"""
['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 
'finally', 'for', 'from','global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 
'print', 'raise', 'return', 'try', 'while', 'with', 'yield']
"""


四. 语法2 - 变量

1. 变量声明和变量类型

每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建
也可以使用 del 语句删除一些对象引用: del var_a, var_b

# 声明方式
a=1
a=b=c=1
a,b,c=1,2,"runoob"

d=None

# 删除变量
del a,b,c

try:
    print(a)
except Exception as e:
    print('error occurred:',e)
    # error occurred: name 'a' is not defined

标准数据类型

  • Number: 包括 int,float,complex,bool

  • String: 包括

  • List(可变数组)

  • Tuple(不可变数组)

  • Sets(只有key的集合)

  • Dictionary(键值对集合)

判断变量类型 -- type 和 isinstance
typeisinstance 的区别是:
type(some_var) 返回的是变量所属的类
isinstance(some_var,int) 是判断变量是否是指定的类或其子类的对象
issubclass(cls1,cls2) 是判断 cls1 是否是 cls2或其子类

a=20
b=5.5
c=True
d=4+3j

# 打印变量类型
print(type(a), type(b), type(c), type(d))
# 输出 <type 'int'> <type 'float'> <type 'bool'> <type 'complex'>

a=111
# 判断变量类型
print(isinstance(a,int))
# 输出 True

print(issubclass(type(a),int))
# 输出 True

2. 数字类型

# 整数(int) 
a=20

# 浮点数(float 1.23,3E-2) 
b=5.5

# 布尔(bool)
c=True

# 复数(complex a=1+2j) 
d=4+3j 

print(20+10)
print(20-10)
print(20*10)
print(20/10) # 输出 2.0, 除法输出 float
print(5/4) # 输出1.25
print(5//4) # 整除 输出 1
print(5%3) # 取余 输出 2
print(5**2) # 幂运算 输出 25

# bool 运算使用 and or not
print(True and False)
print(True or False)
print(not False)

# 数字判断运算符
print(a >= 18)

3. 字符串

a='astr'
a="aStr"

a='''multiline
str'''
a="""multiline
str"""

a="' in str"
a='" in str'
a="\" in str" # 使用 \ 转义

a="\\n of this line is not lf"
a=r"\n of this line is not lf" # 在字符串前加 `r` 或 `R` 表示是自然字符串
a=u"this is an unicode string" # 在字符串前加 `u` 或 `U` 表示是unicode字符串
# 在最新的Python 3版本中,字符串是以Unicode编码的  

# 按字面意义级联字符串
a="this " "is " "string" # 等同于 a="this is string"

3.1 字符编码和解码 encode和decode

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

print(ord('A')) # 输出 65
print(ord('中')) # 输出 20013
print(chr(66)) # 输出 'B'
print(chr(25991)) # 输出 '文'

print('\u4e2d\u6587') # 输出 '中文'

print('中文'.encode()) # 等价于 print('中文'.encode('utf-8'))
# 输出 
# b'\xe4\xb8\xad\xe6\x96\x87'
print(b'\xe4\xb8\xad\xe6\x96\x87'.decode())
# 输出 '中文'

# 如果bytes中包含无法解码的字节,decode()方法会报错:
try:
    print(b'\xe4\xb8\xad\xff'.decode())
except Exception as e:
    print('error occurred:',e)

# 如果要忽略错误,可以传入errors='ignore'忽略错误的字节:
print(b'\xe4\xb8\xad\xff'.decode( errors='ignore'))
# 输出 '中'

计算字符串字符数 or 字节数

1个中文字符经过UTF-8编码后通常会占用3个字节,而1个英文字符只占用1个字节

print(len('中文'))
# 输出 2
print(len('中文'.encode()))
# 输出 6

3.2 格式化

  • %nd 整数
  • %.nf 浮点数
  • %s 字符串
  • %x 十六进制整数
print('Hi, %s, you have $%d.' % ('Michael', 1000000))
# 只有一个%?时,括号可以省略
print("我叫 %s " % '小明') 
print("今年 %3d 岁!" % (10)) # 数字10 将占3个字符的位置


# 还可以使用 format 格式化
print('Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125))


4. List

元组的元素可以修改, 使用 [] 定义

a_list = [ 'a', 'b','c','d','e','f','g']
tinylist = [1, 2,] # 等价于 tinylist = [1, 2]
   
# 获取list长度
print(len(a_list)) 

# 索引元素
print(a_list[0]) 
# 索引下标为 1和2,不包含3的元素
print(a_list[1:3]) 
print(a_list[2:]) 
a_list[0] = 9
# 设置下标为 2,3,4 不包含5的元素
a_list[2:5] = [13, 14, 15]
a_list[2:5] = [] 
del(a_list[2:5])

# 输出两次列表
print(tinylist * 2) 

# 连接列表
print(a_list + tinylist) 

# 获取列表元素最大值
print(max(a_list))

# 统计 'a' 在列表中出现的次数
print(a_list.count('a'))


# 将元组转换为列表
a_seq = (20,)
print(list(a_seq))

# 成员测试
if('a' in a_list) :
  print('a 在集合中')
else :
  print('a 不在集合中')

# 遍历
for value in ['tic', 'tac', 'toe']: 
    print(value)

for index, value in enumerate(['tic', 'tac', 'toe']): 
    print(index, value)

questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for q, a in zip(questions, answers): 
  print('What is your {0}?  It is {1}.'.format(q, a))

4.1更多列表函数

http://www.runoob.com/python3/python3-list.html
http://www.runoob.com/python3/python3-data-structure.html

4.2 列表推导式

vec = [2, 4, 6]

# 推导出一个新的列表
print([ 3*x for x in vec ]) 
# 输出 [6, 12, 18]

print([[x, x**2] for x in vec])
# 输出 [[2, 4], [4, 16], [6, 36]]

print([3*x for x in vec if x > 3])
# 输出 [12,18]
   
vec1 = [2, 4, 6]
vec2 = [4, 3, -9]
print([x*y for x in vec1 for y in vec2])
# 类似于矩阵相乘
# 输出 [8, 6, -18, 16, 12, -36, 24, 18, -54]

print([vec1[i]*vec2[i] for i in range(len(vec1))])
# 输出 [8, 12, -54]
   
freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
print([weapon.strip() for weapon in freshfruit])
# 输出  ['banana', 'loganberry', 'passion fruit']

4.3 map()函数

map()函数接收两个参数,一个是函数,一个是 Iterable对象(如 列表)
并返回一个 Iterator对象

f=lambda x:x*x

# map函数表示对列表中的每个对象都执行f函数,并返回一个新的列表
r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) 
 # 转换为 list 对象
print(list(r))

# 连起来写就是这样
print(list(map(f,[1, 2, 3, 4, 5, 6, 7, 8, 9])))

4.4 reduce() 函数

reduce() 函数 表示依次对列表中的2个元素执行 某个函数,其效果如下

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

from functools import reduce
add=lambda x,y:x+y;
sum=reduce(add,[1,3,5,7,9]); 
print(sum) # 输出 25

4.5 filter() 函数:

is_odd=lambda n:n%2==1
print(list(filter(is_odd,[1, 2, 4, 5, 6, 9, 10, 15])))

4.6 sorted() 函数

f=lambda x:1/abs(x)
print(sorted([36, 5, -12, 9, -21]))
print(sorted([36, 5, -12, 9, -21],key=abs,reverse=True))
print(sorted([36, 5, -12, 9, -21],key=f,reverse=True))

5. Tuple

元组的元素不能修改, 使用 () 定义

tup4=1,2,3 # 等价于 tup4=(1,2,3)

# 空元组
tup1 = () 

# 包含一个元素的元组 需要在元素后添加逗号
tup2 = (20,)
tup3=(20) # 等价于 tup3=20  !! 等价于声明了一个 int 变量!

tuple的陷阱
当你定义包含一个元素的 tuple 时, 使用
tup2 = (20,) 而不是 tup2 = (20)
后者相当于声明了一个 int 变量!

6. Set(集合)

Set 是一个无序不重复元素的序列, 使用 {} 定义

set和dict的唯一区别仅在于没有存储对应的value,
但是,set的原理和dict一样,所以,同样只能放入不可变对象(hashable对象),
因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。
把list放入set 会报错。

# 声明
students = {'Tom', 'Jim', 'Mary', 'Tom', 'Jack', 'Rose'}
a = set('abracadabra')
print(a)
# 输出 {'d', 'b', 'r', 'a', 'c'}

print(set([1, 2, 2]))
# 输出 {1, 2}

# 成员测试
if('Rose' in student) :
  print('Rose 在集合中')
else :
  print('Rose 不在集合中')

# 遍历
for stu in students:
    print(stu)

# 集合运算 
a = set('dbrac')
b = set('zalmc')
# 差集
print(a - b) 
# 并集
print(a | b) 
# 交集
print(a & b) 
# 异或
print(a ^ b) 

7. Dictionary(字典)

Dictionary 无序的对象集合,键(key)必须使用不可变类型,且必须是唯一的.
DictionarySet 一样,也使用 {} 定义, 但是其内容是 key:value 格式,而不是只有 key .

# 声明
a_dict = {}
tinydict = {'name': 'runoob','code':1 }
tinydict = dict(name='runoob',code=1)
tinydict=dict([('name', 'runoob'), ('code', 1)])
tinydict={x: x**2 for x in (2, 4, 6)}

# 赋值
a_dict['one'] = "1 - 菜鸟教程"
a_dict[2] = "2 - 菜鸟工具"
a_dict.pop('three')

# 索引
print(a_dict['one'])
# 如果字典中不存在该key,则索引该key的内容会报异常
# 可以使用 tinydict.get('name') 获取key的内容,
# key 不存在时返回None,而不是异常
print(a_dict.get('three','defalutvalue'))


# 输出所有键
print(tinydict.keys()) 

# 输出所有值
print(tinydict.values()) 

# 成员测试
if('name' in tinydict) :
  print('name 在字典中')
else :
  print('name 不在字典中')


# 遍历
knights = {'gallahad': 'the pure', 'robin': 'the brave'}
for k, v in knights.items(): 
    print(k,v);

8. 数据类型转换

# 取整
int(1.234)==1
math.floor(1.234)==1

# 将别的进制的字符串转成整形
int("0o77",8)==63
int("0xff",16)==255
oct(63)=='0o77'
hex(255)=='0xff'

# eval
eval("1+1")==2


五. 语法3 - 运算符&函数

1. 运算符:

  • 数值运算
    + - * /
    //(整除) %(取余) ** 幂运算

  • 赋值运算符
    += -= *= ...

  • 比较运算符:
    == != > >= <=

  • 位运算符
    & | ^(异或) ~(取反) << >>

  • 逻辑运算符
    and or not

  • 成员运算符
    a in list
    a not in list

  • 身份运算符 is / is not
    a is b
    a is not b
    id(a) == id(b)


六. 语法4 - 流程语句

1. if 语句

import random
a=random.choice(range(10))

if (a>8):
    print('a>8')
elif a>5:
    print('a>5')
else:
    print('other')

2. while 循环

在Python中没有do..while循环

a=1
while a<3:
  print(a)
  a+=1
else:
  print('end')

# 输出
1
2
end

a=1
while a<4:
  if a>2:
    break

  print(a)
  a+=1
else:
  print('end')

# 输出
1
2

3. for 循环

names = ['Michael', 'Bob', 'Tracy']
for name in names:
    print(name)
else:
    print('end')

# 输出
Michael
Bob
Tracy
end

4. 迭代器

可以直接作用于for循环的对象统称为可迭代对象:Iterable
可以被 next() 函数调用并不断返回下一个值的对象称为迭代器:Iterator

可以使用 isinstance() 判断一个对象是否是 Iterable对象
list、tuple、dict、set、str 等都是 Iterable对象,
但不是 Iterator

把 list、dict、str等 Iterable 变成 Iterator 可以使用 iter() 函数

你可能会问,为什么list、dict、str等数据类型不是Iterator?

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

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

isinstance([], Iterable)
# True

isinstance([], Iterator)
# False

a_list=[1,2,3,4]
it = iter(a_list) 
# 转换回列表可以
a_list2=list(it)
# 但是转换回列表后 it 也就废了,不能再对其进行遍历了

it = iter(a_list) 
# 遍历 Iterator
for x in it:
  print(x, end=" ")
  
while True:
  try:
    print(next(it))
  except StopIteration:
    break

# 使用列表推导式生成 Iterator 的示例  
g = (x * x for x in range(10))
print(type(g))
# 输出 <class 'generator'>

# 遍历 generator
for n in g: 
    print(n)

5. 生成器:

使用了 yield 的函数被称为生成器(generator

  • 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

  • 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值。
    并在下一次执行 next() 方法时从当前位置继续运行。

以下实例使用 yield 实现斐波那契数列
http://www.runoob.com/python3/python3-iterator-generator.html


六. 语法4 - 其他语句

1. pass 语句:

空语句,不做任何事情,一般用做占位语句,
因为有的时候你确实什么都不想做, 但不写语句语法有过不去,所以...

def nop():
    pass

2. 模块

举个例子,一个abc.py的文件就是一个名字叫abc的模块,一个xyz.py的文件就是一个名字叫xyz的模块。

现在,假设我们的abc和xyz这两个模块名字与其他模块冲突了,于是我们可以通过包来组织模块,避免冲突。
方法是选择一个顶层包名,比如mycompany,按照如下目录存放:

mycompany
├─ __init__.py
├─ abc.py
└─ xyz.py

现在,abc.py模块的名字就变成了mycompany.abc,类似的,xyz.py的模块名变成了mycompany.xyz

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

2.00 作用域

模块示例

#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
"""
mython12

@Version: 1.0
@Python Version:3.6.6
@Author: ludq1
@File: test2
@Time: 2019/1/10 19:10
@Description:
"""

__author__='ludq1'

def test():
    """
    test函数
    Returns:

    """
    print("test")

if __name__=='__main__':
    test()

在一个模块中,我们可能会定义很多函数和变量,但有的函数和变量我们希望给别人使用,有的函数和变量我们希望仅仅在模块内部使用。在Python中,是通过 _ 前缀来实现的。

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

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

类似 _xxx__xxx 这样的函数或变量就是非公开的(private),不应该被直接引用,比如 _abc__abc 等;

之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量。

2.01 安装第三方模块

在Python中,安装第三方模块,是通过包管理工具pip/pip3完成的。

2.02 导入模块 import 与 from...import

# 导入整个 module
import somemodule1,module2,...

# 导入module 中特定的函数
from somemodule import somefunction
# 从某个模块中导入某个函数
from somemodule import firstfunc, secondfunc, thirdfunc
# 将某个模块中的全部函数导入
from somemodule import *

注:
(1) 模块中那些由单一下划线(_)开头的名字不能导入
(2) 不管你执行了多少次import 一个模块只会被导入一次

2.1 当我们使用import语句的时候,Python解释器是怎样找到对应的文件的呢?

当我们试图加载一个模块时,Python会在指定的路径下搜索对应的.py文件,如果找不到,就会报错

默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在 sys模块的path变量中

如果我们要添加自己的搜索目录,有两种方法:
一是直接修改 sys.path ,添加要搜索的目录:

import sys
sys.path.append('/Users/michael/my_py_scripts')

这种方法是在运行时修改,运行结束后失效。

第二种方法是设置环境变量 PYTHONPATH ,该环境变量的内容会被自动添加到模块搜索路径中。
设置方式与设置Path环境变量类似。
注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。


七. 语法5 - 自定义函数

1. 函数定义


def printinfo1( name, age ):
    """
    可选的函数说明文档
    """

    print('Hi, %s, your age is %d.' % (name, age))



# 默认参数示例
def printinfo2( name, age = 35 ):
    """
    可选的函数说明文档
    """

    print('Hi, %s, your age is %d.' % (name, age))


# 函数调用
printinfo1('Jackie',40)
printinfo1(age=40,name="Jackie")
printinfo2('Jackie')
printinfo2(name='Jackie')

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

def add_end(L=[]):
    L.append('END')
    return L

add_end()
# 输出 ['END']

# 但是,再次调用add_end()时,结果就不对了:
add_end()
# 输出 ['END', 'END']
add_end()
# 输出 ['END', 'END', 'END']

上面的例子原因解释如下:
Python函数在定义的时候,默认参数L的值就被计算出来了,即 []
因为默认参数L也是一个变量,它指向对象 []
每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的 [] 了。

2. 不定长参数

加了星号(*)的变量名会存放所有未命名的变量参数。
如果在函数调用时没有指定参数,它就是一个空元组。
我们也可以不向函数传递未命名的变量

def printinfo3( arg1, *vartuple ):
    print('arg1:',arg1)
    print('otherArgs:',vartuple)


# 调用printinfo3 函数
printinfo3(1,2,3)
aTuple=(1,2,3)
printinfo3(*aTuple); 
# 输出 
"""
arg1: 1
otherArgs: (2, 3)
"""

# 更一般的用法是 
def printinfo4(*vartuple,arg1='arg1'):
    print('arg1:',arg1)
    print('otherArgs:',vartuple)

# 调用printinfo3 函数
printinfo4(1,2,3,arg1='a')
aTuple=(1,2,3)
printinfo4(*aTuple,arg1='a'); 
printinfo4(*aTuple); 
# 输出
"""
arg1: arg1
otherArgs: (1, 2, 3)
"""

3. 不定长参数2

def printinfo5( arg1, **kwargs ):
    print('arg1:',arg1)
    print('otherArgs:',kwargs)

# 调用printinfo5 函数
printinfo5(1,arg2=2,arg3=3)
aDict={'arg1':1,'arg2':2,'arg3':3}
printinfo5(**aDict); 
# 输出
"""
arg1: 1
otherArgs: {'arg2': 2, 'arg3': 3}
"""

aDict={'arg2':2,'arg3':3}
printinfo5(1,**aDict); 
# 输出同上


# 更一般的用法是
def printinfo6( **kwargs ):
    print('args:',kwargs)

# 调用printinfo6 函数
aDict={'arg1'=1,'arg2'=2,'arg3'=3}
printinfo6(**aDict)

3.2 命名关键字参数

def person(name, age, *, city, job):
    print(name, age, city, job)

# 调用
person('Jack', 24, city='Beijing', job='Engineer')

# 如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了
def person(name, age, *args, city, job):
    print(name, age, args, city, job)

# 错误的调用
person('Jack', 24, 'Beijing', 'Engineer')
# 这是由于调用时缺少参数名city和job,Python解释器把这4个参数均视为位置参数,但person()函数仅接受2个位置参数。

4. 匿名函数 lambda 表达式

sum = lambda arg1, arg2: arg1 + arg2;

5. 返回None

不带参数值的 return语句 返回 None

6. 返回多个值.

def test():
    return 1,2
    # 其实返回多个值,就是返回一个 tuple,等价于返回 `return (1,2)`

x,y=test();
print(x,y);
# 输出 1,2

aa=test()
print(aa)
# 输出 (1,2)

7. 变量作用域

查找顺序: L(局部) –> E(闭包函数外的函数中) –> G(全局) –>B(内建作用域)

Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,
其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这这些语句内定义的变量,外部也可以访问

在函数内部虽然可以访问全局变量,但是无法更改全局变量,
例如:

# 这是一个全局变量
total = 0; 
# 可写函数说明
def sum( arg1, arg2 ):
    #返回2个参数的和.
    # total在这里是局部变量.
    total = arg1 + arg2 

    # 如果是 total=total+arg1+arg2 会报错, 这是因为系统查找当前作用域找不到total,使用未定义的 total 变量也会出错


    print("函数内是局部变量 : ", total)
    return total;

#调用sum函数
sum( 10, 20 ); 
# 输出30
print("函数外是全局变量 : ", total) 
# 输出0

# 如果要想修改全局变量,需要使用 global ,例如
def sum( arg1, arg2 ):
    #返回2个参数的和.
    # 声明 total 为全局变量 或 将全局变量 total 引用到此处
    global total
    total =  arg1 + arg2; 
    print("函数内是局部变量 : ", total)
    return total;


如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字


八. 异常

1. 示例

该示例让用户输入一个数字,如果输入不正确则提示后继续等待用户输入

count=0
while True:
    try:
      x = int(input("Please enter a number: "))
      count+=1
      if count>2:
        break
    # 捕获单个异常
    except ValueError as e:
      print("Oops! That was no valid number:",e,".  Try again   ")
    # 捕获多个异常(KeyboardInterrupt 是 Ctrl+C, EOFError 是 Ctrl+Z)
    except (ValueError,KeyboardInterrupt,EOFError) as e:
      print("Oops! That was someError:",e,".  Try again   ")
    # 捕获任意的异常
    except Exception as e:
      print("Oops! That was someError:",e,".  Try again   ")
    # 捕获任意的异常
    except:
      print("Oops! That was someError.  Try again   ")
    # 没有异常的时候执行,提前break时代码不会执行到此处
    else:
        print("no error")
    # 无论如何都会执行, 提前break时代码也会执行到此处
    # 用于表示无论何时都会执行的"清理行为"
    finally:
        print("finally")

2. 示例2:

try: 
    f = open('foo.txt', 'r')
except IOError: 
    print('cannot open', arg)
else:
    print('foo.txt', 'has', len(f.readlines()), 'lines')
    f.close()

2.1 打印调用栈

import logging

def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    try:
        bar('0')
    except Exception as e:
        logging.exception(e)

main()
print('END')

3. 抛出异常 raise

raise NameError('HiThere')

4. 自定义异常

继承 Exception 类

6. 预定义的"清理行为": 使用 with

例如下面的代码

for line in open("foo.txt"):  
    print(line, end="")

# 以上这段代码的问题是,当执行完毕后,文件会保持打开状态,并没有被关闭
# 使用with,就算在处理过程中出问题了,文件 f 总是会关闭
f=open("foo.txt")
print(f.closed)
# 输出 False

with f:
    raise NameError('HiThere')

print(f.closed)
# 输出 True

7. 调试

7.1 print

7.2 assert :

python -O 来关闭assert

7.3 logging:

import logging;
logging.basicConfig(level=logging.INFO)
logging.info('someMsg')

7.4 pdb: 单步调试

python -m pdb err.py

# 输入 `n` 单步执行代码; 
# 任何时候都可以输入命令 `p 变量名` 来查看变量; 
# q 结束调试

7.5 使用IDE

最后,当然最爽的还是使用 IDE:
目前比较好的Python IDE有PyCharm:
另外,Eclipse加上pydev插件也可以调试Python程序。

8. 单元测试

假设你写了一个模块 my_module.py

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

class Student(object):
    _name = 'defaultname'

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        # some code
        self._name = value

    def print_name(self):
        print('my name is ', self.name)

编辑一个文件(例如名为 my_module_test.py )

import unittest

from my_module import Student

# 需要继承 unittest.TestCase 
class TestMyModule(unittest.TestCase):

    # 以test开头的方法就是测试方法,
    # 不以test开头的方法不被认为是测试方法,测试的时候不会被执行
    def test_init(self):
        stu = Student()
        self.assertEqual(stu.name, 'defaultname')
        self.assertTrue(isinstance(stu, object))

    def test_attrerror(self):
        stu = Student()
        with self.assertRaises(Exception):
            value = stu.namexx

    # setUp 和 tearDown 这两个方法会分别在每调用一个测试方法的前后分别被执行
    def setUp(self):
        print('setUp...')

    def tearDown(self):
        print('tearDown...')

# 最简单的运行方式是判断是否是 main进程
if __name__ == '__main__':
    unittest.main()

另一种运行方式是
python -m unittest my_module_test

9. 文档测试

就是直接按照文档进行测试

直接上代码

# mydict2.py
class Dict(dict):
    '''
    Simple dict but also support access as x.y style.

    >>> d1 = Dict()
    >>> d1['x'] = 100
    >>> d1.x
    100
    >>> d1.y = 200
    >>> d1['y']
    200
    >>> d2 = Dict(a=1, b=2, c='3')
    >>> d2.c
    '3'
    >>> d2['empty']
    Traceback (most recent call last):
        ...
    KeyError: 'empty'
    >>> d2.empty
    Traceback (most recent call last):
        ...
    AttributeError: 'Dict' object has no attribute 'empty'
    '''
    def __init__(self, **kw):
        super(Dict, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Dict' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

if __name__=='__main__':
    import doctest
    doctest.testmod()

运行该脚本 什么输出也没有。
这说明我们编写的doctest运行都是正确的。
如果程序有问题,比如把 __getattr__()方法 注释掉,再运行就会报错:

相关文章

  • Python3学习记录

    一. 安装 1. windows下的安装 (自行去官网或镜像网下载) 注意: 安装的时候 勾上Add Python...

  • scrapy python爬虫框架使用

    scrapy已经支持python3,以下是在mac python3环境下使用记录,假设已经安装python3。 s...

  • centos自定义安装pip3

    题记 在之前的文章centos云服务器安装Python3记录 记录了怎么自定义安装 Python3 ,在后边测试p...

  • head first Python 学习

    这本书以Python3为讲解,我安装的是Python2.7,以下写出学习记录。 page76:print(data...

  • 01学习记录Python

    学习记录,欢迎指出错误 Python3基础语法 编码 默认情况下,Python源码文件是以UTF-8编码,所有字符...

  • Python踩坑记录

    发现上一篇Python记录写到后面像是我的学习笔记了,还是单开一个记录一下踩坑吧。 1.字典python3中,使用...

  • Python3 个人学习记录

    Python3 学习记录 1.数据类型与变量 整数 浮点数 字符串 布尔型 常量 运算符 2.字符串与编码 字符串...

  • 一周学习精选(2018-09-09)

    Python3 最近在对接 Python3 写的项目,也从中学习一些 Python3 的风格。总的来说,Pytho...

  • Python3学习笔记--基础知识

    Python3学习笔记--基础知识

  • 用C调用python函数简易教程

    因为项目需要,所以学习了一下如何使用C/C++调用python2/python3。先记录如下: 现在主流是使用py...

网友评论

    本文标题:Python3学习记录

    本文链接:https://www.haomeiwen.com/subject/cnkxpxtx.html