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])

 

posted @ 2016-07-23 17:16  龙哥1995xyabc  阅读(157)  评论(0编辑  收藏  举报