深入解析Python中函数的参数与作用域

传递参数

函数传递参数时的一些简要的关键点:

  • 参数的传递是通过自动将对象赋值给本地变量名来实现的。所有的参数实际上都是通过指针进行传递的,作为参数被传递的对象从来不自动拷贝。
  • 在函数内部的参数名的赋值不会影响调用者。
  • 改变函数的可变对象参数的值会对调用者有影响。

实际上,Python的参数传递模型和C语言的相当相似:

不可变参数”通过值”进行传递。像整数和字符串这样的对象是通过对象引用而不是拷贝进行的,但是因为不论怎么样都不可能在原处改变不可变对象,实际的效果就很像创建了一份拷贝。
可变对象是通过”指针”进行传递的。这就意味着,可变对象能够在函数内部进行原处修改。
>>避免可变参数的修改
避免参数的修改有很多种方式:

传递参数时,传递一个拷贝:

L = [1,2]
changer(L[:])

函数内部进行拷贝

def changer(b):
 b=b[:]

将可变对象转化为不可变对象

L=[1,2]
changer(tuple(L))

>>对参数输出进行模拟
对于参数的返回值有一个小技巧:因为return能够返回任意种类的对象,如果这些值封装进一个元组或其他的集合类型,那么它也能够返回多个值。

def multiple(x,y):
 x = 2
 y = [2,4]
 return x,y #Return new values in a tuple

这段代码貌似返回了两个值,其实只有一个:一个包含了2个元素的元组,它的括号是可以省略的。

特定的参数匹配模型

>>基础知识
匹配模型的大纲:

  • 位置:从左至右进行匹配。
  • 关键字参数:通过参数名进行匹配。(调用者可以定义哪一个函数接受这个值,通过在调用时使用参数的变量名,使用name=value这种语法。)
  • 默认参数:为没有传入值的参数定义参数值。
  • 可变参数:搜集任意多基于位置或关键字的参数。
  • 可变参数解包:传递任意多的基于位置或关键字的参数。
  • Keyword-only参数:参数必须按照名称传递。(只存在于Python3.0中)

>>匹配语法

语法 位置   解释
func(value) 调用者 常规参数:通过位置进行匹配。
func(name=value) 调用者 关键字参数:通过变量名匹配。
func(*sequence) 调用者 以name传递所有的对象,并作为独立的基于位置的参数。
func(**dict) 调用者 以name成对的传递所有的关键字/值,并作为独立的关键字参数。
def func(name) 函数 常规参数:通过位置或变量名进行匹配。
def func(name=value) 函数 默认参数值,如果在调用中传递的话。
def func(*name) 函数 匹配并收集(在元组中)所有包含位置的参数。
def func(**name) 函数 匹配并收集(在字典中)所有包含位置的参数。
def func(*args,name) 函数 参数必须在调用中按照关键字传递。
def func(*,name=value) 函数  参数必须在调用中按照关键字传递。(Python3.0)

相应的说明:

在函数的调用中(表中的前4行),简单的通过变量名位置进行匹配,但是使用name=value的形式告诉Python依照变量名进行匹配,这些叫做关键字参数。在调用中使用*sequence或**dict允许我们在一个序列或字典中相应地封装任意多的位置相关或者关键字的对象,并且在将他们传递给函数的时候,将它们解包为分开的、单个的参数。
在函数的头部,一个简单的变量名时通过位置或变量名进行匹配的(取决于调用者是如何传递给它参数的),但是name=value的形式定义了默认的参数值。*name的形式收集了任意的额外不匹配的参数到元组中,并且**name的形式将会手机额外的关键字参数到字典中。在Python3.0及其以后的版本中,跟在*name或一个单独的*之后的、任何正式的或默认的参数名称,都是keyword-only参数,并且必须在调用时按照关键字传递。
>>细节
在使用混合的参数模型的时候,Python将会遵循下面有关顺序的法则。

在函数调用中,参数必须以此顺序出现:任何位置参数(value),后面跟着任何关键字参数(name=value)和*sequence形式的组合,后面跟着**dict形式。
在函数头部,参数必须以此顺序出现:任何一般参数(name),紧跟着任何默认参数(name=value),后面是name(在Python3.0中是)形式,后面跟着任何name或name=value keyword-only参数(Python3.0中),后面跟着**name形式。
在调用和函数头部中,如果出现**arg形式的话,都必须出现在最后。

Python内部是使用以下的步骤来在赋值前进行参数匹配的:

  • 通过位置分配非关键字参数。
  • 通过匹配变量名分配关键字参数。
  • 其他额外的非关键字分配到*name元组中。
  • 其他额外的关键字参数分配到**name字典中。
  • 用默认值分配给在头部未得到分配的参数。
  • 在这之后,Python会进行检测,确保每个参数只传入了一个值。如果不是这样的话,将会发生错误。当所有匹配都完成了,Python把传递给参数名的对象赋值给它们。

>>关键字参数和默认参数的实例
如果没有使用任何特殊的匹配语法,Python默认会通过位置从左至右匹配变量名。

def f(a,b,c):
 print(a,b,c)

f(1,2,3)   #Prints 1,2,3

关键字参数

关键字参数允许通过变量名进行匹配,而不是通过位置。

f(c=3,b=2,a=1) #Prints 1,2,3

默认参数

默认参数允许创建函数可选的参数。如果没有传入值的话,在函数运行前,参数就被赋了默认值。

def f(a,b=2,c=3):
 print(a,b,c)

f(1)    #Prints 1,2,3
f(1,4)   #Prints 1,4,3
f(1,c=6)   #Prints 1,2,6

关键字参数和默认参数的混合

def func(spam,eggs,totast=0,ham=0):
 print((spam,eggs,totast=0,ham=0))
func(1,2)     #Ouput:(1,2,0,0)
func(1,ham=1,eggs=0)  #Ouput:(1,0,0,1)
func(spam=1,eggs=0)   #Ouput:(1,0,0,0)
func(toast=1,eggs=2,spam=3) #Ouput:(3,2,1,0)
func(1,2,3,4)    #Ouput:(1,2,3,4)

>>任意参数的实例
最后两种匹配扩展,*和**,是让函数支持接收任意数目的参数的。

收集参数

在函数定义中,在元组中收集不匹配的位置参数。

def f(*args):print(args)

当这个函数调用时,Python将所有位置相关的参数收集到一个新的元组中,并将这个元组赋值给变量args。因此它是一个一般的元组对象,能够进行索引或迭代。

**特性类似,但是它只对关键字参数有效。将这些关键字参数传递给一个新的字典,这个字典之后将能够通过一般的字典工具进行处理。在这种情况下,**允许将关键字参数转化为字典,你能够在之后使用键调用进行步进或字典迭代。

def f(a,*pargs,**kargs):print(a,pargs,kargs)

f(1,2,3,x=1,y=2)  #Prints:1 (2,3) {'x':2,'y':1}

解包参数

在最新的Python版本中,我们在调用函数时能够使用*语法。在这种情况下,它与函数定义的意思相反。它会解包参数的集合,而不是创建参数的集合。

def func(a,b,c,d):print(a,b,c,d)
args=(1,2)
args+=(3,4)
func(*args)   #Prints 1,2,3,4

相似的,在函数调用时,**会以键/值对的形式解包一个字典,使其成为独立的关键字参数。

args={'a':1,'b':2,'c':3}
args['d']=4
func(**args)   #Prints 1,2,3,4

注意:别混淆函数头部和函数调用时*/**的语法:在头部,它意味着收集任意多的参数,而在调用时,它解包任意数量的参数。

应用函数通用性

if <test>:
 action,args=func1,(1,)
else:
 action,args=func2,(1,2,3)
...

action(*args)

>>Python3.0 Keyword-Only参数
Python3.0把函数头部的排序规则通用化了,允许我们指定keyword-only参数——即必须只按照关键字传递并且不会由一个位置参数来填充的参数。

从语法上讲,keyword-only参数编码为命名的参数,出现在参数列表中的*args之后。所有这些参数都必须在调用中使用关键字语法来传递。

我们也可以在参数列表中使用一个*字符,来表示一个函数不会接受一个变量长度的参数列表,而是仍然期待跟在*后面的所有参数都作为关键字传递。

def kwonly(a,*,b,c):
 print(a,b,c)
kwonly(1,c=3,b=2) #Prints:1,2,3
kwonly(c=3,b=2,a=1) #Prints:1,2,3
kwonly(1,2,3)  #Error!

上述代码中,b和c必须按照关键字传递,不允许其他额外的位置传递。

另外,默认函数仍然对keyword-only参数有效,所以,实际上,带有默认值的keyword-only参数都是可选的,但是,那些没有默认值的keyword-only参数真正地变成了函数必需的keyword-only参数。

排序规则 最后,注意keyword-only参数必须在一个单个星号后指定,而不是两个星号——命名的参数不能出现在**args任意关键字形式的后面,并且一个**不能独自出现在参数列表中。这两种做法将产生错误。

def kwonly(a,**pargs,b,c)  #Error!
def kwonly(a,**,b,c)   #Error!

这就意味着,在一个函数的头部,keyword-only参数必须编写在**args任意关键字形式之前,且在*args任意位置形式之后。

实际上,在函数调用中,类似的排序规则也是成立的:当传递keyword-only参数的时候,它们必须出现在一个**args形式之前。keyword-only参数可以编写在*arg之前或者之后,并且可能包含在**args中:

def f(a,*b,c=6,**d):print(a,b,c,d)

f(1,*(2,3),**dict(x=4,y=5))  #Prints:1 (2,3) 6 {'x':4,'y':5}
f(1,*(2,3),**dict(x=4,y=5),c=7) #Error!
f(1,*(2,3),c=7,**dict(x=4,y=5)) #Prints:1 (2,3) 7 {'x':4,'y':5}
f(1,c=7,*(2,3),**dict(x=4,y=5)) #Prints:1 (2,3) 7 {'x':4,'y':5}
f(1,*(2,3),**dict(x=4,y=5,c=7)) #Prints:1 (2,3) 7 {'x':4,'y':5}

Python作用域

在一个Python程序只用变量名时,Python创建、改变或查找变量名都是在所谓的命名空间(一个保存变量名的地方)中进行的。也就是说,在代码中变量名被赋值的位置决定了这个变量名能被访问到的范围,也即决定了它存在于哪个命名空间中。

除了打包程序之外,函数还为程序增加了一个额外的命名空间层:默认情况下,一个函数所有变量名都是与函数的命名空间相关联的。这意味着:

一个在def内的定义的变量能够在def内的代码使用,不能在函数的外部应用这样的变量名。
def之中的变量名与def之外的变量名并不冲突,一个在def之外被赋值的变量X与在这个def之中赋值的变量X是完全不同的变量。
>>作用域法则
在开始编写函数之前,我们编写的所有代码都是位于一个模块的顶层(也就是说,并不是嵌套在def之中),所以我们使用的变量名要么是存在于模块文件本身,要么就是Python内置预先定义好的。函数定义本地作用域,而模块定义的全局作用域。这两个作用域有如下关系:

内嵌的模块是全局作用域 每个模块都是一个全局作用域(也就是说,一个创建于模块文件顶层的变量的命名空间)。对于模块外部来说,该模块的全局变量就成为了这个模块对象的属性,但是在这个模块中能够像简单的变量一样使用。
全局作用域的作用范围仅限于单个文件 这里的全局指的是在一个文件的顶层的变量名仅对于这个文件内部的代码而言是全局的。在Python中是没有基于一个单个的、无所不包的情景文件的全局作用域的。
每次对函数的调用都创建了一个新的本地作用域
赋值的变量名除非声明为全局变量或非局部变量,否则均为局部变量
所有的变量名都可以归纳为本地、全局或者内置的
>>变量名解析:LEGB原则
Python的变量名解析机制有时称为LEGB法则,当在函数中使用未认证的变量名时,Python搜索4个作用域:

  • 本地作用域(L)
  • 上一层结构中def或lambda的本地作用域(E)(其实就是函数嵌套的情况)
  • 全局作用域(G)
  • 最后是内置作用域(B)

Python按顺序在上面4个作用域中查找变量,并且在第一个能够找到这个变量名的地方停下来,如果在这4个作用域中都没找到,Python会报错。

这里需要强调的是,上面四个作用域是函数中代码的搜索过程,也就是说,在函数中能直接使用上一层中的变量!

s=10
def times(x,y):
 x=s
 return x*y

times(3,4) #return 40 not 12

>>内置作用域
内置作用域是通过一个名为builtin的标准模块来实现的,但是这个变量名自身并没有放入内置作用域内,所以必须导入这个文件才能够使用它。在Python3.0中,可以使用以下的代码来查看到底预定义了哪些变量:

import builtins
dir(builtins)

因此,事实上有两种方法可以引用一个内置函数:通过LEGB法则带来的好处,或者手动导入builtin模块。其中第二种方法在一些复杂的任务里是很有用的,因为一些局部变量有可能会覆盖内置的变量或函数。再次强调的是,LEGB法则只使它找到的第一处变量名的地方生效!

global语句

global语句是一个命名空间的声明,它告诉Python解释器打算生成一个或多个全局变量,也就是说,存在于整个模块内部作用域(命名空间)的变量名。关于全局变量名:

全局变量是位于模块文件内部顶层的变量名。
全局变量如果是在函数内部被赋值的话,必须经过声明。
全局变量名在函数的内部不经过声明也可以被引用。
global语句包含了关键字global,其后跟着一个或多个由逗号分开的变量名。当在函数主题被赋值或引用时,所有列出来的变量名将被映射到整个模块的作用域内。 举个例子:

X=88
def func():
 global X
 X = 99

func()
print(X) #Prints 99

作用域和嵌套函数

这部分内容是关于LEGB查找法则中E这一层的,它包括了任意嵌套函数内部的本地作用域。嵌套作用域有时也叫做静态嵌套作用域。实际上,嵌套是一个语法上嵌套的作用域,它是对应于程序源代码的物理结构上的嵌套结构。

>>嵌套作用域的细节
对于一个函数来说:

一个引用(X)首先在本地(函数内)作用域查找变量名X;之后会在代码的语法上嵌套了的函数中的本地作用域,从内到外查找;之后查找当前的全局作用域(模块文件);最后在内置作用域内(模块builtin)。全局声明将会直接从全局(模块文件)作用域进行搜索。其实就是从引用X的地方开始,一层一层网上搜索,直到找到的第一个X。
在默认情况下,一个赋值(X=value)创建或修改了变量名X的当前作用域。如果X在函数内部声明为全局变量,它将会创建或改变变量名X为整个模块的作用域。另一方面,如果X在函数内部声明为nonlocal,赋值会修改最近的嵌套函数的本地作用域中的名称X。
>>嵌套作用域举例

X = 99
def f1():
 X = 88
 def f2():
 print(X)
 f2()
f1() #Prints 88:enclosing def local

首先需要说明的是,上面这段代码是合法的,def是一个简单的执行语句,可以出现在任意其他语句能够出现的地方,包括嵌套在另一个def之中。代码中,f2是在f1中定义的函数,在此情况下,f2是一个临时函数,仅在f1内部执行的过程中存在(并且只对f1中的代码可见)。通过LEGB查找法则,f2内的X自动映射到了f1的X。

值得注意的是,这个嵌套作用域查找在嵌套的函数已经返回后也是有效的。

X = 99
def f1():
 X = 88
 def f2():
 print(X) #Remember X in enclosing def scope
 return f2 #Return f2 but don't call it

action = f1() #Make return function
action() #Call it now:Prints 88

上述代码中,不管调用几次action函数,返回值都是88,f2记住了f1中嵌套作用域中的X,尽管此时f1已经不处于激活的状态。

工厂函数

上述这些行为有时叫做闭合(closure)或者工厂函数——一个能够记住嵌套作用域的变量值的函数,即使那个作用域也许已经不存在了。通常来说,使用类来记录状态信息时更好的选择,但是像这样的工厂函数也提供了一种替代方案。 具体的例子:

def maker(N):
 def action(X):
 return X ** N
 return action

f=maker(2) #Pass 2 to N
f(3) #Pass 3 to X,N remembers 2: 3**2,Return 9
f(4) #return 4**2

g=maker(3) #g remembers 3,f remembers 2
g(3) #return 27
f(3) #return 9

从上面代码中可以看到,f和g函数分别记录了不同的N值,也就是记录了不同的状态,每一次对这个工厂函数进行赋值,都会得到一个状态信息的集合,每个函数都有自己的状态信息,由maker中的变量N保持。

作用域与带有循环变量的默认参数相比较

在已给出的法则中有一个值得注意的特例:如果lambda或者def在函数中定义,嵌套在一个循环之中,并且嵌套的函数引用了一个上层作用域的变量,该变量被循环所改变,所有在这个循环中产生的函数都将会有相同的值——在最后一次循环中完成时被引用变量的值。具体的例子:

def makeActions():
 acts=[]
 for i in range(5): #Tries to remember each i
 acts.append(lambda x: i ** x) #All remember same last it
 return acts

尽管是在尝试创建一个函数列表,使得每个函数拥有不同的状态值,但是事实上,这个列表中的函数的状态值都是一样的,是4。因为嵌套作用域中的变量在嵌套的函数被调用时才进行查找,所以它们实际上记住的是同样的值(在最后一次循环迭代中循环变量的值)。

为了能让这类代码能够工作,必须使用默认参数把当前的值传递给嵌套作用域的变量。因为默认参数是在嵌套函数创建时评估的(而不是在其稍后调用时),每一个函数记住了自己的变量i的值。

def makeActions():
 acts=[]
 for i in range(5): #Use default instead
 acts.append(lambda x,i=i: i ** x) #Remember current i
 return acts
{

nonlocal语句

事实上,在Python3.0中,我们也可以修改嵌套作用域变量,只要我们在一条nonlocal语句中声明它们。使用这条语句,嵌套的def可以对嵌套函数中的名称进行读取和写入访问。nonlocal应用于一个嵌套的函数的作用域中的一个名称,而不是所有def之外的全局模块作用域——它们可能只存在于一个嵌套的函数中,并且不能由一个嵌套的def中第一次赋值创建。

换句话说,nonlocal即允许对嵌套的函数作用域中的名称变量赋值,并且把这样的名称作用域查找限制在嵌套的def。

>>nonlocal基础

def func():
 nonlocal name1,name2...

这条语句允许一个嵌套函数来修改在一个语法嵌套函数的作用域中定义的一个或多个名称。在Python 2.X中,当一个函数def嵌套在另一个函数中,嵌套的函数可以引用上一层函数中定义的各种变量,但是不能修改它们。在Python3.0中,在一条nonlocal语句中声明嵌套的作用域,使得嵌套的函数能够赋值,并且由此也能够修改这样的名称。

除了允许修改嵌套的def中的名称,nonlocal语句还加快了引用——就像global语句一样,nonlocal使得对该语句中列出的名称的查找从嵌套的def的作用域中开始,而不是从声明函数的本地作用域开始,也就是说,nonlocal也意味着”完全略过我的本地作用域”。

实际上,当执行到nonlocal语句的时候,nonlocal中列出的名称必须在一个嵌套的def中提前定义过,否则,将会产生一个错误。直接效果和global很相似:global意味着名称位于上一层的模块中,nonlocal意味着它们位于一个上一层的def函数中。nonlocal甚至更加严格——作用域查找只限定在嵌套的def。也就是说,nonlocal只能出现在嵌套的def中,而不能在模块的全局作用域中或def之外的内置作用域中。

当在一个函数中使用的时候,global和nonlocal语句都在某种程度上限制了查找规则:

global使得作用域查找从嵌套的模块的作用域开始,并且允许对那里的名称赋值。如果名称不存在与该模块中,作用域查找继续到内置作用域,但是,对全局名称的赋值总是在模块作用域中创建或修改它们。
nonlocal限制作用域查找只是嵌套的def,要求名称已经存在于那里,并且允许对它们赋值。作用域查找不会继续到全局或内置作用域。
>>nonlocal应用
使用nonlocal进行修改

def tester(start):
 state = start #each call gets its own state
 def nested(label):
 nonlocal state #remember state in enclosing scope
 print(label,state)
 state+=1 #Allowed to change it if onolocal
 return nested

F = tester(0) #Increments state on each call
F('spam') #Prints:spam 0
F('ham') #Prints:ham 1
F('eggs') #Prints:eggs 2

边界情况

当执行一条nonlocal语句时,nonlocal名称必须已经在一个嵌套的def作用域中赋值过,否则将会得到一个错误。
nonlocal限制作用域查找仅为嵌套的def,nonlocal不会在嵌套的模块的全局作用域或所有def之外的内置作用域中查找。

时间: 2016-03-19

Python作用域用法实例详解

本文实例分析了Python作用域用法.分享给大家供大家参考,具体如下: 每一个编程语言都有变量的作用域的概念,Python也不例外,以下是Python作用域的代码演示: def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): nonlocal spam spam = "nonlocal spam" def do_global(): global spam spam = &quo

解读Python编程中的命名空间与作用域

变量是拥有匹配对象的名字(标识符).命名空间是一个包含了变量名称们(键)和它们各自相应的对象们(值)的字典. 一个Python表达式可以访问局部命名空间和全局命名空间里的变量.如果一个局部变量和一个全局变量重名,则局部变量会覆盖全局变量. 每个函数都有自己的命名空间.类的方法的作用域规则和通常函数的一样. Python会智能地猜测一个变量是局部的还是全局的,它假设任何在函数内赋值的变量都是局部的. 因此,如果要给全局变量在一个函数里赋值,必须使用global语句. global VarName的

Python中的作用域规则详解

Python是静态作用域语言,尽管它自身是一个动态语言.也就是说,在Python中变量的作用域是由它在源代码中的位置决定的,这与C有些相似,但是Python与C在作用域方面的差异还是非常明显的. 接下来会谈论Python的作用域规则,在这中间也会说明一下Python与C在作用域方面的不同. 在Python 2.0及之前的版本中,Python只支持3种作用域,即局部作用域,全局作用域,内置作用域:在Python 2.2中,Python正式引入了一种新的作用域 --- 嵌套作用域:在Python 2

从局部变量和全局变量开始全面解析Python中变量的作用域

理解全局变量和局部变量 1.定义的函数内部的变量名如果是第一次出现, 且在=符号前,那么就可以认为是被定义为局部变量.在这种情况下,不论全局变量中是否用到该变量名,函数中使用的都是局部变量.例如: num = 100 def func(): num = 123 print num func() 输出结果是123.说明函数中定义的变量名num是一个局部变量,覆盖全局变量.再例如: num = 100 def func(): num += 100 print num func() 输出结果是:Unb

解析Python中的变量、引用、拷贝和作用域的问题

在Python中,变量是没有类型的,这和以往看到的大部分编辑语言都不一样.在使用变量的时候,不需要提前声明,只需要给这个变量赋值即可.但是,当用变量的时候,必须要给这个变量赋值:如果只写一个变量,而没有赋值,那么Python认为这个变量没有定义.如下: >>> a Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a'

Python新手在作用域方面经常容易碰到的问题

通常,当我们定义了一个全局变量(好吧,我这样说是因为讲解的需要--全局变量是不好的),我们用一个函数访问它们是能被Python理解的: bar = 42 def foo(): print bar 在这里,我们在foo函数里使用了全局变量bar,然后它也如预想的能够正常运行: >>> foo() 42 这样做很酷.通常,我们在使用了这个特性之后就想在所有的代码里用上它.如果像以下的例子中使用的话还是能够正常运行的: bar = [42] def foo(): bar.append(0) f

讲解python参数和作用域的使用

本文会介绍如何将语句组织成函数,还会详细介绍参数和作用域的概念,以及递归的概念及其在程序中的用途.一. 创建函数函数是可以调用,它执行某种行为并且返回一个值.用def语句即可定义一个函数:(并非所有的函数都会返回一些东西) 复制代码 代码如下: def fibs(num):    result = [0,1]    for i in range(num-2):        result.append(result[-2]+result[-1])    return result 记录函数如果想

优化Python代码使其加快作用域内的查找

我将示范微优化(micro optimization)如何提升python代码5%的执行速度.5%!同时也会触怒任何维护你代码的人. 但实际上,这篇文章只是解释一下你偶尔会在标准库或者其他人的代码中碰到的代码.我们先看一个标准库的例子,collections.OrderedDict类: def __setitem__(self, key, value, dict_setitem=dict.__setitem__): if key not in self: root = self.__root l

讲解Python中for循环下的索引变量的作用域

我们从一个测试开始.下面这个函数的功能是什么? def foo(lst): a = 0 for i in lst: a += i b = 1 for t in lst: b *= i return a, b 如果你觉得它的功能是"计算lst中所有元素的和与积",不要沮丧.通常很难发现这里的错误.如果在大堆真实的代码中发现了这个错误就非常厉害了.--当你不知道这是一个测试时,很难发现这个错误. 这里的错误是在第二个循环体中使用了i而不是t.等下,这到底是怎么工作的?i在第一个循环外应该是

通过5个知识点轻松搞定Python的作用域

1.块级作用域 想想此时运行下面的程序会有输出吗?执行会成功吗? #块级作用域 if 1 == 1: name = "lzl" print(name) for i in range(10): age = i print(age) 我们先看下执行结果 C:/Users/L/PycharmProjects/s14/preview/Day8/作用域/main.py lzl 9 Process finished with exit code 0 代码执行成功,没有问题:在Java/C#中,执行

JavaScript 一行代码,轻松搞定浮动快捷留言-V2升级版

前天熬了大半宿发了一篇[一行代码轻松搞定快捷留言功能],同时发布了V1.0beta版的快捷留言功能和源代码,之所以是beta版,就是当时感觉虽然基本功能有了,但是还不够完善,特性也不一定合理,今天不知不觉又弄到了这个时候,这次对上一版做了很大改进: 首先,原来自动提交留言信息的同时会自动推荐,大量的推荐数,直接影响了博客园的推荐排名机制,所以后来在第一时间修改成了询问是否要推荐的交互模式! 其次,虽然快捷功能有了,并且很好用,但是满屏幕的"好贴!我顶你!"也确实有些审美疲劳了,并且没什

网站被恶意镜像怎么办 php一段代码轻松搞定(全面版)

有时候你会发现,你在搜索引擎输入网站名称的时候,出来的网站信息是你们的,但是域名却是一个陌生的,这种情况可以基本确定网站被镜像了,那么究竟什么叫网站被镜像? 恶意镜像,也叫恶意克隆,恶意解析,是指有人通过域名 A 记录直接解析别人 IP 地址,从而得到一个在访问者眼中完全相同网站的过程.其工作原理基本上是这样子的:有用户访问镜像站点时,程序就会来正版的站点查询数据,并修改相关链接然后呈献给用户,实质上还是在读取原站的数据.严谨一点的解释:通过复制整个网站或部分网页内容并分配以不同域名和服务器,以

1个文件如何轻松搞定Asp.net core 3.1动态页面转静态页面

前言 最近一个Asp.net core项目需要静态化页面,百度查找了一下,没有发现合适的.原因如下 配置麻烦. 类库引用了第三方类,修改起来麻烦. 有只支持MVC,不支持PageModel. 继承ActionFilterAttribute类,只重写了OnActionExecutionAsync,看似静态化了,其实运行时该查数据库还是查数据库,没有真正静态化. 缺少灵活性,没有在线更新静态文件方法,不能测试查看实时页面,没有进行Html压缩,没有使用gzip.br压缩文件. 于是我开始了页面静态化

轻松搞定iOS远程消息推送

一.引言 IOS中消息的推送有两种方式,分别是本地推送和远程推送,本地推送在http://www.jb51.net/article/93602.htm这篇博客中有详细的介绍,这里主要讨论远程推送的流程与配置过程. 二.远程推送机制的原理 1.从一张很火的图说起 搜索IOS远程推送,你总能看到一张如下的流程示意图,因为这张图确实很火,所以我也将它引用在此: 这张图示意的很清晰,大致意思是这样:你的应用服务端将消息发送到apple的APNS服务器,APNS服务器将消息推送到指定的Iphone,最后由

要用最新驱动 四步就可以轻松搞定

不同设备.同一设备的不同型号,还有不同的操作系统所对应的驱动程序是不同的,即使是同一个驱动程序也有多个不同版本.一旦为硬件安装了错误的驱动程序,后果可想而知.因此,安全.及时地更新驱动相对来说还是有一定难度的.现在,有了"驱动精灵2004",可以很快帮助我们搞定,让我们的硬件驱动永远保持最新!驱动更新不用愁,我有精灵做帮手. 第一步:查找/下载更新驱动 先下载.安装并启动"驱动精灵2004",该软件会自动搜集系统中硬件的驱动信息,并联机到服务器检查有无相关硬件的驱动

JavaScript 轻松搞定快捷留言功能 只需一行代码

别急,方法非常简单,还是先听我说说它的来历吧... 最开始,快捷留言这个功能要追溯到发表[AjaxControlToolkitTests自动测试框架完全解析之一:架构篇]这篇文章的时候,当时它纯粹是那篇文章的副产品,本来没太在意,本想只是给像我一样的懒人准备的一条捷径而已,后来因为没有提示这个功能会直接自动提交留言,还引起了几枚同学的不满意,于是后来又在醒目位置加上了提示:[提示:快捷链接会直接推荐并提交留言信息.],才平息了局势: 再后来,有部分同学可能是鼠标太高级,连击速度特别快的原因,每次

一篇文章搞定Python操作文件与目录

前言 文件和目录操作是很常见的功能,这里做个简单的总结,包括注意事项和实际的实现代码,基本日常开发都够用了 目录操作 判断目录或是文件是否存在 os.path.exists(path) 判断是否是文件或是目录 # 如果文件或是目录不存在也会返回False os.path.isfile(path) os.path.isdir(path) 创建/删除目录 os.mkdir(path) os.rmdir(path) 得到当前的目录名称 os.path.split(dir_path)[1] 这个方法既简

一键搞定python连接mysql驱动有关问题(windows版本)

对于mysql驱动问题折腾了一下午,现共享出解决方案 1:手动安装驱动 完全是场噩梦,推荐大家采用自动安装 2:自动安装 下载自动安装包,下载地址:http://www.jb51.net/softs/73369.html 双击安装!安装完成后.已能正常对数据库操作 eg: import mysqldb con=mysqldb.connect(host='localhost',user='root',passwd='root',db='test') cursor = con.cursor() sq

轻松搞定jQuery.noConflict()

jQuery是目前使用最广泛的前端框架之一,有大量的第三方库和插件基于它开发.为了避免全局命名空间污染,jQuery提供了jQuery.noConflict()方法解决变量冲突.这个方法,毫无疑问,非常有效.遗憾的是,jQuery的官方文档对该方法的描述不够清晰,许多开发者并不清楚当他们调用jQuery.noConflict()时,究竟发生了什么,从而导致在使用时出现了许多问题.尽管如此,jQuery.noConflict()背后实现原理依然值得Web开发者学习掌握,成为解决类似全局命名空间污染