揭秘 Python 的 10 个隐藏技巧

对于初涉编程世界的人来说,Python 是一门优秀的语言,但它有许多细节可能不为初学者所注意。

在本篇文章中,您将学习到每个 Python 程序员都应该掌握的 10 个技巧,以便编写出更好的代码!

01 – 在不使用中介的情况下交换变量值

在许多语言中,在两个变量之间交换值需要第三个临时变量,例如在 C 语言中:

#include <stdio.h>

int main() {
    int a = 5;
    int b = 10;
    int temp;

    temp = a;
    a = b;
    b = temp;

    printf("Output:\n");
    printf("a = %d\n", a); // a = 10
    printf("b = %d\n", b); // b = 5

    return 0;
}

在 Python 中,我们可以优雅地做到这一点:

x, y = 5, 10
x, y = y, x
print(x, y)  # Output: 10 5

这种方法使用元组重构来简化交换。

02 – PEP 8

PEP 8 是官方的 Python 风格指南。遵循它可以提高代码的可读性和标准化。一些重要的规则

import os

def my_function():
    print("Following PEP 8!")

如果您使用 VSCode,可以安装 autopep8 扩展来帮助您。

03 –Walrus 运算符

在 Python 3.8 中引入的 walrus 操作符允许在表达式中赋值,从而减少代码重复:

# Without Walrus Operator
n_len = len([1, 2, 3, 4])
if n_len > 3:
    print(f"The list has {n_len} elements")

# With Walrus Operator
if (n := len([1, 2, 3, 4])) > 3:
    print(f"The list has {n} elements")

该运算符可避免重复调用函数(本例中为 len() 函数),并提高代码的可读性,尤其是在循环和条件式中。

有趣的事实:该运算符因酷似海象的牙齿(Walrus)而得名。

04 – Is 运算符

很多人不知道这个运算符,但 is 运算符可以检查两个变量是否指向内存中的同一个对象:

a = [1, 2, 3]
b = a
print(a is b)  # True

c = [1, 2, 3]
print(a is c)  # False

该操作符也常用于检查对象是否为 None

a = None
if a is None:
    print("a is None")

⚠️ 注意: 要比较值,请使用 ==,因为is对于不可变类型(如字符串和数字),使用 == 会因插值而导致意想不到的结果:

x = 256
y = 256
print(x is y)  # True (small values can be interned)

05 – 复制对象

将一个变量赋值给另一个变量 (=) 只会创建对同一对象的引用。

要创建真正的副本,需要使用copy library。请密切注意,复制有两种类型:

浅复制: 不复制嵌套对象,只复制其结构。

深度复制: 递归复制所有对象。

我们来看一个例子:

import copy

original_dict = {
    'a': 1,
    'b': [2, 3, 4],
    'c': {'x': 5, 'y': 6}
}

shallow_copy = copy.copy(original_dict)
deep_copy = copy.deepcopy(original_dict)

# Modifying the original object
original_dict['a'] = 100
original_dict['b'][0] = 200 # shallow_copy will have this value even if it is not modified \0/
original_dict['c']['x'] = 300

print("Original:", original_dict)
print("Shallow Copy:", shallow_copy)
print("Deep Copy:", deep_copy)

# Original: {'a': 100, 'b': [200, 3, 4], 'c': {'x': 300, 'y': 6}}
# Shallow Copy: {'a': 1, 'b': [200, 3, 4], 'c': {'x': 300, 'y': 6}} <--------------- 
# Deep Copy: {'a': 1, 'b': [2, 3, 4], 'c': {'x': 5, 'y': 6}}

在上面的示例中,你可以看到属性 shallow_copy['b'][0]存储了值 200,尽管它在代码的任何地方都没有被修改。

在这种情况下,由于复制是浅层的,对原始字典 original_dict['b'] 的引用被复制到了属性 shallow_copy['b']。换句话说,属性 original_dict['b'] shallow_copy['b'] 指向同一个内存地址。

另一方面,deep_copy 字典的创建完全独立于其他字典,字典之间不共享内存地址。

总结:

浅层拷贝: 只复制结构,但共享内部对象(列表、字典等)的引用。

深度复制: 递归复制所有内容,创建独立对象。

06 – 负索引

Python 允许使用负索引从末尾访问列表中的元素:

  • 最后一项:list[-1]
  • 倒数第二项:list[-2]
numbers = [10, 20, 30, 40]
print(numbers[-1])  # 40
print(numbers[-2])  # 30

07 – 猴子修补

Monkey Patch 是一种在运行时修改或替换现有类的方法和属性的技术。

它对于修复错误、修改第三方库的行为或在不改变原始源代码的情况下添加功能非常有用,尤其是用于测试目的。

不过,使用时应谨慎,因为它可能会带来意想不到的副作用。

class MathOperations: 

    def add(self, a, b) : 
        return a + b

    def subtract(self, a, b) : 
        return a - b 

# Define a new function to be added to the class 
def multiply(self, a, b): 
    return a * b 

MathOperations.multiply = multiply 

# Now, we can use the 'multiply' method as if it was part of the original class 
math_instance = MathOperations() 
result = math_instance.multiply(3, 4)

print("Result of multiplication: ", result) # Result of multiplication: 12

在上面的示例中,一个意想不到的副作用是在运行时为类添加了一个方法。

想象一下,如果 multiply 方法和 MathOperation 类是在不同的文件中。你需要多长时间才能意识到在代码的某处有一行将一个新方法分配给了一个类?

08 – 定时器上下文

使用上下文管理器和 with 可以方便、自动地测量代码块的执行时间。

这对于性能优化、分析关键函数的执行时间和调试代码瓶颈非常有用。

import time

class Timer:
    def __enter__(self):
        self.start = time.time()
        return self

    def __exit__(self, *args):
        print(f"Execution time: {time.time() - self.start:.4f}s")

with Timer():
    sum(range(10**6))

# Execution time: 0.0194s

09 – 访问规范

Python 不像其它语言那样有严格的访问控制,但它使用约定来表示类属性和方法的可见性:

_protected: 表示属性或方法受保护,只能在类及其子类中使用。

__private:私有: 表示一个属性或方法应该是私有的,但仍然可以使用 obj._Class__private 访问(我认为只有在测试场景中使用才是合理的)。

class MyClass:
    def __init__(self):
        self.public = "can be accessed"
        self._protected = "use with caution"
        self.__private = "should not be accessed directly"

obj = MyClass()
print(obj.public)  # OK
print(obj._protected)  # Convention: do not modify
# print(obj.__private)  # Error

try/except 内的 else 块允许将只应在无异常情况下执行的代码分开。

这样可以改进组织结构,避免在 try 内执行不必要的代码,从而降低出现意外异常的风险。

try:
    result = 10 / 2
except ZeroDivisionError:
    print("Error: Division by zero!")
else:
    print("Everything is fine! Result:", result)

结论

这些只是 Python 这门 “蛇的语言 ”之所以如此强大和多才多艺的众多细节中的一小部分。

掌握了这些技术,您就能编写出更高效、可读性更强、更健壮的代码。

 

你也许感兴趣的:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注