python学习易错点

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学习易错点_第1张图片

  •  当在函数中使用未认证的变量名时,python搜索4个作用【本地作用域(L),之后是上一层结构中的def或lambda的本地作用域(E),之后是全局作用域(G),最后是内置作用域(B)】,并且在第一处能够找到这个变量的地方停下来。也就是说,在本地作用域的变量名可能会覆盖在全局作用域和内置作用域有着相同变量名的变量,而全局变量有可能覆盖内置的变量名,例:open是内置变量名,现创建一个名为open的本地变量名。
    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]  

你可能感兴趣的:(python基础)