python基础之知识补充-作用域、特殊语法


python作用域

无函数的作用域

在python中没有块级作用域
什么叫块级作用域呢?先来看个例子:

if 1 == 1:
    name= 'alex'
print(name)

运行结果为alex
在javascript、python中运行结果为alex,但是在java和C#中,会抛出异常:没有name的变量

for i in range(10):
    name=i
print(name)

结果也是9
为什么会出现这种情况呢,归根结底就是因为块级作用域
在python中,一个tab或者空格缩进,表示一个代码块

  • 在有块级作用域的语言中,比如java/c#,代码中的name只在当前作用域下生效。
  • 在没有块级作用域的语言中,比如python/javascript中,代码中的name变量,不仅在代码块中生效,在代码块外面也一样生效

python中以函数为作用域

再来看一下这个:

def fun():
    name ='alex'
fun()
print(name)

在函数的作用域中,变量无法生效的。

总结1

所以我们可以总结一下:python中是以函数作为作用域的,并且python中无块级作用域

python中的作用域链

python中有作用域链,对于变量的查找方式是由内向外查找的,当前作用域中有,使用当前变量设置,如果没有,往上查找,知道找到最后找不到而报错。

看个例子能更为直观些:

name='cc'
def f1():
    name='alex'
    def f2():
        name='bb'
        print(name)
    f2()
f1()

输出:

bb

按照上面所述,查找name的方式就是从f2函数中查找,如果有就是bb,如果没有,就是f1中的alex,如果还没有就是cc,如果最外面的全局变量中也没有,那么程序必然会报错。

python/javascript中作用域与函数的关系

对于作用域来说,在函数没有执行之前,他的作用域、作用域链均已经确定。
看下例子:

name = 'alex'
def f1():   #作用域1
    print(name)  
###################
def f2():   #作用域2
    name='cc'
    f1()
f2()
name = 'alex'
def f1():   #作用域1
    print(name)
######################
def f2():   #作用域2
    name = 'cc'
    return f1
ret = f2()
ret()

上面两个输出均为alex
说下原因吧:我们已经知道了,python中是以函数为作用域的,在作用域1中,作用域会直接用使用全局变量name='alex',但在作用域2中,虽然有一个局部变量name,但在程序最终执行之前,python已经从上到下把作用域和作用域链确定了,就是f1()的执行结果肯定是alex,不受其他因素的影响。

python中的特殊语法

直接上例子吧,据说是一个新浪面试题:

li=[x+100 for x in range(10)]   #在0-9循环,并且每次循环+100
print(li)
lis=[x+100 for x in range(10) if x > 6]     #只有x>6时,x+100
print(lis)

li1=[lambda: x for x in range(10)] #首先li是一个列表,列表中的元素都是函数
print(li1)
# print(type(li1))
r=li1[0]()      #函数加括号执行lambda表达式
print(r)        #最后x为9,所以每个元素都是return 9

输出结果:

[100, 101, 102, 103, 104, 105, 106, 107, 108, 109]
[107, 108, 109]
[<function <listcomp>.<lambda> at 0x0000019EC393D598>, <function <listcomp>.<lambda> at 0x0000019EC393D620>, <function <listcomp>.<lambda> at 0x0000019EC393D6A8>, <function <listcomp>.<lambda> at 0x0000019EC393D730>, <function <listcomp>.<lambda> at 0x0000019EC393D7B8>, <function <listcomp>.<lambda> at 0x0000019EC393D840>, <function <listcomp>.<lambda> at 0x0000019EC393D8C8>, <function <listcomp>.<lambda> at 0x0000019EC393D950>, <function <listcomp>.<lambda> at 0x0000019EC393D9D8>, <function <listcomp>.<lambda> at 0x0000019EC393DA60>]
9

Python中:函数在没执行前,内部代码不执行。
所以,我们在看li1=[lambda: x for x in range(10)],这行代码中,lambda:x是一个函数,函数内部x只是一个x变量,不会被赋值,而for x in range(10)的执行结果都是9;所以内部是10个lambda函数,而函数可以认为是lambda : x,但这个x其实已经赋予9的值了,但因为没有执行,暂时是x,加括号后就直接返回9.
其实把他拆开,我们可以这么写一行:

li = []
for i in range(10)
    def f1():
        return i
    li.append(f1)
print(li[1]())

首先for 循环已完成,i已经赋予9,然后f1()执行时,按照作用域链查找,i=9,那么返回就是9了。
那么:

li = []
for i in range(10)
    def f1(x=i):
        return x
    li.append(f1)
print(li[0]())
print(li[1]())
print(li[2]())

输出是

0
1
2

为什么呢,因为x=i是一个表达式,表达式是执行了函数。所以还是要看他的本质,要看函数是否被执行

总结

总结下这篇的重要的三句话吧:

  • python中是以函数作为作用域的,并且python中无块级作用域
  • 对于作用域来说,在函数没有执行之前,他的作用域、作用域链均已经确定。,并且:对于变量的查找方式是由内向外查找的,当前作用域中有,使用当前变量设置,如果没有,往上查找,知道找到最后找不到而报错。
  • 函数在没执行前,内部代码不执行。在碰到lambda时候需要注意!!!

python 3 和2.7 class 类多继承时的区别

在python2.7中,类默认不继承object类,叫经典类;继承object类,叫新式类
在python3中,如果按照2.7中的规则,所有的类都算新式类

多继承并且有共同父类的情况下:

  • 经典类,一条道走到黑,然后再从第二个继承类中找
  • 新式类,查找的最后的终点是共同父类,所以在查找途中如果遇到共同父类,会返回创建对象类下一个父类类中,知道走到最后共同类。
原文地址:https://www.cnblogs.com/ccorz/p/5662163.html