• 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中的规则,所有的类都算新式类

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

    • 经典类,一条道走到黑,然后再从第二个继承类中找
    • 新式类,查找的最后的终点是共同父类,所以在查找途中如果遇到共同父类,会返回创建对象类下一个父类类中,知道走到最后共同类。
  • 相关阅读:
    C#字符串常见处理
    应用各种领域逻辑模式组织业务逻辑层
    谈谈C#的异常处理机制
    android适配器Adapter
    Struts+Tomcat搭建
    Android特性与系统架构
    常用控件应用之文本框(TextView)特效
    Activity中与ListActivity中使用listview区别
    Android四大基本组件介绍与生命周期
    ftp原理
  • 原文地址:https://www.cnblogs.com/ccorz/p/5662163.html
Copyright © 2020-2023  润新知