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原则:

python 中文文本纠错 模型_作用域

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]