1.列表的浅复制和深复制的区别
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 10 16:45:11 2018
@author: lizihua
"""
import copy
#浅复制
#列表是一维的
lst1=[1,1,1,1,1]
lst2=copy.copy(lst1)
#lst2=lst1.copy() #同上
lst1[1]=0
print("浅复制(list一维):")
print("lst1:",lst1)
print("lst2:",lst2)
#result:
#lst1: [1, 0, 1, 1, 1]
#lst2: [1, 1, 1, 1, 1]
#列表是多维的
lst3=[[1,1,1],[1,1,1]]
lst4=copy.copy(lst3)
#lst4=lst3.copy() #同上
lst3[1][1]=0
print("浅复制(list多维):")
print("lst3:",lst3)
print("lst4:",lst4)
#result
#lst3: [[1, 1, 1], [1, 0, 1]]
#lst4: [[1, 1, 1], [1, 0, 1]]
#深复制
lst5=[[1,1,1],[1,1,1]]
lst6=copy.deepcopy(lst5)
lst5[1][1]=0
print("深复制:")
print("lst5:",lst5)
print("lst6:",lst6)
#result
#lst5: [[1, 1, 1], [1, 0, 1]]
#lst6: [[1, 1, 1], [1, 1, 1]]
2.python记录程序运行时间的三种方法
#方法一
import datetime
starttime = datetime.datetime.now()
#运行函数
endtime = datetime.datetime.now()
print((endtime - starttime).seconds)
#方法二
import time
start = time.time()
#循环函数
end = time.time()
print(end-start)
#方法三
start = time.clock()
#运行函数
end = time.clock()
print(end-start)
方法1和方法2都包含了其他程序使用CPU的时间,是程序开始到程序结束的运行时间,即这期间,cpu可能运行了其他程序。
方法3算只计算了程序运行的CPU时间。
3. 作用域法则
3.1 LEGB原则:
def hider():
open='spam' #局部变量,隐藏了内置变量open
open('salary.txt') #在该本地作用域内,无法打开本文件
hider()
- 当在函数中给一个变量名赋值时,python总是创建或改变本地作用域的变量名,除非它已经在那个函数中声明为全局变量。
- 当在函数之外给一个变量名赋值时,本地作用域与全局作用域(在这个模块的命名空间)是相同。
注意:
- 一个函数内部的任何类型的赋值都会把一个名称划定为本地的,ps:原处改变对象并不会把变量划分为本地变量,即修改对象(例:L.append(X))并不是对一个名称赋值(例:L=X)。
- 全局声明(global)和非本地声明(nonlocal)将赋值的变量名映射到模块文件内部的作用域(即:全局变量)
3.2 作用域实例
#Global scope
X=99
def func(Y):
#Local scope
Z=X+Y
return Z
func(1) #result:100
#全局变量名:X,func
#本地变量名:Y,Z
import builtins
dir(builtins)
"""
***************************以下变量名组成了Python中的内置作用域***********************
['ArithmeticError','AssertionError','AttributeError','BaseException','BlockingIOError',
'BrokenPipeError','BufferError','BytesWarning','ChildProcessError','ConnectionAbortedError',
'ConnectionError','ConnectionRefusedError','ConnectionResetError','DeprecationWarning',
......
'print','property','range','repr','reversed','round','runfile','set','setattr','slice',
'sorted','staticmethod','str','sum','super','tuple','type','vars','zip']
"""
3.3 global语句
#对比
X=88 #全局变量
def func():
X=99 #本地变量
print(X) #本地作用域内,因此,result:99
func()
print(X) #全局作用域内,因此,result:88
#对比
X=88 #全局变量
def func():
global X #定义全局变量
X=99 #全局变量
func()
print(X) #全局作用域内,因此,result:99
3.4 嵌套作用域
#使用def嵌套
X=88 #全局变量
def f1():
X=99 #本地变量
def f2():
print(X) #本地作用域内,因此,result:99
f2()
f1() #result:99
从上面可以看出,嵌套的def(即:f2函数)在函数f1调用时运行,f2是f1的本地作用域的一个本地变量,在此情况下,f2是一个临时函数,仅在f1内部执行的过程中存在(并且只对f1中代码可见)。当打印变量X时,X引用了存在于函数f1整个本地作用域的变量X的值。因为函数能够在整个def声明内获取变量名,通过LEGB查找法则,f2内X自动映射了f1的X.
#使用lambda嵌套
def func():
x=4
action=(lambda n:x**n)
return action
x=func() #记住x=4,并返回func()函数
print(x(2)) #print:16,4**2
3.5 nonlocal语句
nonlocal应用于一个嵌套的函数的作用域的一个名称,而非所有def之外的全局模块作用域。而且在声明nonlocal名称的时候,它必须已经存在于该嵌套函数的作用域中。换句话说,nonlocal即允许对嵌套的函数作用域中的名称赋值,并且把这样的名称的作用域查找限制在嵌套的def。
#例子:
#tester构建并返回函数nested以便随后调用,
#nested中的state应用使用超常规的作用域查找规则来映射tester的本地作用域
def tester(start):
state=start
def nested(label):
print(label,state)
return nested
F=tester(0)
F('spam') #result:spam 0
#默认情况下,不允许修改嵌套的def作用域的名称。
def tester(start):
state=start
def nested(label):
state+=1 #默认不可改变
print(label,state)
return nested
F=tester(0)
F('spam') #result:spam 0
#报错:UnboundLocalError: local variable 'state' referenced before assignment
#修改后:
def tester(start):
state=start
def nested(label):
nonlocal state #定义state在嵌套函数作用域
state+=1
print(label,state)
return nested
F=tester(0)
F('spam') #result:spam 1
使用nonlocal语句的好处:允许在内存中保存多变状态的多个副本,并且解决了在类中无法保证的情况下的简单的状态保持。
4. 默认和可变对象
默认参数是def语句运行时评估并保存的,而不是在这个函数调用时。从内部上来讲,Python会将每一个默认参数保存成一个对象,附加在这个函数本身。
当修改可变的默认参数时,应特别小心!!!
举个例子:
def saver(x=[]):
x.append(1)
print(x)
saver([2]) #默认值没有使用,result:[2,1]
saver() #使用默认值,result:[1]
saver() #result:[1,1]
saver() #result:[1,1,1]
这是因为可变参数在函数调用之间保存了它们的状态,从某种意义上讲,它们能充当C语言中的静态本地函数变量的角色。在一定程度上,它们工作起来就像全局变量,但它们的变量名对于函数而言是本地变量,而且不会与程序中其他变量名发生冲突。
在这个例子中,其中只有一个列表对象作为默认值,这个列表对像是在def语句执行时被创建的,不会每次函数调用时都得到一个新的列表,所以,每次新的元素加入后,列表会变大,对于每次调用,它都没有重置为空列表。
更改后:
def saver(x=None):
x = x or []
x.append(1)
print(x)
"""
#或:
def saver(x=None):
if x is None:
x =[]
x.append(1)
print(x)
"""
saver([2]) #默认值没有使用,result:[2,1]
saver() #使用默认值,result:[1]
saver() #result:[1]
5.没有return语句的函数
在python函数中,return(以及yield)语句是可选的,当一个函数没有精准的返回值的时候,函数在控制权从函数主体脱离时,函数将退出,从技术上讲,所有函数都返回了一个值,如果没有return语句,函数将自动返回None对象:
def proc(x):
print(x)
x=proc('lizihua') #return:lizihua
print(x) #return:None
#一个例子:list.append就是这样一个没有return的函数
lst=[1,2,3,4,5]
lst=lst.append(6)
print(lst) #return:None
#想要获得lst=[1,2,3,4,5,6],代码应为:
lst=[1,2,3,4,5]
lst.append(6)
print(lst) #return:[1,2,3,4,5,6]