浅谈with语句

上下文管理器

要使用 with 语句,首先要明白上下文管理器这一概念。有了上下文管理器,with 语句才能工作。

上下文管理协议(Context Management Protocol)
包含方法 enter() 和 exit(),支持该协议的对象要实现这两个方法。

上下文管理器(Context Manager)
支持上下文管理协议的对象,这种对象实现了enter() 和 exit() 方法。上下文管理器定义执行 with 语句时要建立的运行时上下文,负责执行 with 语句块上下文中的进入与退出操作。通常使用 with 语句调用上下文管理器,也可以通过直接调用其方法来使用。

运行时上下文(runtime context)
由上下文管理器创建,通过上下文管理器的 enter() 和exit() 方法实现,enter() 方法在语句体执行之前进入运行时上下文,exit() 在语句体执行完后从运行时上下文退出。with 语句支持运行时上下文这一概念。

上下文表达式(Context Expression)
with 语句中跟在关键字 with 之后的表达式,该表达式要返回一个上下文管理器对象。

语句体(with-body)
with 语句包裹起来的代码块,在执行语句体之前会调用上下文管理器的 enter() 方法,执行完语句体之后会执行 exit() 方法。

context_manager._enter_()
进入上下文管理器的运行时上下文,在语句体执行前调用。with 语句将该方法的返回值赋值给 as 子句中的 target,如果指定了 as 子句的话。

context_manager._exit_(exc_type, exc_value, exc_traceback)
退出与上下文管理器相关的运行时上下文,返回一个布尔值表示是否对发生的异常进行处理。参数表示引起退出操作的异常,如果退出时没有发生异常,则3个参数都为None。如果发生异常,返回True 表示不处理异常,否则会在退出该方法后重新抛出异常以由 with 语句之外的代码逻辑进行处理。如果该方法内部产生异常,则会取代由 statement-body 中语句产生的异常。要处理异常时,不要显示重新抛出异常,即不能重新抛出通过参数传递进来的异常,只需要将返回值设置为 False 就可以了。之后,上下文管理代码会检测是否 exit() 失败来处理异常。

基本语法

with 语句的语法格式

with context_expression [as target(s)]:
    with-body

这里 context_expression 要返回一个上下文管理器对象,该对象并不赋值给 as 子句中的 target(s) ,如果指定了 as 子句的话,会将上下文管理器的 enter() 方法的返回值赋值给 target(s)。target(s) 可以是单个变量,或者由“()”括起来的元组(不能是仅仅由“,”分隔的变量列表,必须加“()”)。

使用 with 语句操作文件对象
Python 对一些内建对象进行改进,加入了对上下文管理器的支持,可以用于 with 语句中,比如可以自动关闭文件、线程锁的自动获取和释放等。假设要对一个文件进行操作,使用 with 语句可以有如下代码:

with open(r'somefileName') as somefile:
    for line in somefile:
        print line
        # ...more code

这里使用了 with 语句,不管在处理文件过程中是否发生异常,都能保证 with 语句执行完毕后已经关闭了打开的文件句柄。

try/finally 方式操作文件对象
如果使用传统的 try/finally 范式,则要使用类似如下代码:

    somefile = open(r'somefileName')
    try:
        for line in somefile:
            print line
            # ...more code
    finally:
        somefile.close()

with 语句执行过程

context_manager = context_expression
exit = type(context_manager).__exit__
value = type(context_manager).__enter__(context_manager)

try:exc = True   #//True 表示正常执行,即便有异常也忽略;False 表示重新抛出异常,需要对异常进行处理

    try:
        target = value  #//如果使用了as子句
        with-body       #//执行with-body
    except:
        #//执行过程中有异常发生
        exc = False
        #//如果__exit__ 返回True,则异常被忽略;如果返回False,则重新抛出异常
        #//由外层代码对异常进行处理
        if not exit(context_manager, *sys.exc_info()):
            raise
finally:
    #//正常退出,或者通过statement-body中的 break/continue/return 语句退出
    #//或者忽略异常退出
    if exc:
        exit(context_manager, None, None, None) 
    #//缺省返回None,None在布尔上下文中看做是False

1.执行 context_expression,生成上下文管理器 context_manager

2.调用上下文管理器的 enter() 方法;如果使用了 as 子句,则将 enter() 方法的返回值赋值给 as 子句中的 target(s)

3.执行语句体 with-body

4.不管是否执行过程中是否发生了异常,执行上下文管理器的 exit() 方法,exit() 方法负责执行“清理”工作,如释放资源等。如果执行过程中没有出现异常,或者语句体中执行了语句 break/continue/return,则以 None 作为参数调用 exit(None, None, None) ;如果执行过程中出现异常,则使用 sys.exc_info 得到的异常信息为参数调用 exit(exc_type, exc_value, exc_traceback)

5.出现异常时,如果 exit(type, value, traceback) 返回 False,则会重新抛出异常,让with 之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对异常进行处理

<think>好的,我现在需要帮助用户了解如何使用Android DataBinding。根据用户提供的引用内容,我需要整理一个结构清晰的教程。首先,我要确定DataBinding的基本配置步骤,因为这是开始使用的前提。然后,布局文件的修改是关键,需要解释如何将传统布局转换为DataBinding支持的格式。接下来,数据绑定的部分,用户可能需要知道如何创建数据模型并将其与UI绑定,引用中的User类示例和BindingAdapter的使用都是重点。此外,用户可能对在Activity和Fragment中的不同用法感兴趣,比如在Activity中使用DataBindingUtil.setContentView,而在Fragment中使用inflate方法。我还需要提到数据绑定的优势,比如减少样板代码,以及处理复杂数据的方法,比如使用@BindingAdapter自定义属性。最后,生成相关问题可以帮助用户深入理解,比如性能优化或与LiveData的结合。需要确保所有步骤都符合引用内容,并且语法正确,使用中文回答,行内公式用$...$,独立公式用$$...$$,不过在这个问题中可能公式较少,但要注意LaTeX的正确使用。检查是否有遗漏的步骤,例如启用DataBinding的Gradle配置,绑定变量的设置,以及事件处理的方法。确保每个部分都有对应的引用标注,比如在Activity和Fragment中的用法分别引用[^2]和[^1]。最后,生成的相关问题要覆盖用户可能感兴趣的扩展方向,如性能、优化、应用场景等。</think>### Android DataBinding 使用教程 #### 1. **启用DataBinding** 在模块的$build.gradle$文件中添加配置: ```groovy android { ... dataBinding { enabled = true } } ``` 同步项目后,系统会自动生成与布局文件对应的绑定类。 #### 2. **修改布局文件** 将传统XML转换为DataBinding格式: ```xml <!-- activity_main.xml --> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="com.example.User" /> </data> <LinearLayout...> <TextView android:text="@{user.name}" // 直接绑定变量 .../> <ImageView app:imageUrl="@{user.avatarUrl}" // 自定义属性绑定 .../> </LinearLayout> </layout> ``` 布局根标签需改为$<layout>$,并通过$<data>$定义变量[^3]。 #### 3. **数据绑定实现** - **数据模型类**(例如$User$)需使用可观察机制(如$BaseObservable$或$LiveData$): ```java public class User extends BaseObservable { private String name; @Bindable public String getName() { return name; } public void setName(String name) { this.name = name; notifyPropertyChanged(BR.name); // 触发UI更新 } } ``` - **在Activity中绑定数据**: ```java ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); User user = new User(); user.setName("John Doe"); binding.setUser(user); // 关键绑定语句 ``` - **在Fragment/Adapter中使用**: ```java ListItemBinding binding = DataBindingUtil.inflate( LayoutInflater.from(context), R.layout.list_item, parent, false ); binding.setVariable(BR.item, dataItem); // BR.item对应布局中定义的变量名[^1] ``` #### 4. **处理复杂绑定** - **自定义属性**:通过$@BindingAdapter$实现网络图片加载等逻辑: ```java @BindingAdapter("imageUrl") public static void bindImageUrl(ImageView view, String url) { Glide.with(view).load(url).into(view); // 使用第三方库加载图片[^4] } ``` - **事件绑定**:在布局中直接绑定点击事件: ```xml <Button android:onClick="@{() -> viewModel.onButtonClick()}" .../> ``` #### 5. **优势与注意事项** - **优势**:减少$findViewById$调用,UI更新自动化,代码可读性提升[^3] - **注意**:避免在布局中编写复杂逻辑,建议与ViewModel或Presenter模式结合
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值