#rsa.md

在Python中,变量是动态类型的,

这意味着它们不需要提前声明类型,而是根据赋值的值自动确定类型,并且可以随时改变类型。我们可以用一个简单的例子来理解:


1. 变量的本质:标签与对象

在Python中,变量就像是一个"标签",它指向内存中的某个对象(值)。当变量被赋值时,它实际上是在告诉这个标签:"现在你要指向这个对象"。如果变量被重新赋值,它就会指向一个新的对象。

示例:
复制代码

Python

编辑

复制代码
# 初始赋值:a 是一个整数
a = 5
print(type(a))  # 输出: <class 'int'>

# 重新赋值:a 变成浮点数
a = 5 / 3  # 在Python中,除法(/)的结果是浮点数
print(type(a))  # 输出: <class 'float'>

# 再次赋值:a 变成字符串
a = "hello"
print(type(a))  # 输出: <class 'str'>

解释:

  • a = 5:变量 a 被贴上标签 int(整数)。
  • a = 5 / 35/3 的结果是 1.666...,所以 a 现在指向一个 float(浮点数)对象。
  • a = "hello"a 现在指向一个 str(字符串)对象。

2. 动态类型的优点

Python的动态类型让编程更灵活,不需要提前声明类型,代码更简洁。例如:

  • 快速开发:可以直接写代码,无需关心类型声明。
  • 适应性强:同一个变量可以处理不同类型的数据,适合多种场景。
对比静态类型语言(如Java):
复制代码

Java

编辑

复制代码
// Java中必须声明类型,且不能随意更改
int a = 5;       // a 是整数
// a = "hello"; // 错误!Java不允许将字符串赋值给整数变量

而在Python中,这样的操作是合法的,变量类型可以随时改变。


3. 如何检查变量类型?

使用内置函数 type() 可以查看变量当前的类型:

复制代码

Python

编辑

复制代码
a = 5
print(type(a))  # 输出: <class 'int'>

a = "hello"
print(type(a))  # 输出: <class 'str'>

4. 常见误区与注意事项

  • 变量名命名规则

    • 只能包含字母、数字和下划线(如 my_var, _var, var123)。
    • 不能以数字开头(如 1var 是错误的)。
    • 不能使用Python保留字(如 if, for, while 等)。
  • 动态类型的风险

    • 运行时错误 :如果变量类型改变后,使用了不兼容的操作,会抛出错误。例如:

      复制代码

      Python

      编辑

      复制代码
      a = "10"
      a = a + 5  # 错误!字符串和整数不能直接相加

      需要显式转换类型:

      复制代码

      Python

      编辑

      复制代码
      a = int("10")  # 将字符串转为整数
      a = a + 5      # 现在可以正常相加

5. 动态类型的工作原理

Python内部通过引用计数管理内存。每个对象都有一个引用计数,当变量指向新对象时,旧对象的引用计数减少,如果没有其他引用指向它,就会被垃圾回收。

示例:
复制代码

Python

编辑

复制代码
a = [1, 2, 3]  # 列表对象被创建,引用计数为1
b = a          # b也指向同一个列表,引用计数变为2
a = "hello"    # a现在指向新对象,旧列表的引用计数减到1

6. 练习:动手试试看!

尝试以下代码,观察变量类型的变化:

复制代码

Python

编辑

复制代码
x = 100
print(type(x))  # 输出: int

x = x / 2
print(type(x))  # 输出: float

x = str(x)
print(type(x))  # 输出: str

x = [1, 2, 3]
print(type(x))  # 输出: list

总结

  • 变量是动态类型的:类型由赋值决定,可以随时改变。
  • 变量本质是标签:指向内存中的对象,对象有类型,变量只是引用。
  • 灵活但需注意风险:动态类型让代码更简洁,但需要避免类型错误。



在 Python 和 SageMath 中,

range() 函数

的设计遵循 左闭右开区间 (即包含起始值,但不包含终止值)。因此,range(2, 10) 生成的整数序列是:

复制代码

Text

编辑

复制代码
2, 3, 4, 5, 6, 7, 8, 9

为什么没有包含 10?

这是因为 range(start, stop) 的规则是:

  • 起始值 start 被包含 (即从 start 开始)。
  • 终止值 stop 不被包含 (即在 stop 之前结束)。

设计原理

  1. 与 C/Java 等语言的循环逻辑一致

    在 C 或 Java 中,for (i = start; i < stop; i++) 的循环会从 start 开始,直到 i 小于 stop 时停止。Python 的 range(start, stop) 模拟了这种行为,使得开发者更容易迁移代码逻辑。

  2. 避免重复边界值

    如果 stop 被包含,那么在连续的区间划分中容易产生重叠。例如:

    • range(0, 10)range(10, 20) 会无缝衔接(前者到 9,后者从 10 开始)。
    • 如果 stop 被包含,则需要额外处理边界问题(如 range(0, 10) 到 10,range(10, 20) 从 11 开始,导致断层)。
  3. 历史习惯与简洁性

    Python 的早期版本(如 Python 2)中,range() 返回的是一个列表,而 xrange() 是惰性生成器。左闭右开的设计保持了一致性,并且在数学和编程中广泛被接受(例如数组索引从 0 开始,range(len(list)) 能正确遍历所有元素)。


如何包含终止值?

如果希望生成的列表包含 stop 值,只需将 stop 参数增加 1:

复制代码

Python

编辑

复制代码
# 包含 10 的写法
list(range(2, 11))  # 输出 [2, 3, 4, 5, 6, 7, 8, 9, 10]

其他示例说明

  1. 正向步长(默认步长为 1)

    复制代码

    Python

    编辑

    复制代码
    range(1, 4)       # 输出 [1, 2, 3](不包含 4)
    range(5, 10, 2)   # 输出 [5, 7, 9](不包含 10)
  2. 负向步长

    复制代码

    Python

    编辑

    复制代码
    range(10, 2, -1)  # 输出 [10, 9, 3](不包含 2)

知识库支持

根据你的知识库内容:

  • 资料 [2] 明确指出:range(1,4) 会生成 [1, 2, 3],排除 4
  • 资料 [4][5] 强调 range(a, b) 返回的是 [a, a+1, ..., b-1]
  • 资料 [9] 也提到 range(10) 生成 [0, 1, ..., 9],不包含 10



在 Python 中,

类(class) 是一种强大的工具,

它允许你定义自己的数据类型,将数据和操作数据的方法组织在一起。下面我们将通过一个简单的例子来解释这段代码,并逐步为你讲解。


1. 类的定义

复制代码

Python

编辑

复制代码
class Evens(list):
    def __init__(self, n):
        self.n = n
        list.__init__(self, range(2, n+1, 2))
    
    def __repr__(self):
        return "Even positive numbers up to n."
1.1 类名与继承
  • class Evens(list):
    定义了一个名为 Evens 的类,并让它继承自 list
    继承 意味着 Evens 是一个"扩展版的列表",它可以直接使用列表的所有功能(比如通过索引访问元素),同时还可以添加自己的功能。
1.2 初始化方法 __init__
  • def __init__(self, n):
    这是类的构造函数 ,当创建 Evens 对象时会自动调用。
    • self.n = n:将传入的参数 n 存储为对象的属性 n
    • list.__init__(self, range(2, n+1, 2)):调用父类 list 的构造函数,用 range(2, n+1, 2) 生成的偶数列表初始化这个对象。
      • range(2, n+1, 2):从 2 开始,每次加 2,直到不超过 n。例如,n=10 时生成 [2,4,6,8,10]
1.3 字符串表示方法 __repr__
  • def __repr__(self):
    定义了当打印对象或交互式解释器显示对象时的字符串形式。
    • return "Even positive numbers up to n.":返回固定的描述信息。

2. 创建对象

复制代码

Python

编辑

复制代码
e = Evens(10)
  • 调用 Evens 的构造函数,传入 n=10
  • 此时,e 是一个 Evens 类的对象,它本质上是一个列表,包含 [2,4,6,8,10]

3. 使用对象

3.1 打印对象
复制代码

Python

编辑

复制代码
e
  • 输出:Even positive numbers up to n.
    这是因为 __repr__ 方法定义了对象的默认显示方式。
3.2 查看底层列表
复制代码

Python

编辑

复制代码
list(e)
  • 输出:[2, 4, 6, 8, 10]
    list(e) 会强制将 e 转换为普通列表,从而显示所有元素。
3.3 访问属性和元素
复制代码

Python

编辑

复制代码
e.n  # 输出: 10
e[2]  # 输出: 6
  • e.n:访问对象的属性 n(即传入的 10)。
  • e[2]:像普通列表一样通过索引访问元素(第 3 个元素是 6)。

4. 为什么需要类?

类的核心思想是将数据和操作数据的方法封装在一起。在这个例子中:

  • 数据 :偶数列表和最大值 n
  • 方法:初始化列表、定义显示方式。

通过类,你可以:

  1. 复用代码 :只需定义一次类,就可以创建多个对象(如 Evens(10)Evens(20))。
  2. 简化逻辑:将复杂的逻辑(如生成偶数列表)隐藏在类内部,外部只需关注如何使用。

5. 类比理解

假设你要做一个"自动装水的杯子":

  • :杯子的设计图,规定了杯子的容量、材质等。
  • 对象:根据设计图制造的具体杯子(比如容量 10ml 的杯子)。
  • 方法:杯子的功能(比如装水、倒水)。
  • 属性 :杯子的特性(比如当前水量 n)。

在这个例子中,Evens 就是"设计图",e 是根据设计图制造的"杯子",它能自动装入偶数列表,并提供查看水量(n)和取水(索引访问)的功能。


6. 总结

  • 类(class) 是模板,对象(object) 是实例。
  • 继承Evens 拥有 list 的所有功能。
  • __init__ 初始化对象,__repr__ 定义对象的显示方式。
  • 属性和方法 让数据和操作更清晰、更易维护。

通过这种方式,你可以用类来组织代码,让复杂的程序更简洁、更易读!




我们用最简单的大白话,结合日常生活的例子,来彻底理解

__init__ 方法和类的初始化过程。


1. 类和对象是什么?

就像是一个"模板"或"设计图",对象 是根据这个模板造出来的"实物"。

比如:

  • :汽车的设计图(规定了汽车的颜色、型号、发动机等)。
  • 对象:根据设计图造出的具体汽车(比如一辆红色的特斯拉 Model 3)。

2. __init__ 是什么?

__init__ 就是类的"装修工"------当你用设计图造房子(创建对象)时,它会自动帮你完成一些基础装修工作(比如铺地板、装水管)。
关键点

  • 每次创建对象时,__init__ 会自动运行一次。
  • 它的作用是给对象设置初始状态(比如给房子装好地板、门、窗户)。

3. 举个生活中的例子:买手机

假设你去手机店买手机,手机的"设计图"是一个类,具体买的手机是对象。

复制代码

Python

编辑

复制代码
class Phone:
    def __init__(self, color, brand):
        self.color = color  # 手机颜色
        self.brand = brand  # 手机品牌
  • __init__ 的作用:当你买手机时,店员会问你"要什么颜色?"和"要什么品牌?",然后根据你的回答设置手机的颜色和品牌。
  • self 是什么self 就是你要买的这台具体手机(比如你的红色iPhone)。

4. 回到你的代码:Evens

复制代码

Python

编辑

复制代码
class Evens(list):
    def __init__(self, n):
        self.n = n  # 记录用户传入的最大值
        list.__init__(self, range(2, n+1, 2))  # 用偶数列表初始化这个对象
  • __init__ 的作用 :当你创建 Evens 对象时(比如 Evens(10)),__init__ 会自动:
    1. 把用户传入的 n=10 存起来(self.n = 10)。
    2. range(2, 10+1, 2) 生成一个偶数列表 [2,4,6,8,10],并把这个列表变成 Evens 对象。

5. range(2, n+1, 2) 为什么用 n+1

  • range(start, stop, step) 的规则 :从 start 开始,每次加 step直到小于 stop

  • 例子range(2, 10+1, 2) 等价于 range(2, 11, 2),生成的数字是:

    复制代码

    Text

    编辑

    复制代码
    2 → 4 → 6 → 8 → 10(因为 10 < 11,但 12 不小于 11,所以停止)
  • 如果不用 n+1 会怎样?
    如果写成 range(2, 10, 2),生成的列表是 [2,4,6,8],会漏掉 10


6. 创建对象时发生了什么?

复制代码

Python

编辑

复制代码
e = Evens(10)  # 创建 Evens 对象
  • 步骤
    1. 调用 Evens 类的 __init__ 方法。
    2. n=10 传给 __init__
    3. self.n = 10:记录最大值为 10。
    4. list.__init__(self, [2,4,6,8,10]):把列表 [2,4,6,8,10] 变成 e 对象。

7. 使用对象时发生了什么?

复制代码

Python

编辑

复制代码
print(e)       # 输出 "Even positive numbers up to n."
print(list(e)) # 输出 [2,4,6,8,10]
print(e.n)     # 输出 10
print(e[2])    # 输出 6
  • print(e) :调用 __repr__ 方法,返回预设的字符串。
  • list(e) :把 e 对象转成普通列表,显示所有元素。
  • e.n :访问对象存储的属性 n(即 10)。
  • e[2]:像普通列表一样通过索引访问元素(第 3 个元素是 6)。

8. 总结:一句话记住 __init__

__init__ 就是类的"装修工",在创建对象时自动运行,负责设置对象的初始状态。


9. 其他例子:买披萨

复制代码

Python

编辑

复制代码
class Pizza:
    def __init__(self, size, toppings):
        self.size = size  # 披萨尺寸
        self.toppings = toppings  # 配料
  • 创建对象

    复制代码

    Python

    编辑

    复制代码
    my_pizza = Pizza("大号", ["芝士", "蘑菇"])
    print(my_pizza.size)       # 输出: 大号
    print(my_pizza.toppings)   # 输出: ['芝士', '蘑菇']
  • __init__ 的作用:当你点披萨时,店员会问"要多大?"和"要加什么配料?",然后根据你的回答设置披萨的尺寸和配料。


10. 最后一句话

__init__ 就是让对象"出生时"自动完成的一系列准备工作,比如设置属性、初始化数据,这样你就能直接使用对象了。




我们来一步一步用生活中的例子解释

为什么需要 e = Evens(10),而不是直接用 n = 10


1. 什么是类?什么是对象?

  • 是"模板"或"设计图",它定义了某种类型的数据和操作这些数据的方法。
  • 对象 是根据这个模板"制造出来"的具体实例,每个对象都有自己的属性和行为。

举个例子

  • :汽车的设计图(规定了汽车的颜色、型号、发动机等)。
  • 对象:根据设计图造出的具体汽车(比如一辆红色的特斯拉 Model 3)。

2. 为什么不能直接用 n = 10

直接写 n = 10 只是一个普通的变量赋值,它只能存储数字 10,而 可以做更多事情!

2.1 类能封装数据和行为
复制代码

Python

编辑

复制代码
e = Evens(10)
  • e 是一个 对象 ,它不仅存储了 n = 10,还自动帮你生成了一个偶数列表 [2,4,6,8,10]
  • 你可以像用列表一样用它(比如 e[2] 访问第3个元素),还能访问它的属性 e.n(即 10)。
2.2 直接用 n = 10 的局限性

如果只写 n = 10,你需要手动做很多事:

复制代码

Python

编辑

复制代码
n = 10
evens_list = list(range(2, n+1, 2))  # 手动生成偶数列表
print(evens_list)  # [2,4,6,8,10]
print(n)  # 10
  • 问题 :每次用都要重复写代码,而且数据和功能是分离的(nevens_list 是两个变量)。

3. 类的好处:把数据和功能打包在一起

用类 Evens,你可以:

  1. 自动初始化数据 :传入 n=10,类会自动帮你生成偶数列表。

  2. 直接访问数据和功能

    复制代码

    Python

    编辑

    复制代码
    e = Evens(10)
    print(e)         # 自动显示描述信息(通过 __repr__)
    print(list(e))   # 查看底层列表
    print(e.n)       # 访问属性
    print(e[2])      # 像列表一样操作

4. 生活中的类比:工具 vs. 工具的具体实例

  • 就像"工具的设计图"(比如"锤子的设计图")。
  • 对象 是根据设计图制造出的具体工具(比如"一把红色的锤子")。
场景

你想要一把锤子钉钉子。

  • 直接写 n = 10:就像你直接拿一块铁,自己动手敲打成锤子。虽然能用,但过程复杂,效率低。
  • 用类 Evens :就像你直接去商店买锤子,商店已经根据你的需求(比如"锤头大小")制造好了锤子。你只需要说:"我要一把锤子,锤头大小是10厘米。"(e = Evens(10))。

5. 类的扩展性:未来可以添加更多功能

假设未来你想让 Evens 对象支持更多功能,比如:

  • 计算偶数的平均值。
  • 判断某个数字是否在偶数列表中。
  • 添加缓存机制避免重复计算。

用类的方式,你可以轻松扩展这些功能,而不需要重写所有代码。


6. 总结:一句话记住类和对象

  • 是"模板",对象 是"实例"。
  • 直接用 n = 10 只能存储数据,用类 可以把数据和操作数据的功能打包在一起,让代码更简洁、更强大。

7. 动手试试看

尝试运行以下代码,观察结果:

复制代码

Python

编辑

复制代码
e = Evens(10)
print(e)         # 输出描述信息
print(list(e))   # 输出底层列表 [2,4,6,8,10]
print(e.n)       # 输出 10
print(e[2])      # 输出 6

你会发现,e 是一个既像列表又像对象的"多功能工具"!




__repr__ 是 Python 中的一个特殊方法(Magic Method)

,用于定义一个对象的"官方"字符串表示。它的主要作用是:


1. __repr__ 的核心功能

  • 返回一个字符串 ,这个字符串应该能够:
    • 准确描述对象(尤其是调试时)。
    • 尽可能完整地包含对象的信息
    • 如果可能的话,通过 eval() 重新构造对象 (即 eval(repr(obj)) == obj)。

2. __repr__ 的使用场景

  • 调试和开发 :当你在交互式解释器中直接输入对象名,或者用 repr() 函数时,会调用 __repr__
  • 日志记录:需要记录对象的完整信息时。
  • 序列化 :某些情况下,可以通过 __repr__ 的返回值重新生成对象(虽然不推荐依赖这种方式)。

**3. __repr__ vs __str__

特性 __repr__ __str__
调用方式 repr(obj) 或交互式解释器直接输入 obj str(obj)print(obj)
目的 生成开发者友好的字符串(调试用) 生成用户友好的字符串(展示用)
准确性 必须准确,通常可评估为对象 可以简化,不一定能评估为对象
默认行为 返回 <类名 object at 内存地址> 调用 __repr__ 的结果

4. 示例:自定义类的 __repr__

复制代码

Python

编辑

复制代码
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point(x={self.x!r}, y={self.y!r})"

# 使用
p = Point(3, 4)
print(repr(p))  # 输出: Point(x=3, y=4)
print(str(p))   # 输出: Point(x=3, y=4)(因为 __str__ 默认调用 __repr__)
  • __repr__ 的返回值"Point(x=3, y=4)" 是一个有效的 Python 表达式,可以通过 eval(repr(p)) 重新生成对象。
  • !r 的作用 :确保 self.xself.y 的值用 repr() 表示(比如字符串会加引号)。

5. 为什么需要 __repr__

5.1 默认的 __repr__ 不够友好

如果不自定义 __repr__,Python 会返回类似 <__main__.Point object at 0x000002...> 的字符串,这种信息对调试帮助不大。

5.2 示例:自定义 __repr__ 后的效果
复制代码

Python

编辑

复制代码
class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f"User(name={self.name!r}, age={self.age!r})"

user = User("Alice", 30)
print(repr(user))  # 输出: User(name='Alice', age=30)
print(user)        # 输出: User(name='Alice', age=30)
  • 调试时 :直接看 User(name='Alice', age=30) 比看内存地址更有意义。
  • 可评估性eval(repr(user)) 会生成一个新的 User 对象(假设类在当前环境中存在)。

6. 常见误区

6.1 __repr__ 必须返回有效的 Python 表达式吗?
  • 理想情况 :是的,这样可以通过 eval() 重新构造对象。

  • 实际情况 :不一定,但应尽可能接近有效表达式。例如:

    复制代码

    Python

    编辑

    复制代码
    class Circle:
        def __init__(self, radius):
            self.radius = radius
    
        def __repr__(self):
            return f"Circle(radius={self.radius!r})"
    • eval(repr(Circle(5))) 会报错,因为 Circle 类不在当前作用域。
    • 解决方法:在 __repr__ 中包含模块名(如 __module__)。
6.2 __repr____str__ 的关系
  • 如果只实现 __repr__ 而不实现 __str__str(obj) 会默认调用 __repr__
  • 如果需要更友好的用户输出,建议同时实现 __str__

7. 总结:一句话记住 __repr__

__repr__ 是对象的"身份证",它告诉开发者这个对象是什么、怎么构造的;而 __str__ 是对象的"名片",它告诉用户这个对象是什么样子的。

我们用最简单的

大白话来解释 __repr__

完全不涉及代码,只用生活中的例子:


1. 什么是 __repr__

你可以把它想象成:"这个东西的身份证"

当 Python 需要描述一个对象时(比如你在控制台直接输入对象名),它会自动调用 __repr__ 来生成一个准确、唯一、能被 Python 理解的描述。


2. 举个生活中的例子:身份证 vs 名片

  • 身份证(__repr__

    • 目的:准确描述你是谁,比如你的姓名、年龄、住址等。
    • 特点:信息完整,别人看到身份证能立刻知道你是谁。
    • 例子:Person(name="小明", age=25)
      (这个字符串能被 Python 解释成一个 Person 对象!)
  • 名片(__str__

    • 目的:方便别人认识你,比如只写"小明,25岁"。
    • 特点:信息简洁,适合展示给用户看。
    • 例子:小明,25岁
      (这个字符串只是描述,不能让 Python 自动创建对象。)

3. 为什么需要 __repr__

假设你有一个"书包"对象,里面装着书、铅笔、橡皮。

  • 如果没有 __repr__,Python 只会告诉你:"这是一个书包,内存地址是 0x123456"。

    (就像身份证丢了,只能看身份证号码。)

  • 有了 __repr__,Python 会告诉你:"这是一个书包,里面有《数学书》、3支铅笔、2块橡皮"。

    (这就是完整的身份证信息,开发者一看就知道书包里有什么。)


4. __repr__ 的核心规则

  1. 必须准确

    比如书包里有 3 支铅笔,__repr__ 必须写清楚,不能少写或多写。

  2. 能被 Python 理解
    __repr__ 返回的字符串,理想情况下 应该能被 Python 直接复制粘贴,变成一个一模一样的对象。

    (比如 Person(name="小明", age=25),Python 能用这个字符串重新造出"小明"这个对象。)


5. 举个代码例子(简单版)

复制代码

Python

编辑

复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f"Person(name='{self.name}', age={self.age})"

# 创建对象
p = Person("小明", 25)

# 调用 __repr__
print(p)  # 输出: Person(name='小明', age=25)
  • 为什么输出是 Person(name='小明', age=25)

    因为 __repr__ 告诉 Python:"这个对象是一个 Person 类,参数是 name='小明' 和 age=25"。

  • 如果没写 __repr__ 会怎样?

    Python 会默认输出:<Person object at 0x123456>

    (就像身份证丢了,只能看身份证号码。)


6. 总结:一句话记住 __repr__

__repr__ 是对象的"身份证",它告诉 Python 这个对象是什么、怎么构造的;而 __str__ 是对象的"名片",它告诉用户这个对象是什么样子的。

相关推荐
一个天蝎座 白勺 程序猿2 小时前
Python驱动Ksycopg2连接和使用Kingbase:国产数据库实战指南
数据库·python·kingbase·金仓数据库
丰锋ff2 小时前
2022 年真题配套词汇单词笔记(考研真相)
笔记
丰锋ff2 小时前
2010 年真题配套词汇单词笔记(考研真相)
笔记·学习·考研
开心-开心急了3 小时前
PySide6 文本编辑器(QPlainTextEdit)实现查找功能——重构版本
开发语言·python·ui·重构·pyqt
郝学胜-神的一滴4 小时前
Effective Python 第39条:通过@classmethod多态来构造同一体系中的各类对象
开发语言·python·程序人生·软件工程
聪明的笨猪猪4 小时前
Java “并发工具类”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
雪下的新火4 小时前
爆炸特效-Unity-04-shader&粒子系统
经验分享·笔记·unity·游戏引擎·shader·粒子系统
IT森林里的程序猿4 小时前
基于Python的招聘信息可视化分析系统
开发语言·python
我命由我123455 小时前
Photoshop - Photoshop 工具栏(4)套索工具
经验分享·笔记·学习·ui·职场和发展·职场·photoshop