现在能在网上找到很多很多的学习资源,有免费的也有收费的,当我拿到1套比较全的学习资源之前,我并没着急去看第1节,我而是去审视这套资源是否值得学习,有时候也会去问一些学长的意见,如果可以之后,我会对这套学习资源做1个学习计划,我的学习计划主要包括规划图和学习进度表。
分享给大家这份我薅到的免费视频资料,质量还不错,大家可以跟着学习
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
05. 为什么必须在方法定义和调用中显式使用“self”?
这个想法借鉴了 Modula-3 语言。出于多种原因它被证明是非常有用的。
首先,更明显的显示出,使用的是方法或实例属性而不是局部变量。阅读 self.x 或 self.meth() 可以清楚地表明,即使您不知道类的定义,也会使用实例变量或方法。在 C++ 中,可以通过缺少局部变量声明来判断(假设全局变量很少见或容易识别) —— 但是在 Python 中没有局部变量声明,所以必须查找类定义才能确定。一些 C++ 和 Java 编码标准要求实例属性具有 m_ 前缀,因此这种显式性在这些语言中仍然有用。
其次,这意味着如果要显式引用或从特定类调用该方法,不需要特殊语法。在 C++ 中,如果你想使用在派生类中重写基类中的方法,你必须使用 :: 运算符 – 在 Python 中你可以编写 baseclass.methodname(self, )。这对于 __init__() 方法非常有用,特别是在派生类方法想要扩展同名的基类方法,而必须以某种方式调用基类方法时。
最后,它解决了变量赋值的语法问题:为了 Python 中的局部变量(根据定义!)在函数体中赋值的那些变量(并且没有明确声明为全局)赋值,就必须以某种方式告诉解释器一个赋值是为了分配一个实例变量而不是一个局部变量,它最好是通过语法实现的(出于效率原因)。C++ 通过声明来做到这一点,但是 Python 没有声明,仅仅为了这个目的而引入它们会很可惜。使用显式的 self.var 很好地解决了这个问题。类似地,对于使用实例变量,必须编写 self.var 意味着对方法内部的非限定名称的引用不必搜索实例的目录。换句话说,局部变量和实例变量存在于两个不同的命名空间中,您需要告诉 Python 使用哪个命名空间。
06. 为什么不能在表达式中赋值?
许多习惯于 C 或 Perl 的人抱怨,他们想要使用 C 的这个特性:
while (line = readline(f)) { // do something with line}
但在 Python 中被强制写成这样:
while True: line = f.readline() if not line: break ... # do something with line
不允许在 Python 表达式中赋值的原因是这些其他语言中常见的、很难发现的错误,是由这个结构引起的:
if (x = 0) { // error handling}else { // code that only works for nonzero x}
错误是一个简单的错字:x = 0 ,将 0 赋给变量 x ,而比较 x == 0 肯定是可以预期的。
已经有许多替代方案提案。大多数是为了少打一些字的黑客方案,但使用任意或隐含的语法或关键词,并不符合语言变更提案的简单标准:它应该直观地向尚未被介绍到这一概念的人类读者提供正确的含义。
一个有趣的现象是,大多数有经验的 Python 程序员都认识到 while True 的习惯用法,也不太在意是否能在表达式构造中赋值; 只有新人表达了强烈的愿望希望将其添加到语言中。
有一种替代的拼写方式看起来很有吸引力,但通常不如"while True"解决方案可靠:
line = f.readline()while line: ... # do something with line... line = f.readline()
问题在于,如果你改变主意(例如你想把它改成 sys.stdin.readline() ),如何知道下一行。你必须记住改变程序中的两个地方 – 第二次出现隐藏在循环的底部。
最好的方法是使用迭代器,这样能通过 for 语句来循环遍历对象。例如 file objects 支持迭代器协议,因此可以简单地写成:
for line in f: ... # do something with line...
07 为什么 Python 对某些功能(例如 list.index())使用方法来实现,而其他功能(例如 len(List))使用函数实现?
正如 Guido 所说:
(a) 对于某些操作,前缀表示法比后缀更容易阅读 – 前缀(和中缀!)运算在数学中有着悠久的传统,就像在视觉上帮助数学家思考问题的记法。比较一下我们将 x*(a+b) 这样的公式改写为 x*a+x*b 的容易程度,以及使用原始 OO 符号做相同事情的笨拙程度。”
(b) 当读到写有 len(X)的代码时,就知道它要求的是某件东西的长度。这告诉我们两件事:结果是一个整数,参数是某种容器。相反,当阅读 x.len()时,必须已经知道 x 是某种实现接口的容器,或者是从具有标准 len()的类继承的容器。当没有实现映射的类有 get()或 key()方法,或者不是文件的类有 write()方法时,我们偶尔会感到困惑。
—https://mail.python.org/pipermail/python-3000/2006-November/004643.html”
08. 为什么 join()是一个字符串方法而不是列表或元组方法?
从 Python 1.6 开始,字符串变得更像其他标准类型,当添加方法时,这些方法提供的功能与始终使用 String 模块的函数时提供的功能相同。这些新方法中的大多数已被广泛接受,但似乎让一些程序员感到不舒服的一种方法是:
", ".join([‘1’, ‘2’, ‘4’, ‘8’, ‘16’])
结果如下:
“1, 2, 4, 8, 16”
反对这种用法有两个常见的论点。
第一条是这样的:“使用字符串文本(String Constant)的方法看起来真的很难看”,答案是也许吧,但是字符串文本只是一个固定值。如果在绑定到字符串的名称上允许使用这些方法,则没有逻辑上的理由使其在文字上不可用。
第二个异议通常是这样的:“我实际上是在告诉序列使用字符串常量将其成员连接在一起”。遗憾的是并非如此。出于某种原因,把 split() 作为一个字符串方法似乎要容易得多,因为在这种情况下,很容易看到:
"1, 2, 4, 8, 16".split(", ")
是对字符串文本的指令,用于返回由给定分隔符分隔的子字符串(或在默认情况下,返回任意空格)。
join() 是字符串方法,因为在使用该方法时,您告诉分隔符字符串去迭代一个字符串序列,并在相邻元素之间插入自身。此方法的参数可以是任何遵循序列规则的对象,包括您自己定义的任何新的类。对于字节和字节数组对象也有类似的方法。
09. 异常有多快?
如果没有引发异常,则 try/except 块的效率极高。实际上捕获异常是昂贵的。在 2.0 之前的 Python 版本中,通常使用这个习惯用法:
try:value = mydict[key]exceptKeyError:mydict[key] = getvalue(key)value = mydict[key]
只有当你期望 dict 在任何时候都有 key 时,这才有意义。如果不是这样的话,你就是应该这样编码:
if key in mydict:value = mydict[key]else:value = mydict[key] = getvalue(key)
对于这种特定的情况,您还可以使用 value = dict.setdefault(key, getvalue(key)),但前提是调用 getvalue()足够便宜,因为在所有情况下都会对其进行评估。
10. 为什么 Python 中没有 switch 或 case 语句?
你可以通过一系列 if… elif… elif… else.轻松完成这项工作。对于 switch 语句语法已经有了一些建议,但尚未就是否以及如何进行范围测试达成共识。有关完整的详细信息和当前状态,请参阅 PEP 275 。
对于需要从大量可能性中进行选择的情况,可以创建一个字典,将 case 值映射到要调用的函数。例如:
def function_1(...): ...functions = {'a': function_1, 'b': function_2, 'c': self.method_1, ...}func = functions[value]func()
对于对象调用方法,可以通过使用 getattr() 内置检索具有特定名称的方法来进一步简化:
defvisit_a(self, ...): ......defdispatch(self, value): method_name = 'visit_' + str(value) method = getattr(self, method_name) method()
建议对方法名使用前缀,例如本例中的 visit_ 。如果没有这样的前缀,如果值来自不受信任的源,攻击者将能够调用对象上的任何方法。
11. 难道不能在解释器中模拟线程,而非得依赖特定于操作系统的线程实现吗?
答案 1:不幸的是,解释器为每个 Python 堆栈帧推送至少一个 C 堆栈帧。此外,扩展可以随时回调 Python。因此,一个完整的线程实现需要对 C 的线程支持。
答案 2:幸运的是, Stackless Python 有一个完全重新设计的解释器循环,可以避免 C 堆栈。
12. 为什么 lambda 表达式不包含语句?
Python 的 lambda 表达式不能包含语句,因为 Python 的语法框架不能处理嵌套在表达式内部的语句。然而,在 Python 中,这并不是一个严重的问题。与其他语言中添加功能的 lambda 表单不同,Python 的 lambdas 只是一种速记符号,如果您懒得定义函数的话。
函数已经是 Python 中的第一类对象,可以在本地范围内声明。因此,使用 lambda 而不是本地定义的函数的唯一优点是你不需要为函数创建一个名称 – 这只是一个分配了函数对象(与 lambda 表达式生成的对象类型完全相同)的局部变量!
13. 可以将 Python 编译为机器代码,C 或其他语言吗?
Cython 将带有可选注释的 Python 修改版本编译到 C 扩展中。Nuitka 是一个将 Python 编译成 C++ 代码的新兴编译器,旨在支持完整的 Python 语言。要编译成 Java,可以考虑 VOC 。
14. Python 如何管理内存?
Python 内存管理的细节取决于实现。Python 的标准实现 CPython 使用引用计数来检测不可访问的对象,并使用另一种机制来收集引用循环,定期执行循环检测算法来查找不可访问的循环并删除所涉及的对象。gc 模块提供了执行垃圾回收、获取调试统计信息和优化收集器参数的函数。
但是,其他实现(如 Jython 或 PyPy ),)可以依赖不同的机制,如完全的垃圾回收器 。如果你的 Python 代码依赖于引用计数实现的行为,则这种差异可能会导致一些微妙的移植问题。
在一些 Python 实现中,以下代码(在 CPython 中工作的很好)可能会耗尽文件描述符:
for file in very_long_list_of_files: f = open(file)c = f.read(1)
实际上,使用 CPython 的引用计数和析构函数方案, 每个新赋值的 f 都会关闭前一个文件。然而,对于传统的 GC,这些文件对象只能以不同的时间间隔(可能很长的时间间隔)被收集(和关闭)。
如果要编写可用于任何 python 实现的代码,则应显式关闭该文件或使用 with 语句;无论内存管理方案如何,这都有效:
for file in very_long_list_of_files: with open(file) as f:c = f.read(1)
15. 为什么 CPython 不使用更传统的垃圾回收方案?
首先,这不是 C 标准特性,因此不能移植。(是的,我们知道 Boehm GC 库。它包含了 大多数 常见平台(但不是所有平台)的汇编代码,尽管它基本上是透明的,但也不是完全透明的; 要让 Python 使用它,需要使用补丁。)
当 Python 嵌入到其他应用程序中时,传统的 GC 也成为一个问题。在独立的 Python 中,可以用 GC 库提供的版本替换标准的 malloc()和 free(),嵌入 Python 的应用程序可能希望用 它自己 替代 malloc()和 free(),而可能不需要 Python 的。现在,CPython 可以正确地实现 malloc()和 free()。
16. CPython 退出时为什么不释放所有内存?
当 Python 退出时,从全局命名空间或 Python 模块引用的对象并不总是被释放。如果存在循环引用,则可能发生这种情况 C 库分配的某些内存也是不可能释放的(例如像 Purify 这样的工具会抱怨这些内容)。但是,Python 在退出时清理内存并尝试销毁每个对象。
如果要强制 Python 在释放时删除某些内容,请使用 atexit 模块运行一个函数,强制删除这些内容。
17. 为什么有单独的元组和列表数据类型?
虽然列表和元组在许多方面是相似的,但它们的使用方式通常是完全不同的。可以认为元组类似于 Pascal 记录或 C 结构;它们是相关数据的小集合,可以是不同类型的数据,可以作为一个组进行操作。例如,笛卡尔坐标适当地表示为两个或三个数字的元组。
另一方面,列表更像其他语言中的数组。它们倾向于持有不同数量的对象,所有对象都具有相同的类型,并且逐个操作。例如, os.listdir(‘.’) 返回表示当前目录中的文件的字符串列表。如果向目录中添加了一两个文件,对此输出进行操作的函数通常不会中断。
元组是不可变的,这意味着一旦创建了元组,就不能用新值替换它的任何元素。列表是可变的,这意味着您始终可以更改列表的元素。只有不变元素可以用作字典的 key,因此只能将元组和非列表用作 key。
18. 列表如何在 CPython 中实现?
CPython 的列表实际上是可变长度的数组,而不是 lisp 风格的链表。该实现使用对其他对象的引用的连续数组,并在列表头结构中保留指向该数组和数组长度的指针。
这使得索引列表 a[i] 的操作成本与列表的大小或索引的值无关。
当添加或插入项时,将调整引用数组的大小。并采用了一些巧妙的方法来提高重复添加项的性能; 当数组必须增长时,会分配一些额外的空间,以便在接下来的几次中不需要实际调整大小。
19. 字典如何在 CPython 中实现?
CPython 的字典实现为可调整大小的哈希表。与 B-树相比,这在大多数情况下为查找(目前最常见的操作)提供了更好的性能,并且实现更简单。
字典的工作方式是使用 hash() 内置函数计算字典中存储的每个键的 hash 代码。hash 代码根据键和每个进程的种子而变化很大;例如,“Python” 的 hash 值为-539294296,而"python"(一个按位不同的字符串)的 hash 值为 1142331976。然后,hash 代码用于计算内部数组中将存储该值的位置。假设您存储的键都具有不同的 hash 值,这意味着字典需要恒定的时间 – O(1),用 Big-O 表示法 – 来检索一个键。
20. 为什么字典 key 必须是不可变的?
字典的哈希表实现使用从键值计算的哈希值来查找键。如果键是可变对象,则其值可能会发生变化,因此其哈希值也会发生变化。但是,由于无论谁更改键对象都无法判断它是否被用作字典键值,因此无法在字典中修改条目。然后,当你尝试在字典中查找相同的对象时,将无法找到它,因为其哈希值不同。如果你尝试查找旧值,也不会找到它,因为在该哈希表中找到的对象的值会有所不同。
如果你想要一个用列表索引的字典,只需先将列表转换为元组;用函数 tuple(L) 创建一个元组,其条目与列表 L相同。元组是不可变的,因此可以用作字典键。
已经提出的一些不可接受的解决方案:
- 哈希按其地址(对象 ID)列出。这不起作用,因为如果你构造一个具有相同值的新列表,它将无法找到;例如:
mydict = {[1, 2]: ‘12’}
print(mydict[[1, 2]])
会引发一个 KeyError 异常,因为第二行中使用的 [1, 2] 的 id 与第一行中的 id 不同。换句话说,应该使用 == 来比较字典键,而不是使用 is 。
-
使用列表作为键时进行复制。这没有用的,因为作为可变对象的列表可以包含对自身的引用,然后复制代码将进入无限循环。
-
允许列表作为键,但告诉用户不要修改它们。当你意外忘记或修改列表时,这将产生程序中的一类难以跟踪的错误。它还使一个重要的字典不变量无效:d.keys() 中的每个值都可用作字典的键。
-
将列表用作字典键后,应标记为其只读。问题是,它不仅仅是可以改变其值的顶级对象;你可以使用包含列表作为键的元组。将任何内容作为键关联到字典中都需要将从那里可到达的所有对象标记为只读 —— 并且自引用对象可能会导致无限循环。
如果需要,可以使用以下方法来解决这个问题,但使用它需要你自担风险:你可以将一个可变结构包装在一个类实例中,该实例同时具有 __eq__() 和 __hash__() 方法。然后,你必须确保驻留在字典(或其他基于 hash 的结构)中的所有此类包装器对象的哈希值在对象位于字典(或其他结构)中时保持固定。
classListWrapper:def__init__(self, the_list):self.the_list = the_listdef__eq__(self, other):returnself.the_list == other.the_listdef__hash__(self): l = self.the_list result = 98767 - len(l)*555for i, el in enumerate(l):try: result = result + (hash(el) % 9999999) * 1001 + i except Exception: result = (result % 7777777) + i * 333return result
注意,哈希计算由于列表的某些成员可能不可用以及算术溢出的可能性而变得复杂。
此外,必须始终如此,如果 o1 == o2 (即 o1.__eq__(o2) is True )则 hash(o1) == hash(o2)(即
o1.__hash__() == o2.__hash__() ),无论对象是否在字典中。如果你不能满足这些限制,字典和其他基于 hash 的结构将会出错。
对于 ListWrapper ,只要包装器对象在字典中,包装列表就不能更改以避免异常。除非你准备好认真考虑需求以及不正确地满足这些需求的后果,否则不要这样做。请留意。
21. 为什么 list.sort() 没有返回排序列表?
在性能很重要的情况下,仅仅为了排序而复制一份列表将是一种浪费。因此, list.sort() 对列表进行了适当的排序。为了提醒您这一事实,它不会返回已排序的列表。这样,当您需要排序的副本,但也需要保留未排序的版本时,就不会意外地覆盖列表。
如果要返回新列表,请使用内置 sorted() 函数。此函数从提供的可迭代列表中创建新列表,对其进行排序并返回。例如,下面是如何迭代遍历字典并按 keys 排序:
for key in sorted(mydict): ... # do whatever with mydict[key]...
22. 如何在 Python 中指定和实施接口规范?
由 C++和 Java 等语言提供的模块接口规范描述了模块的方法和函数的原型。许多人认为接口规范的编译时强制执行有助于构建大型程序。
Python 2.6 添加了一个 abc 模块,允许定义抽象基类 (ABCs)。然后可以使用isinstance() 和 issubclass() 来检查实例或类是否实现了特定的 ABC。collections.abc 模块定义了一组有用的 ABCs 例如 Iterable , Container , 和 MutableMapping
对于 Python,通过对组件进行适当的测试规程,可以获得接口规范的许多好处。还有一个工具 PyChecker,可用于查找由于子类化引起的问题。
一个好的模块测试套件既可以提供回归测试,也可以作为模块接口规范和一组示例。许多 Python 模块可以作为脚本运行,以提供简单的“自我测试”。即使是使用复杂外部接口的模块,也常常可以使用外部接口的简单“桩代码(stub)”模拟进行隔离测试。可以使用 doctest和 unittest 模块或第三方测试框架来构造详尽的测试套件,以运行模块中的每一行代码。
适当的测试规程可以帮助在 Python 中构建大型的、复杂的应用程序以及接口规范。事实上,它可能会更好,因为接口规范不能测试程序的某些属性。例如, append() 方法将向一些内部列表的末尾添加新元素;接口规范不能测试您的 append() 实现是否能够正确执行此操作,但是在测试套件中检查这个属性是很简单的。
编写测试套件非常有用,您可能希望设计代码时着眼于使其易于测试。一种日益流行的技术是面向测试的开发,它要求在编写任何实际代码之前,首先编写测试套件的各个部分。当然,Python 允许您草率行事,根本不编写测试用例。
23. 为什么没有 goto?
可以使用异常捕获来提供 “goto 结构” ,甚至可以跨函数调用工作的 。许多人认为异常捕获可以方便地模拟 C,Fortran 和其他语言的 “go” 或 “goto” 结构的所有合理用法。例如:
classlabel(Exception):pass# declare a labeltry: ...if condition: raise label() # goto label ...except label: # where to gotopass...
但是不允许你跳到循环的中间,这通常被认为是滥用 goto。谨慎使用。
24. 为什么原始字符串(r-strings)不能以反斜杠结尾?
更准确地说,它们不能以奇数个反斜杠结束:结尾处的不成对反斜杠会转义结束引号字符,留下未结束的字符串。
原始字符串的设计是为了方便想要执行自己的反斜杠转义处理的处理器(主要是正则表达式引擎)创建输入。此类处理器将不匹配的尾随反斜杠视为错误,因此原始字符串不允许这样做。反过来,允许通过使用引号字符转义反斜杠转义字符串。当 r-string 用于它们的预期目的时,这些规则工作的很好。
如果您正在尝试构建 Windows 路径名,请注意所有 Windows 系统调用都使用正斜杠:
f = open("/mydir/file.txt") # works fine!
如果您正在尝试为 DOS 命令构建路径名,请尝试以下示例
dir = r"\this\is\my\dos\dir""\\"dir = r"\this\is\my\dos\dir\ "[:-1]dir = "\\this\\is\\my\\dos\\dir\\"
25. 为什么 Python 没有属性赋值的“with”语句?
Python 有一个 ‘with’ 语句,它封装了块的执行,在块的入口和出口调用代码。有些语言的结构是这样的:
with obj: a = 1# equivalent to obj.a = 1 total = total + 1# obj.total = obj.total + 1
在 Python 中,这样的结构是不明确的。
其他语言,如 ObjectPascal、Delphi 和 C++ 使用静态类型,因此可以毫不含糊地知道分配给什么成员。这是静态类型的要点 – 编译器 总是 在编译时知道每个变量的作用域。
Python 使用动态类型。事先不可能知道在运行时引用哪个属性。可以动态地在对象中添加或删除成员属性。这使得无法通过简单的阅读就知道引用的是什么属性:局部属性、全局属性还是成员属性?
例如,采用以下不完整的代码段:
deffoo(a):with a: print(x)
该代码段假设 “a” 必须有一个名为 “x” 的成员属性。然而,Python 中并没有告诉解释器这一点。假设 “a” 是整数,会发生什么?如果有一个名为 “x” 的全局变量,它是否会在 with 块中使用?如您所见,Python 的动态特性使得这样的选择更加困难。
然而,Python 可以通过赋值轻松实现 “with” 和类似语言特性(减少代码量)的主要好处。代替:
function(args).mydict[index][index].a = 21function(args).mydict[index][index].b = 42function(args).mydict[index][index].c = 63
写成这样:
ref = function(args).mydict[index][index]ref.a = 21ref.b = 42ref.c = 63
学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!
### 一、Python所有方向的学习路线
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
![](https://img-blog.csdnimg.cn/img_convert/9f49b566129f47b8a67243c1008edf79.png)
### 二、学习软件
工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
![](https://img-blog.csdnimg.cn/img_convert/8c4513c1a906b72cbf93031e6781512b.png)
### 三、全套PDF电子书
书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。
![](https://img-blog.csdnimg.cn/img_convert/46506ae54be168b93cf63939786134ca.png)
### 四、入门学习视频
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
![](https://img-blog.csdnimg.cn/afc935d834c5452090670f48eda180e0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP5aqb56eD56eD,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
### 五、实战案例
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
![](https://img-blog.csdnimg.cn/img_convert/252731a671c1fb70aad5355a2c5eeff0.png)
### 六、面试资料
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
![](https://img-blog.csdnimg.cn/img_convert/6c361282296f86381401c05e862fe4e9.png)
![](https://img-blog.csdnimg.cn/img_convert/d2d978bb523c810abca3abe69e09bc1a.png)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618317507)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**