Question: If I am correct, `with` statement doesn't introduce a local scope for the `with` statement.

These are examples from Learning Python:

```
with open(r'C:\misc\data') as myfile:
    for line in myfile:
        print(line)
        ...more code here...

```

and

```
lock = threading.Lock()                        # After: import threading
with lock:
    # critical section of code
    ...access shared resources...

```

Is the second example equivalent to the following rewritten in a way similar to the first example?

```
with threading.Lock() as lock:
    # critical section of code
    ...access shared resources...

```

What are their differences?

Is the first example equivalent to the following rewritten in a way similar to the second example?

```
myfile = open(r'C:\misc\data')
with myfile:
    for line in myfile:
        print(line)
        ...more code here...

```

What are their differences?

Answer: 
When `with` enters a context, it calls a hook on the context manager object, called `__enter__`, and the return value of that hook can optionally be assigned to a name using `as <name>`. Many context managers return `self` from their `__enter__` hook. If they do, then you can indeed take your pick between creating the context manager on a separate line or capturing the object with `as`.

Out of your two examples, only the file object returned from `open()` has an `__enter__` hook that returns `self`. For `threading.Lock()`, `__enter__` returns the same value as [`Lock.acquire()`](https://docs.python.org/3/library/threading.html#threading.Lock.acquire), so a *boolean*, not the lock object itself.

You'll need to look for explicit documentation that confirms this; this is not always that clear however. For `Lock` objects, the [relevant section of the documentation](https://docs.python.org/3/library/threading.html#using-locks-conditions-and-semaphores-in-the-with-statement) states:

> 
> All of the objects provided by this module that have `acquire()` and `release()` methods can be used as context managers for a `with` statement. **The `acquire()` method will be called when the block is entered**, and release() will be called when the block is exited.
> 
> 
> 

and for file objects, the [`IOBase` documentation](https://docs.python.org/3/library/io.html#io.IOBase) is rather on the vague side and you have to infer from the example that the file object is returned.

The main thing to take away is that *returning `self` is not mandatory*, nor is it always desired. Context managers are entirely free to return something else. For example, many database connection objects are context managers that let you manage the transaction (roll back or commit automatically, depending on whether or not there was an exception), where entering returns a new cursor object bound to the connection.

To be explicit:

* for your `open()` example, the two examples are for all intents and purposes exactly the same. Both call `open()`, and if that does not raise an exception, you end up with a reference to that file object named `myfile`. In both cases the file object will be closed after the `with` statement is done. The name continues to exist after the `with` statement is done.

There is a difference, but it is mostly technical. For `with open(...) as myfile:`, the file object is created, has it's `__enter__` method called and then `myfile` is bound. For the `myfile = open(...)` case, `myfile` is bound first, `__enter__` called later.
* For your `with threading.Lock() as lock:` example, using `as lock` will set `lock` to a `True` (locking always either succeeds or blocks indefinitely this way). This differs from the `lock = threading.Lock()` case, where `lock` is bound to the lock object.
[Here's a good explanation](http://effbot.org/zone/python-with-statement.htm). I'll paraphrase the key part:

> 
> The `with` statement could be thought of like this code:
> 
> 
> 
> ```
> set things up
> try:
>     do something
> finally:
>     tear things down
> 
> ```
> 
> Here, “set things up” could be opening a file, or acquiring some sort of external resource, and “tear things down” would then be closing the file, or releasing or removing the resource. The try-finally construct guarantees that the “tear things down” part is always executed, even if the code that does the work doesn’t finish.
> 
> 
>