Python进阶学习笔记(四)—— property属性、上下文管理器与生成器

1 property 属性


property 属性就是负责把一个方法当做属性进行使用,这样做可以简化代码使用。

定义 property 属性有两种方式:

  • 装饰器方式
  • 类属性方式

1.1 装饰器方式


class Person(object):

    def __init__(self):     
    	# 定义私有属性age
        self.__age = 0

    # 装饰器方式的property, 把age方法当做属性使用, 表示当获取属性时会执行下面修饰的方法
    @property
    def age(self):
        return self.__age

    # 把age方法当做属性使用, 表示当设置属性时会执行下面修饰的方法
    @age.setter
    def age(self, new_age):
        if new_age >= 150:
            print("成精了")
        else:
            self.__age = new_age

# 创建person
p = Person()
print(p.age) # 0

p.age = 100
print(p.age)# 100

p.age = 1000 # 成精了

注意:

  • @property 表示把方法当做属性使用, 表示当获取属性时会执行下面修饰的方法
  • @方法名.setter 表示把方法当做属性使用,表示当设置属性时会执行下面修饰的方法
  • @property@方法名.setter 修饰的方法名一定要一样,本例中方法名都为 age

1.2 类属性方式


class Person(object):

    def __init__(self):
        self.__age = 0

    def get_age(self):
        # 当获取age属性的时候会执行该方法
        return self.__age

    def set_age(self, new_age):
        # 当设置age属性的时候会执行该方法
        if new_age >= 150:
            print("成精了")
        else:
            self.__age = new_age

    # 类属性方式的property属性
    age = property(get_age, set_age)


# 创建person
p = Person()
print(p.age)  # 0

p.age = 100
print(p.age)  # 100

p.age = 1000  # 成精了

类属性 = property(获取值方法, 设置值方法)

  • 第一个参数是获取属性时要执行的方法
  • 第二个参数是设置属性时要执行的方法

2 with语句与上下文管理器

2.1 with语句的使用


 # 1、以【写】的方式打开文件
 f = open("1.txt", "w")
 # 2、写入文件内容
 f.write("hello world")
 # 3、关闭文件
 f.close()

我们知道,文件使用完后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的

但是当执行以下代码,会报错:not writable

 # 1、以【读】的方式打开文件
 f = open("1.txt", "r")
 # 2、读取文件内容
 f.write("hello world")
 # 3、关闭文件
 f.close()

由于文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用。为了保证无论是否出错都能正确地关闭文件,我们可以使用try ... finally来解决

try:
    # 1、以读的方式打开文件
    f = open("1.txt", "r")
    # 2、读取文件内容
    f.write("xxxxx")

except IOError as e:
    print("文件操作出错", e)

finally:
    # 3、关闭文件
    print("文件关闭了")
    f.close()
    print("确实关闭了")

结果输出:

文件操作出错 not writable
文件关闭了
确实关闭了

这种方法虽然代码运行良好,但是缺点就是代码过于冗长,并且需要添加try-except-finally语句,不是很方便,也容易忘记。

在这种情况下,Python提供了 with 语句的这种写法,既简单又安全,并且with 语句执行完成以后自动调用关闭文件操作,即使出现异常也会自动调用关闭文件操作。

2.2 上下文管理器


(1)实现方式一

一个类只要实现了__enter__()__exit__()这个两个魔法方法,通过该类创建的对象我们就称之为上下文管理器。

上下文管理器可以使用 with 语句,with 语句之所以这么强大,背后是由上下文管理器做支撑的,with 语句是结合上下文管理器使用的,也就是说刚才使用 open 函数创建的文件对象就是就是一个上下文管理器对象。(open()函数实现了__enter__()__exit__()这个两个方法)

# 自定义上下文管理器类File类
class File(object):
    def __init__(self, file_name, file_mode):
        self.file_name = file_name
        self.file_mode = file_mode

    def __enter__(self):
        # 上文方法,负责返回操作对象资源,比如:文件对象,数据库连接对象
        self.file = open(self.file_name, self.file_mode)
        return self.file

    # 当with语句执行完成以后自动执行__exit__方法
    def __exit__(self, exc_type, exc_val, exc_tb): # 其中的参数是编译器自动生成的
        # 下文方法,负责释放对象资源,比如: 关闭文件,关闭数据库连接对象
        print("over")
        self.file.close() # 为了够得着__enter__中的file对象,所以要借用self

# with 语句结合上下文管理器对象使用
with File("1.txt", "r") as file:
    # file_data = file.read()
    # print(file_data)
    file.write("sss")

在这里插入图片描述

说明执行了关闭文件操作

(2)实现方式二(装饰器方式)

假如想要让一个函数成为上下文管理器,Python 还提供了一个 @contextmanager 的装饰器,更进一步简化了上下文管理器的实现方式。通过 yield 将函数分割成两部分,yield 上面的语句在 __enter__方法中执行,yield 下面的语句在__exit__ 方法中执行,紧跟在 yield 后面的参数是函数的返回值。

from contextlib import contextmanager


# 加上装饰器这个代码,那么下面函数创建的对象就是一个上下文管理器
@contextmanager
def my_open(file_name, file_mode):

    try:
        file = open(file_name, file_mode)
        # yield关键之前的代码可以认为是上文方法,负责返回操作对象资源
        yield file
    except Exception as e:
        print(e)
    finally:
        print("over")
        # yield关键字后面的代码可以任务是下文方法,负责释放操作对象的资源
        file.close()


# 【普通函数】不能结合with语句使用,with语句结合上【下文管理器】
with my_open("1.txt", "r") as file:
    # file_data = file.read()
    # print(file_data)
    file.write('sss')

结果输出:

not writable
over

3 生成器


生成器:根据程序员制定的规则循环生成数据,当条件不成立时则生成数据结束。数据不是一次性全部生成处理,而是使用一个,再生成一个,可以节约大量的内存

创建生成器的方式

  • 生成器推导式
  • yield 关键字

3.1 生成器推导式


与列表推导式类似,只不过生成器推导式使用小括号

my_generator = (value for value in range(3))
print(my_generator)

# next获取生成器下一个值
value = next(my_generator)
print(value) # 0

value = next(my_generator)
print(value) # 1

value = next(my_generator)
print(value) # 2

# 当生成器已经没有值时,会抛出StopIteration,表示生成器生成数据完毕
value = next(my_generator)
print(value) # StopIteration,停止迭代
# for循环内部循环调用next函数获取生成器中的下一值,当出现异常for循环内部自动进行了异常捕获。
my_generator = (value for value in range(3))

# while True:
#     try:
#         value = next(my_generator)
#         print(value)
#     except Exception as e:
#         break # 跳出循环表示取值完成

for value in my_generator:
    print(value)

# 0
# 1
# 2

3.2 yield 关键字


只要在 def 函数里面看到有 yield 关键字那么就是生成器

def my_generator():
    for i in range(3):
        print("开始生成数据啦...")
        # 当程序执行到yield关键字的时候代码暂停并把结果返回,再次启动生成器的时候会在暂停的位置继续往下执行
        yield i
        print("上一次的数据生成完了...")


result = my_generator()
print(result)

value = next(result)
print(value)
# 开始生成数据啦...
# 0

value = next(result)
print(value)
# 上一次的数据生成完了...
# 开始生成数据啦...
# 1

value = next(result)
print(value)
# 上一次的数据生成完了...
# 开始生成数据啦...
# 2

value = next(result)
print(value) 
# 上一次的数据生成完了...
# 报异常StopIteration

3.3 生成器使用案例


数学中有个著名的斐波拉契数列(Fibonacci),数列中第一个数为0,第二个数为1,其后的每一个数都可由前两个数相加得到:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …

现在我们使用生成器来实现这个斐波那契数列,每次取值都通过算法来生成下一个数据, 生成器每次调用只生成一个数据,可以节省大量的内存。

# num 表示生成斐波那契数列的个数
def fibonacci(num):
    # 初始化前两个值
    a = 0
    b = 1
    # 记录每次生成个数的索引
    current_index = 0
    # 循环判断条件是否成立
    while current_index < num:
        result = a
        # 条件成立交换两个变量的值
        a, b = b, a + b
        current_index += 1
        yield result


# 创建生成器
f = fibonacci(1000)

for value in f:
    print(value)

# value = next(f)
#
# print(value)
#
# value = next(f)
#
# print(value)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值