求解释MIT课程中Python分区函数核心代码及优化方案
Hey there! Let's unpack this partition function clearly, then look at a more readable alternative using Python's itertools module.
Breaking Down the Binary Mask Logic
First, let's understand what parts[i&1].add(item) and i >>= 1 are doing. The variable i here acts as a binary mask that dictates how we split elements between the two sets in parts.
1. i & 1 - Grab the Last Binary Bit
The & operator is a bitwise AND. When you do i & 1, you're checking the rightmost bit of i's binary representation:
- If the last bit is
0,i & 1returns0→ we add the current item toparts[0] - If the last bit is
1,i & 1returns1→ we add the current item toparts[1]
For example, if i = 5 (binary 101), i & 1 is 1; if i = 4 (binary 100), i & 1 is 0.
2. i >>= 1 - Shift the Binary Mask Right
The >>= operator is a bitwise right shift. This moves all bits of i one position to the right, effectively dividing i by 2 (discarding the remainder).
Why do we do this? So that for the next item in the set, we use the next bit in i's binary representation to decide its group.
Let's take a small example with set_ = {1,2,3} and i = 3 (binary 11):
- For item
1:i & 1 = 1→ add toparts[1]; theni >>=1becomes1(binary1) - For item
2:i &1 =1→ add toparts[1]; theni >>=1becomes0(binary0) - For item
3:i &1 =0→ add toparts[0]
Result: parts[0] = {3}, parts[1] = {1,2}.
The loop for i in range(2**len(set_)//2) exists to avoid duplicate partitions (since swapping parts[0] and parts[1] gives the same partition structure). By only iterating half the possible masks, we skip redundant splits.
A More Readable Version with itertools
The original code is efficient but uses low-level bitwise operations that are hard to parse. Here's an alternative using itertools.combinations that's much easier to follow:
from itertools import combinations def partitions_itertools(set_): set_list = list(set_) if not set_list: yield [] return # Force the first element to be in the first subset to avoid duplicate partitions first_element = set_list[0] # Iterate all possible sizes for the first subset (from 1 to full set) for subset_size in range(1, len(set_list) + 1): # Generate all subsets of the remaining elements that, plus first_element, make subset_size for subset_rest in combinations(set_list[1:], subset_size - 1): first_subset = {first_element} | set(subset_rest) # Get elements not in the first subset remaining_elements = [x for x in set_list if x not in first_subset] # Recursively generate partitions for the remaining elements for sub_partition in partitions_itertools(remaining_elements): yield [first_subset] + sub_partition
How This Works:
- Avoid Duplicates: By forcing the first element into the first subset, we eliminate redundant partitions (like
[{1}, {2}]and[{2}, {1}]which are functionally the same). - Intuitive Grouping: We explicitly generate all possible subsets that include the first element, then recursively partition the remaining elements. Each yield gives a unique partition of the original set.
This version trades a tiny bit of efficiency for huge gains in readability—perfect for when you want your code to be easy to debug and understand later.
内容的提问来源于stack exchange,提问作者Paulo Sergio Schlogl

