import
import导入模块路径问题
- 存在的问题:当我们把模块文件放到工程文件夹的外部的文件,发现无法正常引入模块
- 原因: 外部的文件夹的路径,没有放到环境变量中
- 查看环境变量
- 导入 sys模块
- sys.path 查看环境变量 返回值是列表
- 把自己写的模块的路径加入到环境变量中
- sys.path.append("自己的路径") # 加入环境变量的末位
- sys.path.insert(0, "自己的路径") # 加入到环境变量的开头位置
- 添加路径后才能导入
import sys
sys.path
# sys.path.append("d:\\git-python\\进阶\\py") 增加路径
# sys.path.pop(-1) 删除路径
# sys.path.pop(0)
# sys.path.insert(0, "d:\\git-python\\进阶\\py")
['d:\\git-python\\进阶',
'd:\\python\\python312.zip',
'd:\\python\\DLLs',
'd:\\python\\Lib',
'd:\\python',
'',
'C:\\Users\\吴玉堂\\AppData\\Roaming\\Python\\Python312\\site-packages',
'C:\\Users\\吴玉堂\\AppData\\Roaming\\Python\\Python312\\site-packages\\win32',
'C:\\Users\\吴玉堂\\AppData\\Roaming\\Python\\Python312\\site-packages\\win32\\lib',
'C:\\Users\\吴玉堂\\AppData\\Roaming\\Python\\Python312\\site-packages\\Pythonwin',
'd:\\python\\Lib\\site-packages',
'd:\\git-python\\进阶\\py']
import的reload加载问题
- import 导入模块后,如果模块被修改,此时再次 import 不起作用
- import 自动防止重复包含,多次导入不会起作用
- 强制重新加载一次模块
- reload() 函数
- from importlib import reload
- reload(要重新加载的模块)
# reload_test.py
def test():
print("---111---")
print("---222---")
name = "haha"
_age = "18"
import reload_test
reload_test.test()
# reload_test.py 增加输出 ---222---
# ---111--- 输出不变
---111---
import reload_test
from importlib import reload
reload(reload_test)
reload_test.test()
# ---111---
# ---222---
---111---
---222---
from...import的私有化问题
- 私有化: 模块中的一些变量不希望被其他模块导入,可以使用私有化解决
- 私有化使用的前提:必须使用 “ from xxx import * “
- 用法: 在模块中,把变量前增加一个下划线 _变量名
- 注意:如果使用其他的方式导入模块,私有化将无效
- from xxx import _私有变量
- print(_私有变量) 不会报错
from reload_test import *
from importlib import reload
reload(reload_test)
print(name)
# print(_age) # NameError: name '_age' is not defined
haha
from reload_test import *
from reload_test import _age
from importlib import reload
reload(reload_test)
print(name)
print(_age)
haha
18
import和from...import的区别
- 区别
- 写法:
- import 模块名.变量/函数/类
- from 模块 import 变量名/函数/类
- 底层的区别:
- import 直接引用了源模块的 变量/函数/类
- from ... import * 添加新引用 变量/函数/类 到当前自己类
可变参数的拆包问题
- 可变参数 *args **kwargs 默认会有封包过程
- 如果想要这种单数继续传递到下一个函数,传递的时候必须加 号 func(args,**kwargs)
# 定义两个函数 func02 func01
# func02 调用func01
# func02 有可变参数
def func01(*args, **kwargs):
print("--------- func01 ---------")
print("args =", args)
print("kwargs =", kwargs)
def func02(*args, **kwargs):
print("--------- func02 ---------")
print("args =", args)
print("kwargs =", kwargs)
# 调用func01
# 此处没有进行拆包,导致参数传递过去不符合要求
func01(args, kwargs)
func01(*args, **kwargs)
if __name__ == '__main__':
func02(10, 20, 30, 40, 50, a=10, b=20)
--------- func02 ---------
args = (10, 20, 30, 40, 50)
kwargs = {'a': 10, 'b': 20}
--------- func01 ---------
args = ((10, 20, 30, 40, 50), {'a': 10, 'b': 20})
kwargs = {}
--------- func01 ---------
args = (10, 20, 30, 40, 50)
kwargs = {'a': 10, 'b': 20}
单继承中super()
- super() 使用的时候,传递参数的时候,self 不用传递
- super() 调用顺序,按照 mro顺序来完成
- Grandson.__mro__ 是一个元组
- 当在类中使用 super() 在 mro列表中找到当前类的下一个元素,调用该元素的方法
class Parent(object):
def __init__(self, name):
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age):
# super(Son1, self).__init__(name)
self.age = age
super().__init__(name)
print('Son1的init结束被调用')
class Grandson(Son1):
def __init__(self, name, age, gender):
self.gender = "男"
super().__init__(name, age) # 单继承不能提供全部参数
print('Grandson的init结束被调用')
gs = Grandson('grandson', 12, '男')
print(Grandson.__mro__)
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
parent的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
(, , , )
姓名: grandson
年龄: 12
性别: 男
多继承和MRO顺序
- 多继承中 super() 执行顺序,严格执行 MRO顺序表
- MRO顺序表:
- 类名.mro()
- 类名.__mro__
- 注意:
- 当在类中使用 super() 在 mro列表中找到当前类的下一个元素,调用该元素的方法
- 多继承中,不建议使用类名 直接调用父类的方法
# 定义父类Parent
class Parent(object):
def __init__(self, name, *args, **kwargs):
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age, *args, **kwargs):
self.age = age
# Parent.__init__(self, name)
super(Son1, self).__init__(name, *args, **kwargs)
print('Son1的init结束被调用')
class Son2(Parent):
def __init__(self, name, gender, *args, **kwargs):
self.gender = gender
# Parent.__init__(self, name)
super(Son2, self).__init__(name, *args, **kwargs)
print('Son2的init结束被调用')
# 定义子类 Grandson --继承--> Son1 \ Son2
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
# Son1.__init__(self, name, age) # 单独调用⽗类的初始化方法
# Son2.__init__(self, name, gender)
super().__init__(name, age, gender)
print('Grandson的init结束被调用')
# 创建对象
gs = Grandson('grandson', 12, '男')
print(Grandson.mro())
parent的init结束被调用
Son2的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
[, , , , ]
class A(object):
def __init__(self):
print("A")
class B(A):
def __init__(self):
super().__init__()
# A.__init__(self)
print("B")
class C(A):
def __init__(self):
super().__init__()
# A.__init__(self)
print("C")
class D(B, C):
def __init__(self):
super().__init__()
print("D")
d = D()
# A C B D
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
A
C
B
D
(, , , , )
property基本使用
@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改
- @property 的特点: 让我们通过对象.方法名的方式可以调用方法
- 语法格式:
@property def xxx(self): pass
- 注意:@property 装饰的方法,只能有一个参数self
# ############### 定义 ###############
class Foo(object):
def __init__(self, num):
self.num = num
def prop(self):
return self.num
# ############### 调用 ###############
foo_obj = Foo(10)
foo_obj.prop()
10
# ############### 定义 ###############
class Foo(object):
def __init__(self, num):
self.num = num
# 定义property属性
@property
def prop(self):
return self.num
# ############### 调用 ###############
foo_obj = Foo(10)
foo_obj.prop
10
# 简单分页实例
# ############### 定义 ###############
class Pager:
def __init__(self, current_page):
# 用户当前请求的页码(第一页、第二页...)
self.current_page = current_page
# 每页默认显示10条数据
self.per_items = 10
@property
def start(self):
val = (self.current_page - 1) * self.per_items + 1
return val
@property
def end(self):
val = self.current_page * self.per_items
return val
# ############### 调用 ###############
p = Pager(2)
print(p.start) # 就是起始值,即:11
print(p.end) # 就是结束值,即:20
11
20
property其他使用方式
- 经典类: @property 一种方式
- 新式类:
- @property
- goods.price 获取价格的方法
- @xxx.setter
- goods.price = xxx
- @xxx.deleter
- del goods.price ---> @xxx.delete 装饰的方法
# ############### 定义 ###############
class Goods:
"""python3中默认继承object类
以python2、3执行此程序的结果不同,因为只有在python3中才有@xxx.setter @xxx.deleter
"""
def __init__(self):
# 初始化一个原价
self.org_price = 1000
# 初始化折扣
self.discount = 0.7
@property
def price(self):
return self.org_price * self.discount # 打折后的价格
@price.setter
def price(self, value): # 修改价格
if value > 0:
self.org_price = value
@price.deleter
def price(self):
print("售罄")
print('@price.deleter')
# ############### 调用 ###############
obj = Goods()
print(obj.price) # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
obj.price = 600 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数
print(obj.price)
del obj.price # 自动执行 @price.deleter 修饰的 price 方法
700.0
420.0
售罄
@price.deleter
property作为类属性
- 定义 property 对象的类属性
- xxx =property(参数1,参数2,参数3,参数4)
- 第一个参数,当我们 foo.BAR 自动调用第一个参数的方法
- 第二个参数,当我们 foo.BAR = 100,自动调用第二个参数的方法
- 第三个参数,当我们 del foo.BAR ,自动调用第三个参数的方法
- 第四个参数,当我们 Foo.BAR.__doc__,自动获取第四个参数的内容
- 使用
- 对象.xxx 获取值
- 对象.xxx = 100 设置值
- del 对象.xxx 调用第三个参数方法
- 类.xxx.__doc__ 获取第四个参数的内容
class Goods:
def __init__(self):
# 初始化一个原价
self.org_price = 1000
# 初始化折扣
self.discount = 0.7
def get_price(self):
print("getter...")
return self.org_price * self.discount # 打折后的价格
def set_price(self, value): # 修改价格
print("setter...", value)
if value > 0:
self.org_price = value
def del_price(self):
self.org_price = 0
print("售罄")
print('deleter...')
BAR = property(get_price, set_price, del_price, 'description...')
obj = Goods()
obj.BAR # 自动调用第一个参数中定义的方法:get_price
print(obj.BAR)
obj.BAR = 700 # 自动调用第二个参数中定义的方法:set_price方法,并将 700 当作参数传入
print(obj.BAR)
del obj.BAR # 自动调用第三个参数中定义的方法:del_price方法
print(obj.BAR)
desc = Goods.BAR.__doc__ # 自动获取第四个参数中设置的值:description...
print(desc)
getter...
getter...
700.0
setter... 700
getter...
489.99999999999994
售罄
deleter...
getter...
0.0
description...
魔法属性和方法
- 魔术属性
- __doc__ 获取描述信息
- 获取类的 类名.__doc__
- 获取方法的描述 对象.方法名.__doc__
- __module__ 获取所属的模块 对象名.__module__ 直接运行py文件 获取的main
- __class__ 获取对象所属的类 对象名.__class__
- 魔术方法
- __init__ 初始化方法 类名() 自动调用
- __del__ 删除对象的时候,会调用 del 对象
- 魔术属性__dict__ 获取对象或者类的信息
- 获取对象信息 对象名.__dict__对象的实例属性信息
- 获取类的信息 类名.__dict__ 模块、类描述、对象方法...
- 魔术方法
- __call__() 当使用 对象名() 会调用该方法
- __str__() 打印对象的会调用 print(obj) str方法一定要return,而且return 一定字符串内容
- 用字典的书写格式操作对象的方法
- __getitem__ 对象['xx']
- __setitem__ 对象['xx'] = xxx
- __delitem__ del 对象['xx']
class Goods(object):
"""这是一个商品类 Goods"""
def __init__(self):
print("执行__init__方法")
def set_price(self):
"""这是Goods类中定义的设置价格的方法"""
pass
def __del__(self):
print("执行__del__方法")
# __doc__ 描述信息获取
print(Goods.__doc__)
print(Goods.set_price.__doc__)
# 获取当前模块
goods = Goods() # 执行__init__方法
print(goods.__module__) # __main__
print(goods.set_price.__module__) # __main__
# 获取对象所属的类
print(goods.__class__) # <class '__main__.Goods'>
# 删除对象
del goods # 执行__del__方法
这是一个商品类 Goods
这是Goods类中定义的设置价格的方法
执行__init__方法__main__
__main__
执行__del__方法
class Goods(object):
"""这是一个商品的类 Goods"""
# 类属性
goods_color = "白色"
def __init__(self):
# 实例属性
self.org_price = 100
self.discount = 0.7
def set_price(self):
"""这是Goods类中定义的设置价格方法"""
pass
def __call__(self, *args, **kwargs):
print("__call__ 方法被调用")
def __str__(self):
return "我是一个寂寞的对象"
# def __del__(self):
# print("__del__ 正在执行")
def __getitem__(self, item):
print("key = ", item)
def __setitem__(self, key, value):
print("key = %s, value = %s" % (key, value))
def __delitem__(self, key):
print("要删除 key = ", key)
goods = Goods()
# 对象名() 会去调用对象的 __call__() 方法
goods()
# print 打印对象的时候,默认输出<__main__.Goods object at 0x7efe5e9e0a20>
# __str__() 可以重写此输出
print(goods)
# 通过__dict__ 获取对象信息,对象.__dict__返回字典
# {'org_price': 100, 'discount': 0.7}
print(goods.__dict__)
# 通过__dict__ 获取类的信息 类名.__dict__ 返回值是一个字典
# {'__module__': '__main__', '__doc__': '这是一个商品的类 Goods', 'goods_color': '白色', '__init__': <function Goods.__init__ at 0x0000022FF2C43730>, 'set_price': <function Goods.set_price at 0x0000022FF2C436A8>, '__call__': <function Goods.__call__ at 0x0000022FF2C430D0>, '__str__': <function Goods.__str__ at 0x0000022FF2C437B8>, '__del__': <function Goods.__del__ at 0x0000022FF2C43840>, '__getitem__': <function Goods.__getitem__ at 0x0000022FF2C438C8>, '__setitem__': <function Goods.__setitem__ at 0x0000022FF2C43950>, '__delitem__': <function Goods.__delitem__ at 0x0000022FF2C439D8>, '__dict__': <attribute '__dict__' of 'Goods' objects>, '__weakref__': <attribute '__weakref__' of 'Goods' objects>}
print(Goods.__dict__)
# dict1 = {}
# dict1['a'] = 10
# goods['a'] 调用 __getitem__方法
goods['a']
# goods['a'] = 10 调用 __setitem__ key,value
goods['a'] = 10
# del goods['a'] 调用 __delitem__ key
del goods['a']
__call__ 方法被调用
我是一个寂寞的对象
{'org_price': 100, 'discount': 0.7}
{'__module__': '__main__', '__doc__': '这是一个商品的类 Goods', 'goods_color': '白色', '__init__': , 'set_price': , '__call__': , '__str__': , '__getitem__': , '__setitem__': , '__delitem__': , '__dict__': , '__weakref__': }
key = a
key = a, value = 10
要删除 key = a
with管理上下文方式
- 上下文:以 with open 来说,打开文件在上文 关闭文件在下文
- 上下文管理器:
- __enter__ 上文方法
- __exit__ 下文方法
- 自定义一个满足满足上下文管理器的 类
- 通过装饰器 @ contextmanager 实现上下文管理
- 装饰器
- 待装饰的函数
- myopen() 分拆成上文和下文,使用yield 分拆
-
装饰的过程:
- 导入模块 from contextlib import contextmanager
- 第二步:
@contextmanager def myopen(file_name,file_model): ...
"""
类: MyFile()
类方法:
1. __enter__() 上文方法
2. __exit__() 下文方法
3. __init__() 方法,接收参数并且初始化
实现效果:
with MyFile("log.txt", "r", "UTF-8") as file:
file.read()
"""
class MyFile(object):
# 1. __enter__() 上文方法
def __enter__(self):
print("进入上文....")
# 1,打开文件
self.file = open(self.file_name, self.file_model, encoding=self.file_encode)
# 2,返回打开的文件资源
return self.file
# 2. __exit__() 下文方法
def __exit__(self, exc_type, exc_val, exc_tb):
print("进入下文....")
# 关闭文件资源
self.file.close()
# 3. __init__() 方法,接收参数并且初始化
def __init__(self, file_name, file_model, file_encode):
# 保存文件名和文件打开模式,到实例属性中
self.file_name = file_name
self.file_model = file_model
self.file_encode = file_encode
if __name__ == '__main__':
with MyFile("log.txt", "r", "UTF-8") as file:
# 开始读取文件
file_data = file.read()
print(file_data)
"""
进入上文....
....
....
进入下文....
"""
"""
思路:
def myopen(file_name,file_model)
上文(打开资源)
yield
下文(关闭资源)
装饰器装饰函数的步骤:
1. 导入模块 from contextlib import contextmanager
2. 开始装饰 @contextmanager
"""
from contextlib import contextmanager
@contextmanager
def myopen(file_name, file_model, file_encode):
print("进入上文")
# 1.上文 打开文件
file = open(file_name, file_model, encoding=file_encode)
# 2.返回资源
yield file
print("进入下文")
# 3. 下文 关闭资源
file.close()
with myopen("log.txt", "r", "UTF-8") as file:
file_data = file.read()
print(file_data)