1. property 属性
1.1 类属性方式实现
class Dog(object):
def __init__(self, age):
self.__age = age # 私有属性,只能在当前类内部访问的属性, 定义,属性前加两个下划线
def get_age(self):
"""定义方法,获取对象的 age 属性"""
return self.__age
def set_age(self, new_age):
"""定义方法,设置对象的 age 属性"""
self.__age = new_age
# 类属性方式实现 property 属性, 在类中, 方法外部定义的变量,就是类属性
# 使用 python 自带的方法,定义类属性 property(获取属性的方法, 设置属性的方法)
age = property(get_age, set_age)
if __name__ == '__main__':
# 创建对象
dog = Dog(2)
# print(dog.get_age())
# dog.set_age(3)
# print(dog.get_age())
# property 属性, 按照使用属性的方式, 调用类中的方法
print(dog.age) # 调用 get_age 方法
dog.age = 4 # 调用 set_age 方法
print(dog.age)
1.2 装饰器的方式实现
class Dog(object):
def __init__(self, name, age):
self. __name = name
self.__age = age # 私有属性,只能在当前类内部访问的属性, 定义,属性前加两个下划线
def get_age(self):
"""定义方法,获取对象的 age 属性"""
return self.__age
def set_age(self, new_age):
"""定义方法,设置对象的 age 属性"""
self.__age = new_age
# 类属性方式实现 property 属性, 在类中,方法外部定义的变量,就是类属性
# 使用 python 自带的方法,定义类属性 property(获取属性的方法, 设置属性的方法)
age = property(get_age, set_age)
# 使用装饰器的方式实现 property 属性
@property
def name(self): # 这个方法等价于 get_name
return self.__name
@name.setter
def name(self, new_name): # 等价于 set_name 方法
self.__name = new_name
if __name__ == '__main__':
dog = Dog('大黄', "2")
print(dog.name)
dog.name = '小白'
print(dog.name)
2. with 语句和上下文管理器
with open('a.txt', 'r') as f:
pass
使用 with 的好处: 不用关闭文件,会自动关闭,
原因: 上下文管理器对象存在
上下文管理器对象: 一个类如果实现了 __enter__ 和 __exit__ 这两个魔法方法,这个类的对象就是上下文管理器对象
with 语法 , 先进入上文方法, 即 __enter__ 方法
当 with 缩进中的代码,执行结束, 会执行 __exit__ 下文方法,可以在下文方法中关闭文件
补充:
pymysql.connect() 返回连接对象,使用结束后需要关闭连接 连接对象是上下文管理器,即可以使用 with
with pymysql.connect() as cursor: # 使用 with connect 得到的游标对象
pass
连接对象.cursor() 返回的是游标对象 可以使用 with
with 连接对象.cursor() as cursor:
pass
class File(object):
def __init__(self, filename, mode):
"""filename 文件名字, mode 文件的打开权限"""
self.filename = filename
self.mode = mode
print("__init__ 方法被调用")
# 定义上文方法, 获取资源的,参数一般只有 self, 不需要别的
# with 后的语句,对象创建出来之后,会自动执行这个方法
# 即 __init__ 方法执行之后,会执行(前提是使用 with)
def __enter__(self):
print('__enter__ 方法被调用')
# 获取文件对象, open 打开文件
self.fp = open(self.filename, self.mode, encoding='utf-8')
# 将这个文件对象进行返回
return self.fp
# 定义下文方法, 释放资源, 比如 关闭文件对象 __exit__ 方法
# 执行下文方法的时机:1. with 语句的代码执行结束, 2. 当 with 语句中的代码发生异常,也会进入
def __exit__(self, exc_type, exc_val, exc_tb):
# exc_type 异常的类型, 如果没有异常, 是 none
# exc_val 异常的值, 即异常额描述信息
# exc_tb Traceback 对象
# 函数的返回值, True, 代表发生的异常在 __exit__ 方法中结束,不再想上传递
# 函数的返回值, False, 代表异常会向外层传递
print(f"exc_type {exc_type}")
print(f"exc_val {exc_val}")
print(f"exc_tb {exc_tb}")
# 关闭文件
self.fp.close()
print("__exit__ 方法被调用")
# 可以使用 三个参数判断是否发生异常,以及对异常进行处理
if exc_type:
# 发生异常
print('发生异常')
return True # 拦截异常,使异常不再向外传递
else:
# 没有异常 None
print('没有发生异常')
if __name__ == '__main__':
with File('a.txt', 'w') as f: # ① 先创建 File 类的对象, ② 执行上文方法
# f.write('bbb')
f.read() # 使用 w 方式打开文件,只能写文件,不能读取,会发生异常
# ③ with 语句结束之后,执行下文方法
3. 生成器
3.1 生成器推导式
"""
生成器推导式和列表推导式非常像,只是将 [] 换成 ()
列表推导式: 直接生成所有的数据
生成器推导式: 不是一次全部生成数据,存储生成数据的方法, 使用一个数据,生成一个数据
好处: 节省内存
"""
# 列表推导式
my_list = [i for i in range(5)]
print(my_list) # [0, 1, 2, 3, 4]
# 生成器, 保存的生成数据的规则
my_gen = (i for i in range(5))
print(my_gen)
# 获取生成器中的数据 next(生成器对象)
print(next(my_gen)) # 0
print(next(my_gen)) # 1
print(next(my_gen)) # 2
print(next(my_gen)) # 3
print(next(my_gen)) # 4
# print(next(my_gen)) # 此时,生成数据的规则,已经不满足, 会抛出异常, StopIteration 异常
print("*" * 20)
# 获取生成器的数据,一般使用 for 循环, python 内部已经捕获了 StopIteration 的异常
my_gen = (i for i in range(5)) # 为什么不直接使用上边的生成器, 因为上边已经将数据去完了,不满足生成数据的规则了
for i in my_gen:
print(i) # 会自动进行 next 操作
3.2 yield 生成器
# 在函数中,如果出现了 yield 关键字,这个函数就是生成器, 同时 yield 可以实现协程(多任务)
def func():
print('func start....')
# yield 类似 return, ① 会生成 100 这个数据,并且能够将 100 这个数据返回到调用的地方
# ② 函数遇到 yield 会暂停执行, 等待代码下一次 next, 才会继续执行
yield 100
# 再次 next 之后,会继续执行
print('func 继续执行')
yield 200
print('func end ...')
# 后续没有代码, 结束了,再次 next() 会抛出异常
if __name__ == '__main__':
# 创建生成器对象
my_gen = func() # 正常的函数,会直接执行函数的代码, 存在 yield,生成器, 不会执行函数
print(my_gen)
# print(next(my_gen)) # 100
# print(next(my_gen)) # 200
# print(next(my_gen)) #
for i in my_gen: # for python 已经实现了 next 操作, 和捕获异常
print(i)
3.3 案例
# 斐波那契数列
# 0 1 1 2 3
def fibonacci(num):
"""生成多少个斐波那契数列"""
a = 0 # 第一个数据是 0
b = 1 # 第二个数据是 1
current_index = 0 # 以及生成的数据个数
while current_index < num:
yield a # 生成一个数据
current_index += 1 # 生成数据的个数加 1
# 改变 a 和 b 的值
a, b = b, a+b
if __name__ == '__main__':
# 创建对象
fi = fibonacci(5)
for i in fi:
print(i)
4. 深拷贝和浅拷贝
拷贝: 将一个变量的值复制给另一个变量, 在这个过程中可能会开辟新的内存空间, 可能不会. 拷贝的意义: 拷贝能够保证原数据和拷贝之后的数据是一样的, 修改拷贝之后的数据, 可能不会影响原数据.
4.1 浅拷贝
# 不管浅拷贝还是深拷贝,都需要使用 系统的模块 copy
import copy
# 浅拷贝 copy.copy() 函数
# 1. 对于不可变类型来说,浅拷贝等同于引用,不会开辟新的空间
# 不可变类型 int str tuple
# 1.1 int
age = 18
age1 = copy.copy(age)
print(f"age: {age}, {id(age)}")
print(f"age1: {age1}, {id(age1)}")
# 1.2 str
my_str = 'hello'
my_str1 = copy.copy(my_str)
print(f"my_str : {my_str}, {id(my_str)}")
print(f"my_str1: {my_str1}, {id(my_str1)}")
# 1.3 tuple
my_tuple = (1, 2, [3, 4])
my_tuple1 = copy.copy(my_tuple)
print(f"my_tuple : {id(my_tuple)}, my_tuple[2] {id(my_tuple[2])}")
print(f"my_tuple1: {id(my_tuple1)}, my_tuple1[2] {id(my_tuple1[2])}")
# 2. 对于可变类型, 只会对第一层对象开辟内存空间,(即 list 中嵌套一个 list,只会对最外层的 list 开辟空间)
# 可变类型: list set dict
my_list = [1, 2, [3, 4]]
my_list1 = copy.copy(my_list)
print(f"my_list : {id(my_list)}, myList[2] {id(my_list[2])}")
print(f"my_list1: {id(my_list1)}, myList1[2] {id(my_list1[2])}")
4.2 深拷贝
# 不管浅拷贝还是深拷贝,都需要使用 系统的模块 copy
import copy
# 深拷贝 copy.deepcopy() 函数
# 不可变类型 int str tuple
# 1.1 int 不会开辟新的空间
age = 18
age1 = copy.deepcopy(age)
print(f"age: {age}, {id(age)}")
print(f"age1: {age1}, {id(age1)}")
# 1.2 str 不会开辟新的空间
my_str = 'hello'
my_str1 = copy.deepcopy(my_str)
print(f"my_str : {my_str}, {id(my_str)}")
print(f"my_str1: {my_str1}, {id(my_str1)}")
# 1.3 tuple ① 如果元组的数据, 都是不可变类型, 没有可变类型, 不会开辟新的空间
# ② 如果元组中的数据包含可变类型,那就会对元组本身以及包含的可变类型开辟空间
my_tuple = (1, 2)
my_tuple1 = copy.deepcopy(my_tuple)
print(f"my_tuple {id(my_tuple)}")
print(f"my_tuple1 {id(my_tuple1)}")
my_tuple = (1, 2, [3, 4])
my_tuple1 = copy.deepcopy(my_tuple)
print(f"my_tuple : {id(my_tuple)}, my_tuple[2] {id(my_tuple[2])}")
print(f"my_tuple1: {id(my_tuple1)}, my_tuple1[2] {id(my_tuple1[2])}")
# 2. 对于可变类型, 会对所有的可变类型开辟空间
my_list = [1, 2, [3, 4]]
my_list1 = copy.deepcopy(my_list)
print(f"my_list : {id(my_list)}, myList[2] {id(my_list[2])}")
print(f"my_list1: {id(my_list1)}, myList1[2] {id(my_list1[2])}")