目录
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)