• python与js杂谈


    首先我们说说对于with关键字的理解

    有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。

    1 with open("/tmp/foo.txt")
    2  as file:
    3     data = file.read()

    那with是如何工作的呢

    这看起来充满魔法,但不仅仅是魔法,Python对with的处理还很聪明。基本思想是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法。

    紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法。

    下面例子可以具体说明with如何工作:

     1 #!/usr/bin/env
     2  python
     3 #
     4  with_example01.py
     5  
     6  
     7 class Sample:
     8     def __enter__(self):
     9         print "In
    10  __enter__()"
    11         return "Foo"
    12  
    13     def __exit__(self, type,
    14  value, trace):
    15         print "In
    16  __exit__()"
    17  
    18  
    19 def get_sample():
    20     return Sample()
    21  
    22  
    23 with
    24  get_sample() as sample:
    25     print "sample:",
    26  sample
    View Code

    When executed, this will result in: 运行代码,输出如下

    1 bash-3.2$
    2  ./with_example01.py
    3 In
    4  __enter__()
    5 sample:
    6  Foo
    7 In
    8  __exit__()

    正如你看到的, 1. __enter__()方法被执行 2. __enter__()方法返回的值 - 这个例子中是"Foo",赋值给变量'sample' 3. 执行代码块,打印变量"sample"的值为 "Foo" 4. __exit__()方法被调用 with真正强大之处是它可以处理异常。可能你已经注意到Sample类的__exit__方法有三个参数- val, type 和 trace。 这些参数在异常处理中相当有用。我们来改一下代码,看看具体如何工作的。

     1 #!/usr/bin/env
     2  python
     3 #
     4  with_example02.py
     5  
     6  
     7 class Sample:
     8     def __enter__(self):
     9         return self
    10  
    11     def __exit__(self, type,
    12  value, trace):
    13         print "type:", type
    14         print "value:",
    15  value
    16         print "trace:",
    17  trace
    18  
    19     def do_something(self):
    20         bar = 1/0
    21         return bar + 10
    22  
    23 with
    24  Sample() as sample:
    25     sample.do_something()
    View Code

    这个例子中,with后面的get_sample()变成了Sample()。这没有任何关系,只要紧跟with后面的语句所返回的对象有__enter__()和__exit__()方法即可。此例中,Sample()的__enter__()方法返回新创建的Sample对象,并赋值给变量sample。

    代码执行后:

     1 bash-3.2$
     2  ./with_example02.py
     3 type:
     4  <type 'exceptions.ZeroDivisionError'>
     5 value:
     6  integer division or modulo
     7  by zero
     8 trace:
     9  <traceback object at 0x1004a8128>
    10 Traceback
    11  (most recent call last):
    12   File "./with_example02.py",
    13  line 19, in <module>
    14     sample.do_something()
    15   File "./with_example02.py",
    16  line 15, in do_something
    17     bar = 1/0
    18 ZeroDivisionError:
    19  integer division or modulo
    20  by zero
    View Code

    实际上,在with后面的代码块抛出任何异常时,__exit__()方法被执行。正如例子所示,异常抛出时,与之关联的type,value和stack trace传给__exit__()方法,因此抛出的ZeroDivisionError异常被打印出来了。开发库时,清理资源,关闭文件等等操作,都可以放在__exit__方法当中。

    因此,Python的with语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。

    with知识点

      这里要介绍一个知识点。我们在做上下文管理的时候,用到过with。

      我们如何自定义一个with方法呢?

    这是老师上课时所说的上下文管理装饰器

     1    @contextlib.contextmanager
     2     def worker_state(self, state_list, worker_thread):
     3         """
     4         用于记录线程中正在等待的线程数
     5         """
     6         state_list.append(worker_thread)
     7         try:
     8             yield
     9         finally:
    10             state_list.remove(worker_thread)
    11  with self.worker_state(self.free_list, current_thread):
    12                 event = self.q.get()
    View Code

    JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走遍天下都不怕...

    一、“JavaScript中无块级作用域”

    在Java或C#中存在块级作用域,即:大括号也是一个作用域。

     1 public static void main ()
     2 {
     3     if(1==1){
     4         String name = "seven";
     5     }
     6     System.out.println(name);
     7 }
     8 // 报错
     9 
    10 Java
    java
     1 public static void Main()
     2 {
     3     if(1==1){
     4         string name = "seven";
     5     }
     6     Console.WriteLine(name);
     7 }
     8 // 报错
     9 
    10 C#
    c#

    在JavaScript语言中无块级作用域

    1 function Main(){
    2     if(1==1){
    3         var name = 'seven';
    4     }
    5     console.log(name);
    6 }
    7 // 输出: seven
    View Code

    补充:标题之所以添加双引号是因为JavaScript6中新引入了 let 关键字,用于指定变量属于块级作用域。

    二、JavaScript采用函数作用域

    在JavaScript中每个函数作为一个作用域,在外部无法访问内部作用域中的变量。

    1 function Main(){
    2     var innerValue = 'seven';
    3 }
    4  
    5 Main();
    6  
    7 console.log(innerValue);
    8  
    9 // 报错:Uncaught ReferenceError: innerValue is not defined
    View Code

    三、JavaScript的作用域链

    由于JavaScript中的每个函数作为一个作用域,如果出现函数嵌套函数,则就会出现作用域链。

     1 xo = 'alex';
     2   
     3 function Func(){
     4     var xo = "seven";
     5     function inner(){
     6         var xo = 'alvin';
     7         console.log(xo);
     8     }
     9     inner();
    10 }
    11 Func();
    View Code

    如上述代码则出现三个作用域组成的作用域链,如果出现作用域链后,那么寻找变量时候就会出现顺序,对于上述实例:

    当执行console.log(xo)时,其寻找顺序为根据作用域链从内到外的优先级寻找,如果内层没有就逐步向上找,直到没找到抛出异常。

    四、JavaScript的作用域链执行前已创建

    JavaScript的作用域在被执行之前已经创建,日后再去执行时只需要按照作用域链去寻找即可。

    示例一:

     1 xo = 'alex';
     2  
     3 function Func(){
     4     var xo = "seven";
     5     function inner(){
     6  
     7         console.log(xo);
     8     }
     9     return inner;
    10 }
    11  
    12 var ret = Func();
    13 ret();
    14 // 输出结果: seven
    View Code

    上述代码,在函数被调用之前作用域链已经存在:

    • 全局作用域 -> Func函数作用域 -> inner函数作用域

    当执行【ret();】时,由于其代指的是inner函数,此函数的作用域链在执行之前已经被定义为:全局作用域 -> Func函数作用域 -> inner函数作用域,所以,在执行【ret();】时,会根据已经存在的作用域链去寻找变量。

    示例二:

     1 xo = 'alex';
     2  
     3 function Func(){
     4     var xo = "eirc";
     5     function inner(){
     6  
     7         console.log(xo);
     8     }
     9     xo = 'seven';
    10     return inner;
    11 }
    12  
    13 var ret = Func();
    14 ret();
    15 // 输出结果: seven
    View Code

    上述代码和示例一的目的相同,也是强调在函数被调用之前作用域链已经存在:

    • 全局作用域 -> Func函数作用域 -> inner函数作用域

    不同的时,在执行【var ret = Func();】时,Func作用域中的xo变量的值已经由 “eric” 被重置为 “seven”,所以之后再执行【ret();】时,就只能找到“seven”。

    示例三:

     1 xo = 'alex';<br>
     2 function Bar(){
     3     console.log(xo);
     4 }
     5  
     6 function Func(){
     7     var xo = "seven";
     8      
     9     return Bar;
    10 }
    11  
    12 var ret = Func();
    13 ret();
    14 // 输出结果: alex
    View Code

    上述代码,在函数被执行之前已经创建了两条作用域链:

    • 全局作用域 -> Bar函数作用域
    • 全局作用域 -> Func函数作用域

    当执行【ret();】时,ret代指的Bar函数,而Bar函数的作用域链已经存在:全局作用域 -> Bar函数作用域,所以,执行时会根据已经存在的作用域链去寻找。

    五、声明提前

    在JavaScript中如果不创建变量,直接去使用,则报错:

     1 console.log(xxoo); 2 // 报错:Uncaught ReferenceError: xxoo is not defined 

    JavaScript中如果创建值而不赋值,则该值为 undefined,如:

    1 var xxoo;
    2 console.log(xxoo);
    3 // 输出:undefined

    在函数内如果这么写:

    1 function Foo(){
    2     console.log(xo);
    3     var xo = 'seven';
    4 }
    5  
    6 Foo();
    7 // 输出:undefined

    上述代码,不报错而是输出 undefined,其原因是:JavaScript的函数在被执行之前,会将其中的变量全部声明,而不赋值。所以,相当于上述实例中,函数在“预编译”时,已经执行了var xo;所以上述代码中输出的是undefined。

    Python也是以函数作为作用域的

    Li=[lambda:x for x in range(9)]

    Print(li[0],li[1]) #这里的li[0],li[1],都是一个个lambda函数,这些函数都是return 一个x,而这些x它本身没有所以要去for里面去寻找,根据像js一样的作用域一样的看法可以知道for执行完之后i都变成8了,所以这个li[0]=li[1]=8

    1 li =[]
    2 For I in range(9):
    3    Def f1(): #lambda:x等同于
    4        Return i
    5    li.append(f1)
    6 print(i)

    print(li)

    print(li[0],li[1])

  • 相关阅读:
    shell脚本学习
    docker容器的安装与使用
    admin源码分析
    ajax提交文件,django测试脚本环境书写,froms组件,钩子函数
    javascript语法 1.运算符 2. 流程控制 3. 函数 4. 四种变量 5. 数据类型的运用 6. js页面交互
    from提交数据,高级选择器,伪类选择器,前端样式等
    前端HTML介绍,标签介绍,基础选择器,CSS引入方法
    数据库知识总结
    day46
    day45
  • 原文地址:https://www.cnblogs.com/237325670qqcom/p/5699122.html
Copyright © 2020-2023  润新知