当前位置: 首页 > news >正文

Python 笔记 (二)

Python Note 2

    • 1. Python 慢的原因
    • 2. 三个元素
    • 3. 标准数据类型
    • 4. 字符串
    • 5. 比较大小: 富比较方法 rich comparison
    • 6. 数据容器 (支持*混装* )
      • 一、允许重复类 (list、tuple、str)
      • 二、不允许重复类 (set、dict)
        • 1、集合(set)
        • 2、字典(dict)
        • 3、特殊: 双端队列 deque
      • 三、数据容器的共性
      • 四、生成器 (推导式 + yield关键字)
    • 7. 方法
      • 一、4种方法参数 (「位置参数 `/`、`*` 关键字参数」、不定长参数、缺省参数)
      • 二、方法本身作为参数
      • 三、lambda 函数
      • 四、实例方法,静态方法,类方法
      • 五、函数参数 与 闭包 (Closure)
      • 六、装饰器 (Decorator, 切面作用, 本质是特殊的闭包)
      • 七、property 属性
    • 8. 文件
    • 9. 异常
    • 10. 模块
    • 11. 下划线
    • 12. Typing 模块
    • 13. Python 并发编程
      • 协程 (Coroutine: 协同程序)
      • 信号量 Semaphore

1. Python 慢的原因

  1. 动态类型语言, 边解释边执行
  2. GIL (Global Interpreter Lock, 全局解释器锁)
    1. 为了规避并发问题引入GIL
    2. 引用计数器

2. 三个元素

变量、标识符 identifiers (变量名 函数名 类名)、字面量 (被写在代码中固定的值, 常用: 整数 浮点数 字符串)

  • 不允许使用关键字作为标识符. 如 raise、elif、in、as、except、assert、from、nonlocal
  • 不允许使用自带函数名作为标识符, 会顶替掉函数功能. 如 sum、len

python 是动态类型强类型语言. 决定了变量名没有类型, 类型是运行决定的

  • 强弱: 类型隐式自动转换
  • 动静: 类型检查, 动:运行期or静:编译期
# 30个关键字
and exec not assert finally or break for pass class
from print continue global raise def if return del import
try elif in while else is with except lambda yield

3. 标准数据类型

  • Python 的标准数据类型有:

    • Boolean(布尔值)
    • Number(数字)
    • String(字符串)
    • List(列表)
    • Tuple(元组)
    • Set(集合)
    • Dictionary(字典)
  • Golang 不是面向对象的语言, 没有关键字 Class, 通过 struct、interface 类型实现 OOP 编程风格

    • boolean(布尔值)
    • numeric(数字)
    • string(字符串)
    • 数组(数组)
    • slice(切片:不定长数组)
    • map(字典)
    • struct(结构体)
    • pointer(指针)
    • function(函数)
    • interface(接口)
    • channel(通道)
  • 多变量赋值
    a = b = c = 1

  • 判断相等

    • a == b 值相等
    • a is b id 相等 id(a) == id(b)
    • isinstance(a, int)
    • issubclass(int, object)

4. 字符串

  1. 单引号方式、双引号方式、三引号方式:
    " ‘会显示单引号’ “、 ’ “会显示双引号” '、 “”“字符串3"””

  2. 字符串的输出:

    1. 加号拼接方式: “会返回” + “新的字符串”
    2. 百分号占位符方式: “%s %d %f” % (str(a), int(b), float©)
      1. 占位符精度控制 m.n (注意: 超过 m 会忽略、在 n 处会四舍五入)
    3. 快速格式化方式: f"{name} {variable}" # 不会理会类型, 全转为字符串, 不做精度控制
  3. 字符串输入:

    1. input(“提示信息!”) # 获得的永远都是字符串类型 str
  4. 字符串比较, 头到尾 ->, 其中一位大, 后面就无须比较

  5. True、False 产生: 字面量, 比较运算

  6. 函数没有 return 语句也会返回值: 字面量 None (类型为: <class ‘NoneType’>, 使用场景有: if 判断、变量定义)

5. 比较大小: 富比较方法 rich comparison

  • __gt__ (相反 __lt__)
  1. 当都定义时, 分别调用.
  2. 当另一个未定义时, 未定义的操作会调用已定义的方法取反.
  • __le____ge__
  1. 当都定义时, 分别调用.
  2. 当另一个未定义时, 未定义的操作会调用已定义的方法取反.
  • __eq____ne__
  1. 在自定义类中实现了 __eq____ne__ 这两个方法,则 ==!= 的两个对象比较分别调用了这两个方法进行比较.
  2. 当实现了 __eq__ 方法,未实现 __ne__ 方法时, 未定义的操作会调用 __eq__ 方法取反.
  3. 但实现了 __ne__ 方法,未实现 __eq__ 方法, 则 != 调用 __ne__ 方法,而 __eq__ 调用系统内置的 == 对应的方法
  • is vs ==
    1. is 表示的是对象标示符(object identity)
      相当于 id(a) == id(b), 是检查两个对象是否指向同一块内存空间
    2. == 表示的是相等(equality)
      相当于 a.__eq__(b), 是检查他们的值是否相等
    3. Python 里和 None 比较是 is None
      因为 None 是个单例类型,TrueFalse 也是.
      is== 更严格的检查

6. 数据容器 (支持混装 )

  1. python中的数据容器支持混装: str、int、bool
    1. map、list、set、都可以放入不同类型的变量
  2. 5类数据容器
    1. list [1,2] tuple (1,2) str "12" set {1,2} dict
    2. 字符串也可以作为容器, 支持下标索引 forin or str.split(" ") # 返回list

一、允许重复类 (list、tuple、str)

  1. 打磨: new_str = my_str.strip("12") # 表示前后的 两个字串 1 和 2 都会被去除
  2. 统计: my_str.count("it") # 因为允许重复, 所以可统计出现次数
  3. 不变类型: 字符串只可以存储字符、不可以修改
  4. 序列: 三个 (列表、元组、字符串) 都可被视为 序列
    1. 序列可以进行n切片 [start:end:step] step 默认为1 可以为负倒序执行 左闭右开
    2. 可以连续切片 a[:8][2:5][-1:] # [:8]就是0取到8 在从其中取2到5 最后取-1位 [4]
    3. 切片操作的时候, 超出下标不会报错, 相互矛盾的话不会报错, 返回为空
    4. 取反操作 [::-1] 可取代 reverse()
  5. 批量追加: list.extend(seq) 扩展原来的列表
    1. 在列表末尾一次性追加另一个序列中的值
    2. 无返回值,但会在已存在的列表中添加新的列表内容
  6. 元祖在只有一个元素时必须加逗号 (1,) 记住元祖是不可变对象, 定义是什么就是什么
    1. 只有这样才保证没有歧义
    2. python 在打印时也会加上
    3. 另外, 空的元祖不需要加逗号 ()

二、不允许重复类 (set、dict)

1、集合(set)
  1. 特点:
    1. 无序存储
    2. 不支持下标
    3. 不允许重复数据存在 (重要的去重功能)
    4. 不支持while循环
  2. 常用方法:
    1. set1.union(set2) 不变, 返回并集
    2. set1.difference(set2) 不变, 返回差集
    3. set1.difference_update(set2) set2不变, set1去掉set2中的元素
2、字典(dict)
  1. 特点:
    1. key不重复
    2. 不支持下标
    3. key 和 value 支持任意类型, 但 key 不可为字典类型和可变类型
  2. 使用:
    1. 存放: 字典[key] = value
    2. 取出: 字典.pop(key) (对应 value 删除)
    3. 清空: 字典.clear()
    4. 获取所有key: 字典.keys()
      1. 可用于 for 循环
      2. for f in futures 默认就等于 for f in futures.keys()
    5. 长度: len(字典)
    6. 是否包含: 字典.__contains__(key) or if xx in 字典:
  3. 特殊:
    1. 元祖的key可以是元祖 (包含不可变对象)
    2. 元组只有在其元素是可散列的(不可变类型)情况下,才可以作为字典的key值
    3. e.g. (“unhashable type: ‘list’”, [1, 2, 3], “unhashable type ‘dict’”, {})
3、特殊: 双端队列 deque
  1. 引入: from collections import deque
  2. 使用:
    • append pop extend [+ left]
    • index, insert(1, ?), count(“a”)
    • remove, reverse, rotate, copy

三、数据容器的共性

  1. 都支持 for 循环遍历
  2. 函数: len(容器)max(容器)min(容器)sorted(容器, [reverse=True])

四、生成器 (推导式 + yield关键字)

补充: range() 函数
1. 语法: range(start, stop[, step]) or range(stop) # default: start=0, step=1
2. 区分:
1. python3 range() 返回的是一个可迭代对象 (类型是对象) 打印的时候不会打印列表.
2. python2 range() 返回 列表类型(整数列表)

为什么要使用生成器: 生成器的数据是: 使用一个, 再生成一个, 可以节约大量内存

  • 生成器的使用记住: next(生成器对象) 方法

  • 推导式是一种数据处理方式, 类似于stream流. (从一个数据序列构建另一个新的数据序列)

  1. 列表推导式语法: [表达式 for 变量 in 列表 [if 条件]] 其中:
    1. 迭代 列表 将 变量 传入到 表达式 中.
    2. 表达式可以是有返回值的函数也可以是固定值
    3. if 条件语句, 可以过滤列表中不符合条件的值
  2. 字典推导式语法: { key_expr: value_expr for value in collection [if condition ]}
  3. 集合推导式语法: { expression for item in Sequence [if conditional]}
  4. 生成器推导式语法: (expression for item in Sequence if conditional )
    1. 生成推导式返回的结果是一个生成器对象, 不是元祖
      <generator object <genexpr> at 0x1074abac0>
    2. 使用 tuple 函数: tuple(a), 可以将生成器对象转换成元组
    3. 获取下一个值, 使用 next(genertor) 函数
    4. 遍历生成器中的每一个值. 使用 for i in genertor: 循环
  • yield 关键字
    1. 特征: 在 def 中具有 yield 关键字
    2. 定义:
      1. 函数要有 yield 关键字, 那函数就是生成器了(变成生成器了) ;
      2. yield 可以把一个对象返回出去;
    3. 特点: 保存计算状态 (执行状态); 当然还有节约内存资源!! 每次调用只生成一个数据
    4. 注意点:
      1. 赋值时不会运行函数, 调用时才会进入 for 循环, 并停在 yield 关键字处
      2. 代码执行到 yield 会暂停, 然后把结果返回出去, 下次启动生成器会在暂停的位置继续往下执行
      3. 如果生成器把数据生成完成, 再次获取生成器中的下一个数据会抛出 StopIteration 异常, 表示停止迭代异常
      4. while 循环内部没有处理异常操作, 需要手动添加处理异常操作
      5. for 循环内部自动处理了停止迭代异常, 使用起来更方便, 推荐使用
# yield 生成式
def generator(num):for i in range(num):print("start")yield i # stopprint("next generator")g = generator(100)
print(next(g))
print(next(g))for i in g:print(i)
# 简写
for i in generator(100):print(i)
  • 生成器应用: 斐波那契数列
def fb(num):a, b = 0, 1# 记录生成了几个数字index = 0while index < num:result = aa, b = b, a + byield result # yieldindex += 1f = fb(5)
for i in f:print(i)
# 简写
for i in fb(5):print(i)
  • 深拷贝和浅拷贝 import copy
    • 浅: copy.copy 函数, 浅拷贝最多只拷贝一层
    • 深: copy.deepcopy 函数, 深拷贝可拷贝多层, 直到遇到不可变对象
    • 两种拷贝, 成功都会开辟新的空间存储拷贝的对象, 都不会拷贝不可变对象 (数据安全)

7. 方法

一、4种方法参数 (「位置参数 /* 关键字参数」、不定长参数、缺省参数)

  1. 位置参数顺序必须一致, 和关键字参数混用: 位置参数必须在前面. 因为关键字参数不存在前后顺序
  2. 不定长参数:
    1. *位置传递: def user(*args): 所有参数都会被 args 变量收集, 根据位置顺序合并为一个元祖, args 是 元祖类型. 一般命名为 args
    2. **关键字传递: def user(**kwargs): 参数是 标识符=值 形式的情况下, 所有键值对都会组成字典类型 (注意 key 只能是标识符, 所以不能数字开头). 一般命名为 kwargs (keyword arguments)
  3. 缺省参数: 定义时, 写在后面 def twoSum(self, target: int = 6, /) -> list:
  4. 方法参数里有 /* :
    1. / 之前的参数, 调用时必须都用args方式的位置参数
    2. * 之后的参数, 调用时必须都用kwargs方式的关键字传递 (指定命名调用)
def test1(a, b, /, *, c, d):passtest1(1, 2, c=3, d=4)

二、方法本身作为参数

  1. 本质是计算逻辑的传递, 而非数据的传递
  2. 任何逻辑都可以自行定义并作为函数传入

三、lambda 函数

  1. lambda 关键字和 def 对应, 只不过没有名称和括号, 只能临时使用一次
  2. 语法: lambda 传入参数: 函数体(一行代码)
  3. 函数体只能写一行, 无法写多行代码
  4. 函数赋值给一个变量: dequeue = deque.popleft 调用: greet()

四、实例方法,静态方法,类方法

  1. 实例方法 (方法本身带 self 参数)
    既可以获取构造函数定义的变量,也可以获取类的属性值
    非本类中, 调用实例方法和实例变量, 需要先实例化类对象, 然后才能调用
    本类中, 调用实例方法通过 self.func_name() self 就是本类的实例引用

  2. 静态方法 (需要加 @staticmethod 装饰器)
    不能获取构造函数定义的变量,也不可以获取类的属性
    静态方法不能调用 类变量,类方法,实例变量 及 实例方法, 需要实例化对象, 然后通过对象去调取
    但是实例方法可以调用静态方法, 通过 self.static_func() 调用, 类方法也需要实例化后才能调用静态方法.

  3. 类方法 (需要加 @classmethod 装饰器)
    无需实例化, 不能获取构造函数定义的变量,可以获取类的属性
    在类中, 类方法调用类变量, 通过 cls.cls_param 的方式直接调用

  4. 属性方法 (需要加 @property 装饰器)
    类属性方法无传参且必须有返回值, 实例化对象调用的时候通过调取属性的方式进行调用

  5. 构造函数和析构函数

    1. 构造函数, 实例化自动调用该方法, 一般放些属性及初始化的内容
    2. 析构函数, 类实例被销毁的时自动执行
class Person(): #定义类date = '20201215'               # 类变量def __init__(self, weather = 0):             # self 本类, this对象self.name = 'Stephen'       # 实例变量self._weather = weatherdef __str__(self):return self.date + ' ' + self.namedef info(self):                 # 实例方法self.name='xiaoming'@propertydef weather(self):              # 属性方法print("getting")return self._weather@weather.setterdef weather(self, value):print("setting")if not isinstance(value, int):raise ValueError("weather must be an integer!")           if value < 0 or value > 100:raise ValueError('weather must between 0 ~ 100!')self._weather = value@staticmethod          # 静态方法:校验输入值类型和大小是否符合咱们的类型。def var_str(date_str):year, month, day = tuple(date_str.split("-"))if 0 < int(year) and 0 < int(month) <= 12 and 0 < int(day) < 32:return Trueelse:return False@classmethod                    # 类方法def class_method(cls, date_str):if cls.var_str(date_str):  # 这里是调用静态方法,注意要用 cls.静态方法,原理和实例方法中的self一样,自己可以试试,否则是不能读取的。year, month, day = tuple(date_str.split("-"))return cls(int(year), int(month), int(day))def __del__(self):              # 析构函数,类销毁自动执行print("类销毁的时候就执行")
  1. 拆包
def a(*arg):print(*args) # *args 相当于 print(a, b)def run(**kwargs):#传来的 key = value 类型的实参会映射成kwargs里面的键和值# kwargs是一个字典,将未命名参数以键值对的形式print(kwargs)print("对kwargs拆包")#  此处可以把**kwargs理解成对字典进行了拆包,{"a":1,"b":2}的kwargs字典又# 被拆成了a=1,b=2传递给run1,但是**kwargs是不能像之前*args那样被打印出来看的run1(**kwargs)#print(**kwargs)def run1(a,b): #此处的参数名一定要和字典的键的名称一致print(a,b)
    1. *args作为形参时是用来接收多余的未命名参数,而**kwargs是用来接收key=value这种类型的命名参数,args是元组,kwargs是字典。
    2. *和 ** 在函数体中除了拆包之外,并没有什么卵用。
    3. 装包的含义就是把未命名参数和命名参数分别放在元组或者字典中
  • 类似的有 js 中的解构
import X, { myA as myX, Something as XSomething } from './A'
// X: export default 42
// {}: export const A=42let obj = {a: 1, b: 2};
let {x, y} = obj;
//x undefined
//y undefined
let {a, b} = obj;
//a 1
//b 2
let {b, a} = obj;
//b 2
//a 1
let {a: x, b: y, c: z = {num: 1}} = obj; //a 报错 //b 报错 //x 1 //y 2 
// z 有默认值

五、函数参数 与 闭包 (Closure)

  • 函数参数 (函数可以像普通变量一样作为参数使用)

    • 函数名 存放的是: 函数所在空间的地址
    • 函数名 也可以像普变量一样赋值, 两者等价
    • 函数名() 执行的是函数名背后存放空间地址中的代码
  • 闭包 (Closure 暂时封锁, function closures, 内部函数)

    • 函数用完, 局部变量都会被销毁, 但有时我们需要保留…
      - 闭包就是能够读取其他函数内部变量的函数(函数嵌套)
      - javascript中,只有函数内部的子函数才能读取 局部变量 ,所以闭包可以理解成“定义在一个 函数内部 的函数
    • 闭包的作用: 保存函数内的变量, 不会随着函数调用完而销毁, 提高代码复用性.
      - 在本质上,闭包是将函数内部和函数外部连接起来的桥梁
    • 闭包的定义 (3个):
        1. 函数嵌套的前提下
        1. 内部函数使用了外部函数的变量 (自由变量)
        1. 且外部函数返回了内部函数 (函数被当成对象返回, 闭包则实际上是一个函数的实例,也就是说它是存在于内存里的某个结构体),
      • final: 我们把这个使用外部函数变量内部函数称为闭包
    • 两个关键元素: 闭包意味着同时包括 函数指针环境
    • 关键字 (必须在使用之前声明)
      • nonlocal 非局部变量关键字, 声明是 外部嵌套函数 的变量 (并且不是全局变量)
      • global 全局变量关键字, 如果局部 不声明不修改 全局变量, 也可以不用
    • 支持函数参数赋值的语言一般都支持闭包
def normalFunc(num1):def closure(num2):nonlocal num1 # 只有使用关键字nonlocal后, 修改才会生效.num = num1 + num2print("now value", num)# num1 += 10 # 直接修改外部变量(环境)实际只是内部重新声明了一个num1和外部无关# nonlocal num1 # 必须在所有使用之前声明!! 不能在中途声明num1 += 10return closurefunc = normalFunc(10) # actually: func = (closure + 环境)
func(1) # actually: func() = closure()
func(2)
  • 闭包的原理:
    • 闭包函数相对与普通函数会多出一个 __closure__ 的属性, 里面定义了一个元组用于存放所有的 cell 对象, 每个 cell 对象 (元祖)一一保存了这个闭包中所有的外部变量
printer = make_printer('Foo', 'Bar')  # 形成闭包printer.__closure__   # 返回cell元组 
# (<cell at 0x03A10930: str object at 0x039DA218>, <cell at 0x03A10910: str object at 0x039DA488>)printer.__closure__[0].cell_contents  # 第一个外部变量
# 'Foo'

六、装饰器 (Decorator, 切面作用, 本质是特殊的闭包)

早期函数添加额外功能是这样的: 在函数下方紧接着替换函数签名

def debug(func): # func: 被装饰的目标函数def wrapper():  # 装饰器的本质是闭包, 只不过外部函数入参是函数print "[DEBUG]: enter {}()".format(func.__name__)"""函数执行前"""result = func()"""函数执行后"""return resultreturn wrapperdef say_hello():print "hello!"say_hello = debug(say_hello)  # 使用装饰器装饰函数
  • 装饰器语法糖: @装饰器名称
@debug # 外部函数的名字 (注意一定是闭包), 等于 say_hello = debug(say_hello)
def say_hello():print "hello!"
  • 装饰带有参数的函数
    • 内部函数应该和 被装饰函数 参数一样多
    • 外部函数的 入参函数 也应该和 被装饰函数 一致
  • 装饰带有不定长参数的函数 (特例: 通用装饰器)
    • def inner(*args, **kwargs): fn(*args, **kwargs)
  • 多个装饰器使用: 越靠近函数名的越先包装(靠近的在内层)
  • 带参数的装饰器: 使用时指定参数 @getTime(参数, ...)
    • 装饰器的外部函数只能有一个参数
    • 实际是先执行装饰器函数, 然后再返回装饰器 (中间没有任何执行逻辑)
def decorator(fn, flag): # 错误def inner(num1, num2):if flag == "+":print("addition")elif flag == "-":print("subtraction")result = fn(num1, num2)return resultreturn innerdef logging(flag): # 正确装饰器def decorator(fn): # 外部函数def inner(num1, num2):if flag == "+":print("addition")elif flag == "-":print("subtraction")result = fn(num1, num2)return resultreturn innerreturn decorator # 返回装饰器@loggin("+")
def add(a, b): # 实际: 1. logging("+") 2. add = decorator(add)
  • 类装饰器
    • __call__ 方法
      一个类里面一旦实现了该方法, 那么这个类创建的对象就是一个可调用的对象, 可以像调用函数一样进行调用
class Check(object):def __call__(self, *args, **kwds):print("I'm call method")
c = Check()
c()
  • 类装饰器的定义
class CheckI:def __init__(self, func) -> None: # func = commentself.__fn = funcdef __call__(self, *args: Any, **kwds: Any) -> Any:print("登陆")self.__fn(*args, **kwds) # comment()@CheckI # comment = Check(comment)
def comment():print("发表评论")comment() # comment() 其实就是上面的 c()
"""
登陆
发表评论
"""
  • 带参数的类装饰器
class logging(object):def __init__(self, level='INFO'):self.level = leveldef __call__(self, func): # 接受函数def wrapper(*args, **kwargs):print "[{level}]: enter function {func}()".format(level=self.level,func=func.__name__)func(*args, **kwargs)return wrapper #返回函数@logging(level='INFO')
def say(something):print "say {}!".format(something)
  • 类装饰器总结
    • 想要让类实例对象能够像函数一样调用, 需要在类使用call方法, 把类实例变成可调用对象
    • 类装饰器 装饰 函数功能, 是在call方法里面进行添加的
  • 类装饰器最重要的就是 可继承

七、property 属性

定义property属性有两种方式: 装饰器方式、类属性方式
注意: 属性必须先在 __init__ 里面声明, 不然: "XX" object has no attribute "_XX__age"

  1. 装饰器方式 Decorator
    1. @property 表示把方法当作属性使用, 表示获取属性时会执行下面修饰的方法
    2. 方法名.setter 表示把方法当作属性使用, 表示设置属性时会执行下面修饰的方法
    3. 装饰器方式的 property 属性修饰的方法名一定要一样
class Person:def __init__(self) -> None:self.__age = 0# 装饰器方式@property # @property 表示把方法当作属性使用, 表示获取属性时会执行下面修饰的方法def age(self): # 装饰器方式的 property 属性修饰的方法名一定要一样return self.__age@age.setter # 方法名.setter 表示把方法当作属性使用, 表示设置属性时会执行下面修饰的方法def age(self, new_age):if new_age >= 150:print("???")else:self.__age = new_agep = Person()
# age = p.age()
print(p.age) # 自动调用 @property
p.age = 100 # 自动调用 @setter
  1. 类属性方式 Class
    1. 语法: property属性 = property(获取值方法, 设置值方法)
    2. 第一个参数时获取属性时要执行的方法
    3. 第二个参数时设置属性时要执行的方法
class ClassPerson:"""类属性方式"""def __init__(self) -> None:self.__age = 0def get_age(self):return self.__agedef set_age(self, age):if age >= 150:print("???")else:self.__age = ageage = property(get_age, set_age)

8. 文件

文件的4种操作: 打开、关闭、读、写 常用步骤: open -> read/write -> close
python 内置了文件操作函数

  1. open()
    1. 语法: f = open("python.txt", "r", encoding="UTF-8") # encoding 顺序不是第三位, 只能用关键字参数
      1. name: 文件名或路径名
      2. mode: 文件打开模式 (只读 r、写入 w(原有删除、会创建文件)、追加 a (会创建文件)、etc.)
      3. encoding: 文件编码格式 (推荐使用 UTF-8)
    2. open() 方法返回的是文件对象, 拥有属性和方法
  2. read()
    1. 语法: 文件对象.read(num) # 不填, 表示读取所有数据
    2. readlines() 方法: 一次性读取, 每行数据合成列表
    3. 注意文件指针的位置
    4. readline() 方法: 一次只读取一行
    5. for 遍历: for line in open("README.md", "r"): or for line in f: # for 遍历和 readline() 有关
  3. close() 关闭文件对象
    1. with open 语法: with open("READEME.md", "r") as f: 在 with open 块中对文件进行操作, 结束后自动close文件
  4. write()
    1. mode 必须有 w, f = open(“xx.txt”, “w”) # 在写入模式下文件不存在会自动创建 (反面: x 新建存在会报错)
    2. 语法1: f.write(“hello world”) # 文件写入
      语法2: f.flush() # 内容刷新. close() 内置了flush() // 作用: 多次写入, 一次输出

time.sleep(5) # 5s

9. 异常

  • 处理异常 (异常可以传递)
try:print(name)
except [NameError as e]:print("occur except")print(e) # name 'name' is not definedtry:print(1/0) # ZeroDivisionError: division by zero
except (NameError, ZeroDivisionError) as e:print("ZeroDivision or Name Error")# 完整语法
try:print(1/0)
except Exception as e:print("出现异常, 原因: ", e)
else: # 可选print("没有发生任何异常")
finally: # 可选f.close()
# 简洁语法
import sysfor line in sys.stdin:try:a = line.split()print(int(a[0]) + int(a[1]))except:continue
  • 抛出异常
if current is None:raise ValueError("是你下标过了头")
# or
assert current is not None, "你下标过头了" # 该异常是 AssertionError

10. 模块

  • 只能找到当前目录, 以及子目录的包, 找不到上层目录
  1. 导入语法: [from 模块名] import [模块|类|变量|函数|*] [as 别名]
  • case: from time import time as ti, sleep
  1. 使用语法: 模块名.功能名()
  • case: sleep(0.5)now = ti()
  1. 自定义模块: 每个python 文件都可以作为一个模块, 模块的名字就是 文件名
    1. 自定义模块名必须符合标识符命名规则

注意:

  1. 导入多个模块, 模块内有同名功能时, 调用到的是: 后导入的模块的功能
    1. 可以使用 as 区分同名模块
  2. 测试模块: 导入模块的单元测试要写: if __name__ == "__main__": 因为在导入时会自动调用该模块, 无论是导入其中的函数还是变量都会执行 (__name__ 变量执行本文件时为main, 模块调用时为文件名)

__name__ 变量. 当 Python 解释器读取一个源文件时,它首先定义了一些特殊的变量。在这种情况下,我们关心__name__变量。当你的模块是主程序时, 解释器会将硬编码的字符串分配给"__main__"变量__name__. 当您的模块被另一个模块导入时, 解释器将搜索您的foo.py文件 (以及搜索其他一些变体),并且在执行该模块之前,它会将"foo"导入语句中的名称分配给__name__变量.

__all__ 变量 (列表类型). 当该变量存在时, import * 只能导入这个列表中的元素.
注: __all__ 未限制 单独指定 的方式

11. 下划线

非官方

  • 前置单下划线:_var (仅在内部使用, 变量或方法, 只有约定含义)
  • 后置单下划线:var_ (绕过命名冲突, 规避关键字占用, 只有约定含义)
  • 常量: CONST_VAR (使用全大写, 只有约定含义)
    官方
  • 前置双下划线:__var (私有, 变量会被名称改写 (name mangling), __baz -> _Test__baz 防止变量在子类中被重写, 子类的子类 _ExtendedTest__baz)
  • 前后置双下划线:__var__ (一般 python 内置函数保留)
  • 单下划线:_
    1. 代表不关心, 循环中不需要访问正在运行的索引,可以使用 " _ " 来表示它只是一个临时值: for _ in range(32):.
    2. Python REPL中的一个特殊变量,表示由解释器最近一个表达式的结果. 获取命令行上一条语句执行的结果

12. Typing 模块

Python是一种动态类型语言,这意味着我们在编写代码的时候更为自由,运行时不需要指定变量类型, 但是同时 IDE 也无法像静态类型语言那样分析代码,及时给出相应提示,如字符串的 split() 方法提示.

作用: 帮助 IDE 为我们提供更智能的提示. 特性不会影响语言本身, 是一个规范约束,不是语法限制

  1. Union vs TypeVar
    U = Union[int, str]
    def union_func(arg1: U, arg2: U) -> U:
    union_func(1, “s”) # all right
    result: Any = union_func(1, 2) # correct, but return int? or str?

T = TypeVar("T", int, str)
def typevar_func(arg1: T, arg2: T) -> T:
typevar_func(1, “s”) # error
result: int = typevar_func(1, 2) # correct, and return always int

  1. Optional
    必须跟一个参数, 且只能是一个参数. 给个提示作用, 代表可以不传 (实际必须使用 None 占位)
    def foo_func(arg: Optional[int] = None):
    等效于: def foo_func(arg: int = None):
  • 类中:
class BasicStarship:captain: str = 'Picard'               # 实例变量,有默认值damage: int                           # 实例变量,没有默认值stats: ClassVar[Dict[str, int]] = {}  # 类变量,有默认值
  1. ClassVar
    是 typing 模块的一个特殊类. 向静态类型检查器指示, 不应在类实例上设置此变量

13. Python 并发编程

多线程和多进程两者的 API 几乎一致
![[多进程.png]]

  • 多进程适合 cpu 密集型计算

  • 多线程适合 io 密集型计算

  • 线程池不适合长时间占用

  • 可等待的对象分为三种类型:协程、任务 和 Future.

    • 当遇到可等待对象,进程会发生上下文切换(任务调度)
  • CPU 密集型使用多进程实例:

import math
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
from util.Util import timesumPRIMIES = [112272535095293] * 100def is_prime(n):if n < 2:return Falseif n == 2:return Trueif n % 2 == 0:return Falsesqrt_n = int(math.floor(math.sqrt(n)))for i in range(3, sqrt_n + 1, 2):if n % i == 0:return Falsereturn True@timesum
def single_thread():for number in PRIMIES:# print(is_prime(number))is_prime(number)@timesum
def multi_thread():with ThreadPoolExecutor() as pool:pool.map(is_prime, PRIMIES) # 多线程甚至拖慢了速度@timesum
def multi_process():with ProcessPoolExecutor() as pool:pool.map(is_prime, PRIMIES) # 提升了 6 倍if __name__ == '__main__':single_thread()multi_thread()multi_process()""">>开始计时!
<<耗时 23.292997 s
>>开始计时!
<<耗时 23.495053 s
>>开始计时!
<<耗时 4.086435 s"""

协程 (Coroutine: 协同程序)

  • 在单线程内实现并发
    • 核心原理1: 用一个超级循环 (其实就是while true:) The one loop
    • 核心原理2: 配合 I/O 多路复用原理 (IO时 CPU 可以干其他事情)
  • 单线程异步爬虫, 很多时候是快于多线程的
    • 多线程不同线程调度的切换, 本身是耗费时间的
    • 没有上下文切换的开销, 相对来说更快

协程

import asyncio# 获取事件循环
loop = asyncio.get_event_loop()# 定义协程
async def myfunc(url): # async 说明函数是一个协程await get_url(url) # await 对应 IO, 执行到这里不进行阻塞, 超级循环直接进入下一个程序的执行# 创建task列表
tasks = [loop.create_task(myfunc(url))]# 执行爬虫事件列表
loop.run_until_complete(asyncio.wait(tasks)) # 执行直到完成/ 等待任务的完成# 补充
## 运行
asyncio.run(main())
asyncio.run(asyncio.gather(main(),main2()))
  • 协程异步注意事项:
  1. 要用在异步IO编程中, 依赖的库必须支持异步IO特性

  2. 到达await关键字,发生上下文切换

  3. 不使用 await 函数不会暂定现场,不会再回到该调用点

  4. 当一个协程通过 asyncio.create_task() 等函数被封装为一个 任务, 该协程会被自动调度执行

  5. 通常情况下 没有必要 在应用层级的代码中创建 Future 对象。这是一种特殊的 低层级 可等待对象

信号量 Semaphore

  • 异步IO中使用信号量控制爬虫并发度
    • Semaphore 信号量、旗语
      • 是一个同步对象, 用于保持在 0 至 指定最大值之间的一个计数值
      • 完成一个对该 semaphore 对象的等待 (wait) 时, 该计数值减一 (进入并发处理)
      • 完成一个对该 semaphore 对象的释放 (release) 时, 该计数值加一 (完成 释放)
      • 当计数值为 0, 则线程等待该 semaphore 对象不再能成功, 直至该 semaphore 对象变为 signaled 状态 (为0等待, signaled: 已发信号状态)
      • semaphore 对象的计数值大于 0, 为 signaled 状态, 计数值等于 0, 为 nonsignaled 状态,

信号量

爬虫引用中的 requests 不支持异步, 需要使用 aiohttp

netty

每个eventloop就是1个thread, 每个channel类似于1个协程.
进一步思考, 这跟Linux的epoll模型是否很类似

相关文章:

Python 笔记 (二)

Python Note 2 1. Python 慢的原因2. 三个元素3. 标准数据类型4. 字符串5. 比较大小: 富比较方法 rich comparison6. 数据容器 (支持*混装* )一、允许重复类 (list、tuple、str)二、不允许重复类 (set、dict)1、集合(set)2、字典(dict)3、特殊: 双端队列 deque 三、数据容器的共…...

【商城实战(97)】ELK日志管理系统的全面应用

【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配,乃至运营推广策略,102 章内容层层递进。无论是想…...

3.使用epoll实现单线程并发服务器

目录 1. epoll的概述 2. 多线程与epoll的处理流程 2.1 多线程处理流程 2.2 epoll处理流程 3. epoll与多线程的比较 4. epoll的操作函数 4.1 epoll_create() 4.2 epoll_ctl() 4.3 epoll_wait() 5. 示例代码 6. epoll的工作模式 7. 使用O_NONBLOCK防止阻塞 8.运行代…...

蓝桥杯真题------R格式(高精度乘法,高精度加法)

对于高精度乘法和加法的同学可以学学这几个题 高精度乘法 高精度加法 文章目录 题意分析部分解全解 后言 题意 给出一个整数和一个浮点数&#xff0c;求2的整数次幂和这个浮点数相乘的结果最后四舍五入。、 分析 我们可以发现&#xff0c;n的范围是1000,2的1000次方非常大&am…...

PyCharm操作基础指南

一、安装与配置 1. 版本选择 专业版&#xff1a;支持 Web 开发&#xff08;Django/Flask&#xff09;、数据库工具、科学计算等&#xff08;需付费&#xff09;。 社区版&#xff1a;免费&#xff0c;适合纯 Python 开发。 2. 安装步骤 访问 JetBrains 官网 下载对应版本。…...

21 python __name__ 与 __main__

在办公室里&#xff0c;每个员工都有自己的工牌&#xff0c;上面写着姓名和部门。 一、__name__&#xff1a;模块的名字 Python 模块也有类似的 "工牌"——__name__属性&#xff0c;它记录了模块的身份&#xff1a; 直接运行时 → __name__ "__main__"&…...

NixVis 开源轻量级 Nginx 日志分析工具

NixVis NixVis 是一款基于 Go 语言开发的、开源轻量级 Nginx 日志分析工具&#xff0c;专为自部署场景设计。它提供直观的数据可视化和全面的统计分析功能&#xff0c;帮助您实时监控网站流量、访问来源和地理分布等关键指标&#xff0c;无需复杂配置即可快速部署使用。 演示…...

elementUI el-image图片加载失败解决

是不是&#xff0c;在网上找了一些&#xff0c;都不行&#xff0c;这里一行代码&#xff0c;解决&#xff0c;后端返回图片路径&#xff0c;el-image图片加载失败的问题 解决办法&#xff0c; vue项目里&#xff0c;index.html文件里加一行代码就可 <meta name"refe…...

lxd-dashboard 图形管理LXD/LXC

前言 LXD-WEBGUI是一个完全用AngularJS编写的Web应用程序,无需应用服务器、数据库或其他后端服务支持。只需要简单地托管静态HTML和JavaScript文件,就能立即投入使用。这个项目目前处于测试阶段,提供了直观的用户界面,帮助用户便捷地管理和控制LXD实例。 安装lxd-dashboa…...

C# MemoryStream 使用详解

总目录 前言 在.NET开发中&#xff0c;流&#xff08;Stream&#xff09;是一个用于处理输入和输出的抽象类&#xff0c;MemoryStream是流的一个具体实现&#xff0c;它允许我们在内存中读写数据&#xff0c;就像操作文件一样&#xff0c;而无需涉及磁盘 I/O 操作。尤其适合需…...

(二)万字长文解析:deepResearch如何用更长的思考时间换取更高质量的回复?各家产品对比深度详解

DeepResearch的研究背景 业务背景&#xff1a;用更长的等待时间&#xff0c;换取更高质量、更具实用性的结果 当前AI技术发展正经历从“即时响应”到“深度思考”的范式转变。用户对延迟的容忍度显著提升&#xff0c;从传统200ms的交互响应放宽至数秒甚至数分钟&#xff0c;以…...

Redis场景问题1:缓存穿透

Redis 缓存穿透是指在缓存系统&#xff08;如 Redis&#xff09;中&#xff0c;当客户端请求的数据既不在缓存中&#xff0c;也不在数据库中时&#xff0c;每次请求都会直接穿透缓存访问数据库&#xff0c;从而给数据库带来巨大压力&#xff0c;甚至可能导致数据库崩溃。下面为…...

数据结构(并查集,图)

并查集 练习版 class UnionFindSet { public:void swap(int* a, int* b){int tmp *a;*a *b;*b tmp;}UnionFindSet(size_t size):_ufs(size,-1){}int UnionFind(int x){}void Union(int x1, int x2){}//长分支改为相同节点int FindRoot(int x){}bool InSet(int x1, int x2)…...

深度学习篇---断点重训模型部署文件

文章目录 前言一、断点重训&#xff08;Checkpoint&#xff09;文件1. 动态图&#xff08;DyGraph&#xff09;模式.pdparams 文件.pdopt 文件.pdscaler 文件.pdmeta 或 .pkl 文件 2. 静态图&#xff08;Static Graph&#xff09;模式.pdparams 和 .pdopt 文件.ckpt 文件 3. 恢…...

chromem-go + ollama + bge-m3 进行文档向量嵌入和查询

Ollama 安装 https://ollama.com/download Ollama 运行嵌入模型 bge-m3:latest ollama run bge-m3:latestchromem-go 文档嵌入和查询 package mainimport ("context""fmt""runtime""github.com/philippgille/chromem-go" )func ma…...

运维面试题(十一)

1.如果一个硬盘 IO 时阻塞了&#xff0c;会发生什么情况&#xff1f; 进程/线程挂起&#xff1a;发起I/O操作的进程或线程会被操作系统置为阻塞状态&#xff08;等待状态&#xff09;&#xff0c;直到I/O完成。CPU资源释放&#xff1a;阻塞的线程会让出CPU&#xff0c;操作系统…...

深度学习中常见的专业术语汇总

本硕博都是搞机械的匠人&#xff0c;当然也想做一下交叉学科的东西&#xff0c;蹭一下人工智能的热点。虽然世界是个草台班子&#xff0c;但是来都来了&#xff0c;咱也要把这场戏演好。 记得之前网上爆料有位大学生发了很多水文&#xff0c;对&#xff0c;是交叉学科的&#x…...

人工智能赋能医疗:开启智慧医疗新时代

在当今数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的速度渗透到各个行业&#xff0c;其中医疗领域更是成为AI技术大放异彩的重要舞台。从疾病诊断到治疗方案制定&#xff0c;从医疗影像分析到药物研发&#xff0c;AI正在为传统医疗带来…...

stable diffusion 本地部署教程 2025最新版

前提&#xff1a; 需要环境 git git下载地址Git - Downloading Package ​ 直接装即可 python3.10.6 下载地址 Python Release Python 3.10.6 | Python.org ​ 记得python环境一定要3.10.6&#xff01;&#xff01;&#xff01; 第一个版本 项目地址https://github.…...

[Mac]利用Hexo+Github Pages搭建个人博客

由于我这台Mac基本没啥环境&#xff0c;因此需要从零开始配置&#xff0c;供各位参考。 注意⚠️&#xff1a;MacBook (M4)使用/bin/zsh作为默认Shell&#xff0c;其对应的配置文件为~/.zshrc 参考文档&#xff1a; HEXO系列教程 | 使用GitHub部署静态博客HEXO | 小白向教程 文…...

罗杰斯特回归

定义 逻辑回归其实就是原来的线性回归加了激活函数&#xff0c;这个函数其实就是sigmoid函数&#xff0c;把一个回归的连续数值压缩到了0到1的空间&#xff0c;其实只要有函数能够满足把数值压缩到0,1之间就可以&#xff08;因为0到1之间的数值就是概率值&#xff09; 对于分类…...

27_promise

插入一下前端助手测试&#xff0c;顺手可以用来做安全 promise promise 是一个es6新增的语法 汉语&#xff1a;承诺的意思 作用:是专门用来解决回调地狱!!!! 什么是回调函数&#xff1f; <script>// 回调函数 callback回调// 就是把函数A当作参数传递到函数B中// 在函…...

【机械视觉】C#+VisionPro联合编程———【六、visionPro连接工业相机设备】

【机械视觉】C#VisionPro联合编程———【六、visionPro连接工业相机设备】 目录 【机械视觉】C#VisionPro联合编程———【六、visionPro连接工业相机设备】 前言&#xff1a; 连接步骤说明 一. 硬件连接 支持的相机接口类型&#xff1a; 连接步骤 2. 软件配置 Visio…...

红宝书第十九讲:详解JavaScript的Fetch API与Ajax请求

红宝书第十九讲&#xff1a;详解JavaScript的Fetch API与Ajax请求 资料取自《JavaScript高级程序设计&#xff08;第5版&#xff09;》。 查看总目录&#xff1a;红宝书学习大纲 一、基本概念&#xff1a;为什么需要Fetch&#xff1f; Fetch API是浏览器提供的现代网络请求工…...

【深度学习新浪潮】具身智能及其发展前景分析

一、具身智能的定义 具身智能(Embodied Intelligence) 是指通过物理载体(如机器人)与环境实时交互,实现感知、决策与行动闭环的智能系统。其核心在于将人工智能与物理实体结合,强调“智能源于身体与环境的互动”,而非仅依赖虚拟算法。具身智能的典型特征包括多模态感知…...

练习题:111

目录 Python题目 题目 题目分析 需求理解 关键知识点 实现思路分析 代码实现 代码解释 指定文件路径和名称&#xff1a; 定义要写入的内容&#xff1a; 打开文件并写入内容&#xff1a; 异常处理&#xff1a; 输出提示信息&#xff1a; 运行思路 结束语 Python题…...

第三次作业

1、将你的虚拟机的网卡模式设置为nat模式&#xff0c;给虚拟机网卡配置三个主机位分别为100、200、168的ip地址 首先将虚拟机在vmware编辑里将网卡模式改为nat 然后用nmcli c mod ens160 ipv4.addresses 192.168.254.100 nmcli c mod ens160 ipv4.addresses 192.168.254.200…...

Oracle数据库数据编程SQL<3.1 PL/SQL 匿名块 及 流程控制中的条件判断、循环、异常处理和随机函数应用>

PL/SQL部分 在SQL的基础上增加了一些过程化的控制语句。 过程化控制语句包括&#xff1a;类型定义、判断、循环、游标、异常处理&#xff08;例外处理&#xff09; 目录 PL/SQL匿名块 一、匿名块基本结构 1、匿名块由三个部分组成&#xff1a; 2、注意事项&#xff1a; …...

CEF 给交互函数, 添加控制台是否显示交互参数log开关

CEF 控制台添加一函数,枚举 注册的供前端使用的CPP交互函数有哪些 CEF 多进程模式时,注入函数,获得交互信息-CSDN博客 这两篇文章,介绍了注入函数,在控制台中显示 各自提供的交互函数信息。 有些场景下,我们还需要更详细的信息,比如想知道 彼此传递的参数, 如果每次调…...

如何用 Postman 正确传递 Date 类型参数,避免服务器解析错误?

如何在 Postman 中传递 Date 类型参数。调试工具如何模拟发送用户端的当前时间呢&#xff1f; Postman 传递 Date 类型参数教程...

从代码学习深度学习 - 含并行连结的网络(GoogLeNet)PyTorch版

文章目录 前言一、GoogLeNet的理论基础1.1 背景与创新点1.2. Inception模块的工作原理二、完整代码实现与解析2.1. 环境准备与工具函数2.2. 数据加载 - Fashion-MNIST2.3. Inception模块设计2.4. GoogLeNet完整模型2.5. 训练函数2.6. 运行训练三、训练结果与分析3.1. 性能分析3…...

进程Kill杀死后GPU显存没有释放仍然被占用,怎么杀死僵尸进程

参考链接&#xff1a; https://blog.csdn.net/qq_37591986/article/details/131118109 使用下面的命令&#xff1a; fuser -v /dev/nvidia0 | awk {print $0} | xargs kill -9一般来说他会杀掉整个用户的所有进程。...

Deepseek API+Python 测试用例一键生成与导出 V1.0.3

** 功能详解** 随着软件测试复杂度的不断提升,测试工程师需要更高效的方法来设计高覆盖率的测试用例。Deepseek API+Python 测试用例生成工具在 V1.0.3 版本中,新增了多个功能点,优化了提示词模板,并增强了对文档和接口测试用例的支持,极大提升了测试用例设计的智能化和易…...

【字符设备驱动开发–IMX6ULL】(一)简介

【字符设备驱动开发–IMX6ULL】&#xff08;一&#xff09;简介 一、Linux驱动与裸机开发区别 1.裸机驱动开发回顾 ​ 1、底层&#xff0c;跟寄存器打交道&#xff0c;有些MCU提供了库。 spi.c&#xff1a;主机驱动&#xff08;换成任何一个设备之后只需要调用此文件里面的…...

MaxKB 如何通过Nginx修改浮框提示文字

在使用MaxKB做第三方嵌入的时候&#xff0c;总会有想Diy前端样式的场景&#xff0c;下面就通过Nginx的方式&#xff0c;实现浮框样式的改变。 一、效果对比 修改前&#xff1a; 修改后&#xff1a; 前后对比&#xff1a; 修改了提示文字。去掉了图标后面的白框 下面讲一下该…...

中小型企业网络的搭建

1.1 网络逻辑拓扑、布线方案的设计 1.1.1 网络设计依据 网络设计应遵循以下基本原则&#xff1a; 高效性&#xff1a;确保网络架构能够支持企业日常业务的高效运行。 可靠性&#xff1a;采用冗余设计&#xff0c;确保网络的高可用性&#xff0c;避免单点故障。 可扩展性…...

第二卷:海盐城血战(37-72回)正反人物群像

第二卷&#xff1a;海盐城血战&#xff08;37-72回&#xff09;正反人物群像 核心矛盾&#xff1a;寒门军事崛起 → 内部倾轧 → 制度性腐败 主题&#xff1a;通过人物群像展现寒门胜利的虚幻性与权力异化的必然性 一、正派阵营&#xff08;寒门抗争势力&#xff09; 1. 刘裕…...

qt之使用redis与其他程序(python)交互同通信

一、前言 有需求&#xff0c;趁热调试出了嵌入式系统的算法环境安装和远程桌面以及一些其他的之前一直未调试出搁置的功能&#xff0c;趁热继续调试进阶功能redis通信&#xff0c;redis与sqlite各有千秋&#xff0c;redis可以作为在嵌入式系统下多个程序之间相互通信的中间件&…...

Pycharm(七):几个简单案例

一.剪刀石头布 需求&#xff1a;和电脑玩剪刀石头布游戏 考察点&#xff1a;1.随机数&#xff1b;2.判断语句 import random # numrandom.randint(1,3) # print(num) # print(**30) #1.录入玩家手势 playerint(input(请输入手势&#xff1a;&#xff08;1.剪刀 2.石头 3&…...

05.AI搭建preparationの(transformers01)BertTokenizer实现分词编码

一、下载 bert-base-chinese镜像下载 二、简介作用&#xff1a; 模型每个参数占用的字节大小模型大小模型大小层数头数GPT-14 个字节的 FP32 精度浮点数117M446MB1212GPT-22 个字节的 FP161.5亿到1.75亿0.5GB到1.5GB4816GPT-32 个字节的 FP161.75万亿&#xff08;17500亿&a…...

Perl 环境安装指南

Perl 环境安装指南 引言 Perl是一种广泛使用的解释型、动态编程语言,以其强大的文本处理能力和灵活性著称。本文将为您详细介绍Perl环境的安装过程,包括系统要求、安装步骤以及注意事项。 系统要求 在安装Perl之前,请确保您的计算机满足以下基本要求: 操作系统:Window…...

Visual Studio中创建和配置设置文件(Settings.settings) - 详细步骤指南——待调试

#在Visual Studio中创建和配置设置文件(Settings.settings) - 详细步骤指南 在Visual Studio中创建和配置应用程序设置文件&#xff0c;用于保存用户上次输入的值。 第一步&#xff1a;添加设置文件 1. **打开你的项目**&#xff1a;在Visual Studio中打开你的AutoCAD插件项目 …...

Nginx的时钟精度陷阱:request_time与upstream_response_time差异分析

在elasticsearch 采集nginx日志分析的场景下发现&#xff0c; request_time 小于upstream_response_time &#xff0c;于是才有了这边文章。 在 Nginx 中&#xff0c;upstream_response_time 和 request_time 使用不同的系统时钟和精度机制来记录时间&#xff0c;这可能导致 u…...

参加李继刚线下活动启发:未来提示词还会存在吗?

上周六&#xff0c;我参加了李继刚老师组织的线下活动。 现场干货满满&#xff0c;尤其是关于 AI 时代提示词的价值、与 AI 沟通的艺术等话题&#xff0c;李老师的分享如同醍醐灌顶&#xff0c;让我对 AI 人机协作有了更深的理解。 将几点核心收获整理出来&#xff0c;与大家…...

C++作用域辨识详解

在 C 中&#xff0c;作用域&#xff08;Scope&#xff09;定义了变量、函数、类等标识符的可见性和生命周期。理解作用域对于编写清晰、高效的代码至关重要。以下是 C 中作用域的详细分类和说明。 1. 全局作用域&#xff08;Global Scope&#xff09; 全局作用域是指在所有函…...

MYTOOL-记事本

一、前言 目录 1.原型设计 2.程序实现 3.最终界面说明 二、环境 windows10 每个软件工具前期会设计大概的原型&#xff0c;我设计的原型工具使用Axure RP9&#xff0c;很不错的一个设计工具 三、正文 1.原型设计 2.程序实现 3.最终界面说明 四、结语...

混合知识表示系统框架python示例

前文我们已经深入学习了框架表示法、产生式规则和一阶谓词逻辑,并对它们进行了深度对比,发现它们在不同的应用场景下各有优缺点。 一阶谓词逻辑适合复杂逻辑推理场景,具有数学定理证明、形式化系统规范的优点;产生式规则适合动态决策系统,支持实时决策(如风控、诊断),规…...

Vue2——常用指令总结、指令修饰符、v-model原理、computed计算属性、watch监听器、ref和$refs

文章目录 一、概念理解二、指令1. 常用内置指令总结2. 常用指令修饰符3. 自定义指令4. v-model原理表单类组件封装 三、补充1. computed计算属性2. watch监视器3. ref和$refs 一、概念理解 【事件处理函数】 事件处理函数应该写到一个跟data同级的配置项&#xff08;methods&a…...

2025-3-29算法打卡

一&#xff0c;回文判定 1.题目描述&#xff1a; 题目描述 给定一个长度为 nn 的字符串 SS。请你判断字符串 SS 是否回文。 输入描述 输入仅 11 行包含一个字符串 SS。 1≤∣S∣≤1061≤∣S∣≤106&#xff0c;保证 SS 只包含大小写、字母。 输出描述 若字符串 SS 为回…...

【网络编程】搭建一个简单的UDP通信服务器和客户端

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:网络编程 ⚙️操作环境:VS Code (操作系统:Ubuntu 22.04 server 64bit) 目录 搭建UDP服务器 搭建UDP客户端 其余工程文件 主函数文件Main.cc 日志打印文件Log.hpp Makefile文件 结语 搭建UDP服务器 搭建UDP服务器的主要流…...