.pyc 字节码,再由虚拟机解释执行.py)首先被编译成字节码(.pyc 文件),字节码是一种平台无关的低级表示。.class,JVM 解释执行)。objectint、str、list 都是 type 的实例)int、str、float、bool 等def 定义的函数是 function 对象class 定义的类是 type 对象.py 文件是 module 对象print(isinstance(10, object)) # Trueprint(isinstance("hello", object)) # Trueprint(isinstance(print, object)) # Truetype、object 本身也是对象,形成递归定义。is 和 == 有什么区别?== 比较的是两个对象的值是否相等is 比较的是两个对象的身份标识(内存地址),相当于 id(a) == id(b)== 用于判断两个对象的内容是否相等;is 用于判断两个变量是否指向同一个对象。a = [1, 2]b = [1, 2]print(a == b) # True,值相等print(a is b) # False,内存地址不同None 判断,推荐使用 is None 或 is not None,因为 None 是单例对象。a = 100; b = 100; a is b 可能为 True,但这属于实现细节,不应依赖。list、dict、set、用户自定义类(默认)int、float、str、tuple、frozenset# 不可变对象a = "hello"a += " world"# 创建了新字符串,原来的被回收print(id(a)) # id 改变了# 可变对象lst = [1, 2, 3]lst.append(4) # 原地修改print(id(lst)) # id 不变defadd_item(item, items=[]):# 危险! items.append(item)return itemsprint(add_item(1)) # [1]print(add_item(2)) # [1, 2],而非 [2]__hash__() 方法,返回整数哈希值__eq__() 方法,用于比较相等性d = {(1, 2): "ok"} # 合法d = {[1, 2]: "error"} # TypeErroris None 或 is not None== None,虽然技术上可行但不符合 PEP 8is None 或 is not None 判断。result = None# 推荐写法if result isNone: print("没有结果")# 不推荐(虽然功能相同)if result == None: print("没有结果")None 是单例对象,is 比较的是身份(内存地址),比 == 更精确、更快。is None / is not None。bool() 函数NoneFalse0、0.0、0j''、""[]、()、{}、set()__bool__() 返回 False 或 __len__() 返回 0 的对象bool([]) # Falsebool([0]) # True(列表有元素)bool("") # Falsebool("False") # True(非空字符串)None。and 和 or 返回的一定是布尔值吗?and/or 返回的是操作数本身,而非布尔值and 和 or 返回的是实际的值,不是布尔值and 找第一个假值,or 找第一个真值bool() 函数理解and 和 or 返回的是操作数的值,而非 True/False。a and b:如果 a 为假值,返回 a;否则返回 ba or b:如果 a 为真值,返回 a;否则返回 bprint(0and"hello") # 0print(1and"hello") # helloprint(0or"hello") # helloprint(1or"hello") # 1name = user_input or"Anonymous"x = 10# intx = "hello"# 现在是 strx = [1, 2, 3] # 现在是 listdefgreet(name: str) -> str:returnf"Hello, {name}"defadd(a: int, b: int) -> int:return a + badd("1", "2") # 运行时不会报错!mypy 进行类型检查s[::-1]reversed() 返回迭代器,需用 ''.join() 组合s = "hello"print(s[::-1]) # ollehprint(''.join(reversed(s)))result = ""for c in s: result = c + results[start:end:step],step=-1 表示从后往前遍历。+ 会产生大量临时对象+ 拼接适合少量字符串,join() 适合列表拼接+ 拼接每次都会创建新的字符串对象,O(n²) 复杂度。join() 先计算总长度,分配内存,一次性复制,O(n) 复杂度。# 不推荐:每次+都会创建新对象result = ""for s in strings: result += s # 效率低# 推荐:一次分配内存result = "".join(strings) # 效率高" ".join()、",".join() 可以指定分隔符。split() 将字符串拆分成列表strip() 去除字符串两端的空白字符split():分割,返回字符串列表"a,b,c".split(",") # ['a', 'b', 'c']"hello world".split() # ['hello', 'world'],按空白字符分割strip():去除两端空白(或指定字符),返回新字符串" hello ".strip() # 'hello'"###hello###".strip('#') # 'hello'[表达式 for item in iterable if 条件]# 普通方式squares = []for x in range(5): squares.append(x ** 2)# 列表推导式squares = [x ** 2for x in range(5)]print(squares) # [0, 1, 4, 9, 16][表达式 for item in 可迭代对象]if condition 放在 for 后面if result_a else result_b 放在表达式位置# 筛选偶数nums = [1, 2, 3, 4, 5, 6]evens = [x for x in nums if x % 2 == 0]print(evens) # [2, 4, 6]# 奇数变 0,偶数保留result = [x if x % 2 == 0else0for x in nums]print(result) # [0, 2, 0, 4, 0, 6]append() 将整个对象作为一个元素添加extend() 将可迭代对象的每个元素逐一添加append():将单个对象添加到列表末尾extend():将可迭代对象的每个元素逐一添加到列表末尾lst = [1, 2, 3]lst.append([4, 5])print(lst) # [1, 2, 3, [4, 5]],列表作为整体添加lst = [1, 2, 3]lst.extend([4, 5])print(lst) # [1, 2, 3, 4, 5],元素逐一添加+ 运算符与 extend() 效果相同:[1,2] + [3,4] → [1,2,3,4]sort() 原地修改列表,返回 Nonesorted() 返回新的排序列表,原列表不变list.sort():原地排序,直接修改原列表,返回 Nonesorted(iterable):返回新列表,原对象不变lst = [3, 1, 4, 1, 5]lst.sort()print(lst) # [1, 1, 3, 4, 5]print(lst.sort()) # Nonelst = [3, 1, 4, 1, 5]new_lst = sorted(lst)print(new_lst) # [1, 1, 3, 4, 5]print(lst) # [3, 1, 4, 1, 5],原列表不变key 和 reverse 参数:sorted(strings, key=len, reverse=True) # 按长度降序t = (1, [2, 3], 4)t[0] = 10# TypeError,不能修改元素引用t[1].append(5) # 合法!修改列表内容print(t) # (1, [2, 3, 5], 4)get() 返回默认值(默认为 None),不抛异常d[key] 直接访问会抛 KeyErrorget()d = {"a": 1}print(d.get("b")) # Noneprint(d.get("b", 0)) # 0,提供默认值setdefault()d = {"a": 1}d.setdefault("b", 0) # 返回 0,并设置 d["b"] = 0defaultdictfrom collections import defaultdictd = defaultdict(int) # 不存在的 key 返回 0print(d["b"]) # 0keys() 返回键的视图values() 返回值的视图items() 返回键值对的视图d = {"a": 1, "b": 2}for key in d: print(key)for key in d.keys(): print(key)for value in d.values(): print(value)for key, value in d.items(): print(f"{key}: {value}")dict.keys()、dict.values()、dict.items() 在 Python 3 中返回视图对象,支持迭代但不是列表。{key: value for item in iterable}# 普通方式squares = {}for x in range(5): squares[x] = x ** 2# 字典推导式squares = {x: x ** 2for x in range(5)}print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}# 带条件:筛选evens = {x: x**2for x in range(5) if x % 2 == 0}print(evens) # {0: 0, 2: 4, 4: 16}# 键值对互换d = {"a": 1, "b": 2}reversed_d = {v: k for k, v in d.items()}print(reversed_d) # {1: 'a', 2: 'b'}s = {1, 2, 3, 3, 3}print(s) # {1, 2, 3},自动去重s.add(4) # 添加元素s.remove(2) # 删除元素(不存在会报错)s.discard(5) # 删除元素(不存在不报错)union() 或 |intersection() 或 &difference() 或 -symmetric_difference() 或 ^a = {1, 2, 3, 4}b = {3, 4, 5, 6}# 并集:合并所有元素print(a | b) # {1, 2, 3, 4, 5, 6}print(a.union(b))# 交集:共同元素print(a & b) # {3, 4}print(a.intersection(b))# 差集:A 有 B 没有print(a - b) # {1, 2}print(a.difference(b))# 对称差集:互不包含的元素print(a ^ b) # {1, 2, 5, 6}print(a.symmetric_difference(b))# 子集/超集判断print({1, 2}.issubset({1, 2, 3})) # Trueprint({1, 2, 3}.issuperset({1, 2})) # Truelist.count() 统计单个元素Counter 统计所有元素count()lst = [1, 2, 2, 3, 3, 3]print(lst.count(2)) # 2Counterfrom collections import Counterlst = [1, 2, 2, 3, 3, 3]counter = Counter(lst)print(counter) # Counter({3: 3, 2: 2, 1: 1})print(counter[2]) # 2print(counter.most_common(2)) # [(3, 3), (2, 2)]Counter.most_common(n) 返回前 n 个最常见元素from collections import Counterlst = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]# 最常见的元素counter = Counter(lst)most_common = counter.most_common(1)print(most_common[0][0]) # 4# 前 3 个最常见的print(counter.most_common(3)) # [(4, 4), (3, 3), (2, 2)]# 手写实现defmost_frequent(lst):ifnot lst:returnNone counts = {}for item in lst: counts[item] = counts.get(item, 0) + 1return max(counts, key=counts.get)defgreet(name, age): print(f"{name} is {age}")greet("Alice", 25)greet(age=25, name="Alice")defgreet(name, greeting="Hello"): print(f"{greeting}, {name}")*args:接收任意数量的位置参数,组成元组**kwargs:接收任意数量的关键字参数,组成字典deffunc(*args, **kwargs): print(args, kwargs)func(1, 2, 3, a=4, b=5) # (1, 2, 3) {'a': 4, 'b': 5}# 错误示例defadd_item(item, items=[]): items.append(item)return itemsprint(add_item(1)) # [1]print(add_item(2)) # [1, 2],而非 [2]!# 正确方式defadd_item(item, items=None):if items isNone: items = [] items.append(item)return itemsprint(add_item(1)) # [1]print(add_item(2)) # [2]*args 收集所有位置参数成元组*args 允许函数接受任意数量的位置参数,收集成元组。defsum_all(*args): total = 0for num in args: total += numreturn totalprint(sum_all(1, 2, 3, 4, 5)) # 15# 解包:调用时将列表展开nums = [1, 2, 3, 4, 5]print(sum_all(*nums)) # 15* 可以用在函数定义的参数前(收集),也可以用在实参前(解包)。**kwargs 收集所有关键字参数成字典**kwargs 允许函数接受任意数量的关键字参数,收集成字典。defprint_info(**kwargs):for key, value in kwargs.items(): print(f"{key}: {value}")print_info(name="Alice", age=25, city="Beijing")# name: Alice# age: 25# city: Beijing# 解包:调用时将字典展开info = {"name": "Bob", "age": 30}print_info(**info)def func(*args, **kwargs) 或 def func(a, b, *args, **kwargs)defgreet(name):returnf"Hello, {name}"# 函数可以赋值给变量say_hello = greetprint(say_hello("Alice")) # Hello, Alice# 函数可以作为参数defcall_twice(func, arg):return func(func(arg))# 函数可以作为返回值defmultiplier(n):returnlambda x: x * ndouble = multiplier(2)print(double(5)) # 10# 接收函数作为参数defapply_twice(func, x):return func(func(x))result = apply_twice(lambda x: x * 2, 5)print(result) # 20# 返回函数defmake_power(exponent):defpower(base):return base ** exponentreturn powersquare = make_power(2)print(square(5)) # 25map()、filter()、sorted() 的 key 参数lambda 是创建匿名函数的表达式,返回一个函数对象。# 普通函数defadd(a, b):return a + b# lambda 表达式add = lambda a, b: a + bprint(add(1, 2)) # 3lambda 参数: 表达式if...else 可以用三元表达式)returnnumbers = [3, 1, 4, 1, 5, 9]numbers.sort(key=lambda x: -x) # 降序排列map(func, iterable) 对可迭代对象的每个元素应用函数,返回迭代器。# 平方每个元素numbers = [1, 2, 3, 4, 5]squares = map(lambda x: x ** 2, numbers)print(list(squares)) # [1, 4, 9, 16, 25]# 字符串转整数strings = ["1", "2", "3"]ints = list(map(int, strings)) # [1, 2, 3]map 返回迭代器,需要 list() 转换或遍历。filter(func, iterable) 过滤可迭代对象,返回满足条件的元素。# 筛选偶数numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]evens = filter(lambda x: x % 2 == 0, numbers)print(list(evens)) # [2, 4, 6, 8, 10]# 筛选非空字符串strings = ["hello", "", "world", None, "python"]non_empty = filter(None, strings) # None 表示用元素本身布尔值判断print(list(non_empty)) # ['hello', 'world', 'python']True 的元素会被保留。zip(*iterables) 将多个可迭代对象对应位置的元素配对成元组。# 并行遍历names = ["Alice", "Bob", "Charlie"]ages = [25, 30, 35]for name, age in zip(names, ages): print(f"{name}: {age}")# 构建字典keys = ["name", "age", "city"]values = ["Alice", 25, "Beijing"]d = dict(zip(keys, values))print(d) # {'name': 'Alice', 'age': 25, 'city': 'Beijing'}# 解压zipped = zip(names, ages)unzipped = zip(*zipped)print(list(unzipped)) # [('Alice', 'Bob', 'Charlie'), (25, 30, 35)]x = "global"defouter(): x = "enclosing"definner(): x = "local" print(x) # 找到 local inner()outer() # 输出:localglobal 关键字用于在函数内部声明/修改全局变量。count = 0defincrement():global count # 声明使用全局变量 count += 1increment()increment()print(count) # 2global,Python 会创建同名的局部变量,不会影响全局变量。nonlocal 用于在内层函数中修改外层函数(非全局)的变量。defouter(): x = 10definner():nonlocal x # 声明修改外层函数的 x x = 20 inner() print(x) # 20outer()global:声明/修改模块级别的变量nonlocal:声明/修改外层函数的变量(闭包内)defcounter(): count = 0defincrement():nonlocal count count += 1return countreturn incrementc = counter()print(c()) # 1print(c()) # 2defmake_multiplier(factor):defmultiplier(number):return number * factor # 引用外层变量return multipliertimes_3 = make_multiplier(3)times_5 = make_multiplier(5)print(times_3(10)) # 30print(times_5(10)) # 50deflog_calls(func):defwrapper(*args, **kwargs): print(f"Calling {func.__name__}") result = func(*args, **kwargs) print(f"Finished {func.__name__}")return resultreturn wrapper@log_callsdefgreet(name): print(f"Hello, {name}")greet("Alice")# 输出:# Calling greet# Hello, Alice# Finished greet@log_calls 等价于 greet = log_calls(greet)functools.wraps 保留原函数的元信息。import functoolsdeflog_calls(func): @functools.wraps(func) # 保留原函数信息defwrapper(*args, **kwargs): print(f"Calling {func.__name__}")return func(*args, **kwargs)return wrapper@log_callsdefgreet(name):"""打招呼函数""" print(f"Hello, {name}")print(greet.__name__) # greet(而非 wrapper)print(greet.__doc__) # 打招呼函数greet.__name__ 会变成 "wrapper",影响调试、文档、装饰器栈等。import functoolsdefrepeat(times):defdecorator(func): @functools.wraps(func)defwrapper(*args, **kwargs):for _ in range(times): result = func(*args, **kwargs)return resultreturn wrapperreturn decorator@repeat(times=3)defgreet(name): print(f"Hello, {name}")greet("Alice")# 输出:Hello, Alice 三次@repeat(times=3) → 返回 decorator → 装饰 greet@lru_cache(maxsize=128)、@click.option()try: result = 10 / 0except ZeroDivisionError: print("不能除以零")# 多个异常try: int("abc")except ValueError: print("值错误")except TypeError: print("类型错误")# 捕获所有异常try: risky_operation()except Exception as e: print(f"发生错误: {e}")except ZeroDivisionError: # 先匹配这个passexcept ArithmeticError: # 父类放后面passtry: print("try")# 可能抛出异常的代码 x = 10 / 2except ZeroDivisionError: print("except: 捕获到异常")else: print("else: 没有异常时执行") # x = 10 / 2 成功执行后才执行finally: print("finally: 无论是否异常都执行")# finally 与 returndeftest():try:return1finally: print("finally") # 仍然会执行test() # 输出: finally, 返回 1raise 关键字抛出异常。# 抛出异常类raise ValueError("值不合法")# 抛出异常实例raise ValueError("值不合法")# 重新抛出当前异常try: something()except:raise# 保持原始异常信息defwithdraw(amount):if amount <= 0:raise ValueError("取款金额必须为正数")# 基本自定义异常classValidationError(Exception):pass# 带额外信息的异常classValidationError(Exception):def__init__(self, field, message): self.field = field self.message = message super().__init__(f"{field}: {message}")raise ValidationError("email", "格式不正确")# 捕获自定义异常try: ...except ValidationError as e: print(f"字段 {e.field}: {e.message}")Error 结尾KeyboardInterrupt、SystemExit# 错误做法try: dangerous_operation()except: # 捕获所有,包括退出信号pass# 正确做法try: dangerous_operation()except SpecificError as e: handle_error(e) # 适当处理raise# 必要时重新抛出except Exception:,不要裸 except:with 语句确保文件在使用完毕后自动关闭,即使发生异常。# 不推荐:需要手动关闭f = open("file.txt", "r")content = f.read()f.close() # 如果中间出错,文件不会关闭# 推荐:自动关闭with open("file.txt", "r") as f: content = f.read()# with 块结束后,文件自动关闭__enter__ 和 __exit__ 方法(上下文管理器协议)__enter__ 和 __exit__ 方法的对象,控制资源的获取和释放。classFileManager:def__init__(self, filename, mode): self.filename = filename self.mode = mode self.file = Nonedef__enter__(self): self.file = open(self.filename, self.mode)return self.filedef__exit__(self, exc_type, exc_val, exc_tb):if self.file: self.file.close()returnFalse# 不处理异常with FileManager("test.txt", "w") as f: f.write("Hello")@contextmanagerfrom contextlib import contextmanager@contextmanagerdeffile_manager(filename, mode): f = open(filename, mode)yield f f.close()__iter__ 和 __next__ 方法的对象。classCounter:def__init__(self, n): self.n = n self.current = 0def__iter__(self):return selfdef__next__(self):if self.current >= self.n:raise StopIteration self.current += 1return self.currentfor i in Counter(3): print(i) # 1, 2, 3__iter__ 返回迭代器本身__next__ 返回下一个元素StopIteration__iter__ 方法(返回迭代器)的对象。# 列表是可迭代对象lst = [1, 2, 3]iterator = lst.__iter__() # 或 iter(lst)print(next(iterator)) # 1print(next(iterator)) # 2for 遍历,不一定有 __next__for 遍历,也有 __next__yield 语句返回值的函数,每次迭代生成一个值。defcount_up_to(n): i = 1while i <= n:yield i # 暂停,返回值 i += 1gen = count_up_to(3)print(next(gen)) # 1print(next(gen)) # 2print(next(gen)) # 3next() 执行到 yield 并暂停StopIteration 后结束gen = (x**2 for x in range(5))# 普通列表:一次性加载所有数据numbers = [x**2for x in range(1000000)] # 占用大量内存# 生成器:按需计算numbers = (x**2for x in range(1000000)) # 几乎不占内存# 处理大文件with open("huge_file.txt") as f: lines = (line.strip() for line in f) # 不读取所有行for line in lines: process(line)yield from 将控制权委托给子生成器,自动传递值。# 不使用 yield fromdefflatten(nested):for item in nested:for element in item:yield element# 使用 yield fromdefflatten(nested):for item in nested:yieldfrom itemnested = [[1, 2], [3, 4], [5, 6]]print(list(flatten(nested))) # [1, 2, 3, 4, 5, 6][],生成器表达式用 ()[] | () | |
|---|---|---|
# 列表推导式squares_list = [x**2for x in range(1000)]print(type(squares_list)) # <class 'list'># 生成器表达式squares_gen = (x**2for x in range(1000))print(type(squares_gen)) # <class 'generator'>classDog:# 类def__init__(self, name): self.name = namedefbark(self): print(f"{self.name} says Woof!")# 创建对象dog1 = Dog("Buddy")dog2 = Dog("Max")print(type(dog1)) # <class '__main__.Dog'>print(isinstance(dog1, Dog)) # True__init__ 是初始化器,__new__ 才是构造函数。__new__ 负责创建实例,__init__ 负责初始化实例。classExample:def__new__(cls, *args, **kwargs): print("__new__ called")return super().__new__(cls) # 必须返回实例def__init__(self, value): print("__init__ called") self.value = valuee = Example(10)# 输出:# __new__ called# __init__ called__init__**,__new__ 用于特殊场景(如单例模式、不可变对象)。classDog: species = "Canis familiaris"# 类属性,所有对象共享def__init__(self, name): self.name = name # 实例属性,每个对象独立dog1 = Dog("Buddy")dog2 = Dog("Max")print(dog1.name) # Buddy(实例属性)print(dog1.species) # Canis familiaris(类属性)# 修改实例属性不影响类属性dog1.species = "Cat"# 创建了实例属性,不影响 dog2print(dog2.species) # Canis familiarisself.xxx 定义classExample: class_attr = "类属性"definstance_method(self):# self 是实例return"实例方法", self @classmethoddefclass_method(cls):# cls 是类return"类方法", cls @staticmethoddefstatic_method():# 没有隐式参数return"静态方法"obj = Example()# 调用方式obj.instance_method() # 需要实例Example.class_method() # 可以用类或实例调用Example.static_method() # 可以用类或实例调用classAnimal:def__init__(self, name): self.name = namedefspeak(self):raise NotImplementedErrorclassDog(Animal):# 继承 Animaldefspeak(self):returnf"{self.name} says Woof!"classCat(Animal):# 继承 Animaldefspeak(self):returnf"{self.name} says Meow!"dog = Dog("Buddy")print(dog.name) # Buddy(继承自父类)print(dog.speak()) # Buddy says Woof!classParent:defgreet(self):return"Hello from Parent"classChild(Parent):defgreet(self):# 重写父类方法return"Hello from Child"defgreet_parent(self):# 调用父类方法return super().greet()child = Child()print(child.greet()) # Hello from Childprint(child.greet_parent()) # Hello from Parentsuper() 返回一个代理对象,用于调用父类的方法。classAnimal:def__init__(self, name, age): self.name = name self.age = ageclassDog(Animal):def__init__(self, name, age, breed): super().__init__(name, age) # 调用父类 __init__ self.breed = breed # 添加新属性dog = Dog("Buddy", 3, "Golden Retriever")print(dog.name, dog.age, dog.breed) # Buddy 3 Golden Retrieversuper().__init__(...)(不需要传类名和 self)super() 按照 MRO 顺序调用下一个类的方法classFlyer:deffly(self): print("Flying")classSwimmer:defswim(self): print("Swimming")classDuck(Flyer, Swimmer):# 多继承passduck = Duck()duck.fly() # Flyingduck.swim() # Swimmingprint(Duck.__mro__) # 查看 MRO__ 包裹的方法,由 Python 内部调用或允许开发者重写。classPoint:def__init__(self, x, y): self.x = x self.y = ydef__add__(self, other):# 重写 + 运算符return Point(self.x + other.x, self.y + other.y)def__repr__(self):returnf"Point({self.x}, {self.y})"p1 = Point(1, 2)p2 = Point(3, 4)print(p1 + p2) # Point(4, 6)__init__:初始化__str__ / __repr__:字符串表示__add__ / __eq__ / __lt__:运算符__len__ / __getitem__:容器行为__repr__:开发者友好,用于调试和开发环境__str__:用户友好,用于最终用户显示classPerson:def__init__(self, name): self.name = namedef__repr__(self):returnf"Person(name='{self.name}')"# 精确、可以重建对象def__str__(self):returnf"Person: {self.name}"# 友好、可读p = Person("Alice")print(repr(p)) # Person(name='Alice')print(str(p)) # Person: Alice# print 优先用 __str__,没有则用 __repr__# 直接在解释器输入对象优先用 __repr____repr__ 优先(IDE、调试用),__str__ 可选。@property 将方法转换为属性访问,实现类似 getter 的功能。classCircle:def__init__(self, radius): self._radius = radius # 私有属性(约定) @propertydefradius(self):"""Getter"""return self._radius @radius.setterdefradius(self, value):"""Setter,带验证"""if value < 0:raise ValueError("半径不能为负") self._radius = value @propertydefarea(self):"""只读属性"""return3.14 * self._radius ** 2c = Circle(5)print(c.radius) # 5(像访问属性一样)c.radius = 10# 调用 setterprint(c.area) # 314.0dataclass 是 Python 3.7+ 的装饰器,自动生成常用方法。from dataclasses import dataclassfrom typing import Optional@dataclassclassPerson: name: str age: int email: Optional[str] = Noneperson = Person("Alice", 25)print(person) # Person(name='Alice', age=25, email=None)print(person.name) # Alice__init__、__repr__、__eq__、__hash__(可选)frozen=True:不可变对象order=True:支持比较运算slots=True:使用 __slots__ 优化内存__slots__ 限制类只能拥有的属性,禁用 __dict__,节省内存。classWithoutSlots:def__init__(self, name): self.name = nameclassWithSlots: __slots__ = ['name']def__init__(self, name): self.name = name# __slots__ 类w1 = WithSlots("Alice")w1.name = "Bob"# OK# w1.age = 25 # AttributeError# 无 __slots__ 类w2 = WithoutSlots("Alice")w2.age = 25# OK,可以动态添加__dict__、slots 继承问题.py 文件,可以包含函数、类、变量__init__.py 的目录,用于组织多个模块# 模块# file: mymodule.pydefhello():return"Hello"# 使用模块import mymodulemymodule.hello()# 包# directory: mypackage/# file: mypackage/__init__.py# file: mypackage/module.pyimport mypackage.module__init__.py 使目录成为包(Python 3.3+ 不必须,但仍建议保留)__name__ 是 Python 自动设置的变量:__name__ == "__main__"__name__ == "模块名"# file: example.pydefmain(): print("Main function")if __name__ == "__main__": main()# 只有直接运行此文件时才执行pip install package_namepip install package==1.0.0pip install -r requirements.txtpython -m venv venvsource venv/bin/activate # Linux/Macvenv\Scripts\activate # Windowspip install packagerequirements.txt:列出依赖pyproject.toml:现代标准(PEP 518),包含项目元数据和依赖requirements.txt 记录项目的第三方依赖,便于复现环境。# 生成 requirements.txtpip freeze > requirements.txt# 安装依赖pip install -r requirements.txtrequests>=2.28.0flask==2.2.0numpy>=1.23.0==:精确版本>=:最低版本~=:兼容版本(如 ~=2.0 表示 >=2.0 且 <3.0)pyproject.toml 是现代 Python 项目的标准配置文件(PEP 518)。[project]name = "my-project"version = "1.0.0"dependencies = [ "requests>=2.28.0", "flask>=2.0.0"][project.optional-dependencies]dev = [ "pytest>=7.0.0", "black>=22.0.0"][build-system]requires = ["setuptools>=45", "wheel"]build-backend = "setuptools.build_meta"import os# 方式一:os.environdb_host = os.environ["DB_HOST"]db_port = os.environ.get("DB_PORT", "5432") # 带默认值# 方式二:os.getenv(推荐)api_key = os.getenv("API_KEY")timeout = os.getenv("TIMEOUT", "30")# 设置环境变量os.environ["DEBUG"] = "true"__all__ 列表定义 from module import * 时导出的内容。# file: mymodule.py__all__ = ['public_func', 'PublicClass']defpublic_func():passdef_private_func():passclassPublicClass:pass# 导入行为from mymodule import * # 只导入 public_func 和 PublicClass_ 开头的函数/类是私有约定import threadingimport requestsdeffetch_url(url): response = requests.get(url)return response.textthreads = []for url in urls: t = threading.Thread(target=fetch_url, args=(url,)) threads.append(t) t.start()import threadingimport timedefcpu_task(): count = 0for i in range(100000000): count += 1return count# CPU 密集型:多线程无效t1 = threading.Thread(target=cpu_task)t2 = threading.Thread(target=cpu_task)t1.start(); t2.start() # 总时间 ≈ 单线程!from multiprocessing import Pooldefcpu_task(n):return sum(i**2for i in range(n))if __name__ == "__main__":with Pool(4) as p: # 4 个进程 results = p.map(cpu_task, [10000000] * 8)spawn 方式:创建进程时会重新导入模块、执行所有顶层代码fork 方式:子进程继承父进程状态from multiprocessing import Processdefworker(): print("Worker")if __name__ == "__main__": # Windows 必须! p = Process(target=worker) p.start()Process(...) 创建新的子进程multiprocessing 代码都放在 if __name__ == "__main__" 下import asyncioasyncdeffetch(url):asyncwith aiohttp.ClientSession() as session:asyncwith session.get(url) as response:returnawait response.text()asyncdefmain(): urls = [...] tasks = [fetch(url) for url in urls] results = await asyncio.gather(*tasks)优势:
对比:
async def 定义协程函数,await 等待协程对象。import asyncio# 定义协程函数asyncdeffetch_data(): print("Fetching...")await asyncio.sleep(1) # 模拟 I/Oreturn"data"# 运行协程asyncdefmain(): result = await fetch_data() # 等待协程完成 print(result)asyncio.run(main())async def 定义的是协程函数,返回协程对象await 只能在 async def 函数内使用asyncio.run() 创建事件循环并运行await 会让出控制权,允许其他协程运行import asyncioasyncdeftask(id):await asyncio.sleep(0.5)returnf"Task {id} done"asyncdefmain():# 方式一:gather(推荐) results = await asyncio.gather( task(1), task(2), task(3) ) print(results) # ['Task 1 done', 'Task 2 done', 'Task 3 done']# 方式二:create_task + wait t1 = asyncio.create_task(task(1)) t2 = asyncio.create_task(task(2)) done, pending = await asyncio.wait([t1, t2])import asyncioimport time# 协程中使用 time.sleep()(错误)asyncdefbad_example(): time.sleep(1) # 阻塞整个线程,其他协程无法运行!# 协程中使用 asyncio.sleep()(正确)asyncdefgood_example():await asyncio.sleep(1) # 挂起协程,其他协程可以运行time.sleep():线程阻塞,CPU 空转asyncio.sleep():协程挂起,事件循环可以切换到其他协程async 函数中必须使用 asyncio.sleep()threading.Lock 实现线程同步。import threadingcounter = 0lock = threading.Lock()defincrement():global counterfor _ in range(1000000):with lock: # 自动获取/释放锁 counter += 1threads = [threading.Thread(target=increment) for _ in range(4)]for t in threads: t.start()for t in threads: t.join()print(counter) # 4000000defaultdict 在访问不存在的 key 时自动调用工厂函数创建默认值。from collections import defaultdict# 自动创建列表dd_list = defaultdict(list)dd_list["fruits"].append("apple")dd_list["fruits"].append("banana")print(dd_list) # {'fruits': ['apple', 'banana']}# 自动创建字典dd_dict = defaultdict(dict)dd_dict["user"]["name"] = "Alice"print(dd_dict) # {'user': {'name': 'Alice'}}# 自动计数dd_int = defaultdict(int)dd_int["apple"] += 1print(dd_int) # {'apple': 1}list、dict、int(默认 0)、setdeque(双端队列)在两端操作效率高,适合队列和滑动窗口。from collections import deque# 两端添加/删除 O(1)dq = deque([1, 2, 3])dq.appendleft(0) # [0, 1, 2, 3]dq.append(4) # [0, 1, 2, 3, 4]dq.popleft() # 返回 0dq.pop() # 返回 4# 滑动窗口defsliding_window_max(nums, k): dq = deque() result = []for i, num in enumerate(nums):while dq and nums[dq[-1]] < num: dq.pop() dq.append(i)if dq[0] <= i - k: dq.popleft()if i >= k - 1: result.append(nums[dq[0]])return resultinsert(0, x) 和 pop(0) 是 O(n),deque 是 O(1)heapq 提供最小堆操作。import heapq# 创建堆heap = []heapq.heappush(heap, 5)heapq.heappush(heap, 2)heapq.heappush(heap, 8)print(heap) # [2, 5, 8]# 弹出最小print(heapq.heappop(heap)) # 2# 堆化列表nums = [5, 2, 8, 1]heapq.heapify(nums)print(nums) # [1, 2, 8, 5]# 最大堆:存负数max_heap = []heapq.heappush(max_heap, -5)heapq.heappush(max_heap, -2)heapq.heappush(max_heap, -8)print(-heapq.heappop(max_heap)) # 8# 优先队列deftop_k(nums, k):return heapq.nlargest(k, nums) # 前 k 大dumps:Python 对象序列化为 JSON 字符串loads:JSON 字符串反序列化为 Python 对象import json# Python 对象 → JSON 字符串data = {"name": "Alice", "age": 25, "scores": [90, 85, 88]}json_str = json.dumps(data)print(json_str) # {"name": "Alice", "age": 25, "scores": [90, 85, 88]}# JSON 字符串 → Python 对象parsed = json.loads(json_str)print(parsed) # {'name': 'Alice', 'age': 25, 'scores': [90, 85, 88]}# 格式化输出print(json.dumps(data, indent=2, ensure_ascii=False))s 表示 string(字符串)import jsonfrom decimal import Decimaldata = {"price": Decimal("19.99"), "amount": Decimal("100")}# 方式一:转换为 float(可能有精度损失)defdecimal_to_float(obj):if isinstance(obj, Decimal):return float(obj)raise TypeErrorjson_str = json.dumps(data, default=decimal_to_float)print(json_str) # {"price": 19.99, "amount": 100.0}# 方式二:转换为字符串(保持精度)defdecimal_to_str(obj):if isinstance(obj, Decimal):return str(obj)raise TypeErrorjson_str = json.dumps(data, default=decimal_to_str)print(json_str) # {"price": "19.99", "amount": "100"}from pathlib import Pathp = Path("project/data/file.txt")# 路径拼接(比 os.path.join 更直观)p2 = p / ".." / "backup" / p.name# 属性访问print(p.name) # file.txtprint(p.stem) # fileprint(p.suffix) # .txtprint(p.parent) # project/data# 方法print(p.exists()) # 检查存在p.mkdir(parents=True, exist_ok=True) # 创建目录p.write_text("content") # 写入文件# 路径规范化print(p.resolve()) # 绝对路径p / "subdir"p.name、p.suffiximport csv# 方式一:读取为列表with open("data.csv", "r", encoding="utf-8") as f: reader = csv.reader(f)for row in reader: print(row)# 方式二:读取为字典(推荐)with open("data.csv", "r", encoding="utf-8") as f: reader = csv.DictReader(f)for row in reader: print(row["name"], row["age"])# 写入 CSVwith open("output.csv", "w", encoding="utf-8", newline="") as f: writer = csv.DictWriter(f, fieldnames=["name", "age"]) writer.writeheader() writer.writerow({"name": "Alice", "age": 25})encoding="utf-8"newline=""csv.DictReader 更易处理import logging# 基本配置logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", handlers=[ logging.FileHandler("app.log"), logging.StreamHandler() ])logger = logging.getLogger(__name__)logger.debug("Debug message")logger.info("Info message")logger.warning("Warning message")logger.error("Error message")import unittestdefadd(a, b):return a + bclassTestAdd(unittest.TestCase):deftest_positive_numbers(self): self.assertEqual(add(1, 2), 3)deftest_negative_numbers(self): self.assertEqual(add(-1, -2), -3)deftest_mixed_numbers(self): self.assertEqual(add(-1, 2), 1)deftest_zero(self): self.assertEqual(add(0, 5), 5) self.assertEqual(add(5, 0), 5)if __name__ == "__main__": unittest.main()assertEqual(a, b):相等assertTrue(x):为真assertRaises(Exception):抛出异常assertAlmostEqual(a, b):浮点数近似相等import pytestdefdivide(a, b):if b == 0:raise ValueError("Cannot divide by zero")return a / b# 基本用法deftest_division_by_zero():with pytest.raises(ValueError): divide(1, 0)# 验证异常消息deftest_division_error_message():with pytest.raises(ValueError, match="Cannot divide by zero"): divide(1, 0)# 验证异常属性deftest_exception_attributes():with pytest.raises(ValueError) as exc_info: divide(1, 0)assert"zero"in str(exc_info.value)import sys# 查看单个对象大小print(sys.getsizeof(1)) # 28print(sys.getsizeof("hello")) # 54print(sys.getsizeof([1, 2, 3])) # 72print(sys.getsizeof({"a": 1})) # 232# 深度分析内存import tracemalloctracemalloc.start()data = [x ** 2for x in range(10000)]current, peak = tracemalloc.get_traced_memory()print(f"当前: {current / 1024:.2f} KB")print(f"峰值: {peak / 1024:.2f} KB")tracemalloc.stop()# 第三方工具:pip install pymplerfrom pympler import asizeofprint(asizeof.asizeof(data))# 问题:生成 1000000 个平方数# 不推荐:列表占用大量内存squares = [x**2for x in range(1000000)]# 推荐:生成器按需计算squares = (x**2for x in range(1000000))# 分批处理defprocess_in_chunks(data, chunk_size=1000):for i in range(0, len(data), chunk_size):yield data[i:i+chunk_size]# 使用 itertoolsfrom itertools import islicedefgenerate_squares(): i = 0whileTrue:yield i ** 2 i += 1# 取前 10 个平方数squares = islice(generate_squares(), 10)print(list(squares)) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]import copyoriginal = [[1, 2, 3], [4, 5, 6]]# 浅拷贝:只拷贝一层shallow = copy.copy(original)shallow[0][0] = 99print(original) # [[99, 2, 3], [4, 5, 6]],原数据被修改!# 深拷贝:递归拷贝所有层deep = copy.deepcopy(original)deep[0][0] = 88print(original) # [[99, 2, 3], [4, 5, 6]],原数据不变# 切片是浅拷贝lst = [[1, 2], [3, 4]]lst_copy = lst[:]copy.copy() | ||
copy.deepcopy() | ||
[:] |
with 语句在任何情况下都会释放资源,即使发生异常。# 手动关闭(不安全)f = open("file.txt", "r")content = f.read()f.close() # 如果 read() 抛异常,文件不会关闭!# with 语句(安全)with open("file.txt", "r") as f: content = f.read()# 无论是否异常,文件都会关闭# try...finally 等效f = open("file.txt", "r")try: content = f.read()finally: f.close() # 总是执行a = b 而不是 a=bsnake_casePascalCaseUPPER_SNAKE_CASE# 好的写法defcalculate_total(items, tax_rate=0.1): subtotal = sum(item['price'] for item in items)return subtotal * (1 + tax_rate)# 工具:black(格式化)、flake8(检查)、mypy(类型)black(自动格式化)、flake8(检查)、mypy(类型检查)从以下维度阐述:
代码规范
类型提示
测试覆盖
重构与设计
性能优化
代码审查
回答示例:
❝"我会从规范、测试、性能三个维度提升代码质量。规范上使用 black 统一格式、flake8 检查;测试上用 pytest 做单元测试,保证覆盖率;性能上用生成器处理大数据,用 cProfile 分析瓶颈。同时保持函数短小、命名清晰,并通过 Code Review 持续改进。"