Python Challenge - Level 5
Problem

pronounce it
Page source contains:
<peakhell src="banner.p" />
<!-- peak hell sounds familiar ? -->
peakhell → sounds like → pickle — Python's binary serialization format.
Solution
The file banner.p is a pickled Python object. It's a list of lists of (char, count) tuples — a run-length encoded banner.
Python
import urllib.request, pickle
data = pickle.load(urllib.request.urlopen(
"http://www.pythonchallenge.com/pc/def/banner.p"
))
for line in data:
print("".join(char * count for char, count in line))
Output (ASCII art):
##### #####
### ## #### ####### ## ### #### ####### ### ### ####
### ### ##### #### ### #### ##### #### ### ### ####
...
The banner reads: channel
Go
Python's pickle format is Python-specific — Go has no standard library support. The practical approach is to avoid re-implementing pickle and instead run a Python helper to decode + re-encode as JSON, then consume JSON in Go:
// Step 1 (Python helper): convert banner.p → banner.json
// import pickle, json, urllib.request
// data = pickle.load(urllib.request.urlopen("...banner.p"))
// print(json.dumps(data))
// Step 2 (Go): decode JSON and render
package main
import (
"encoding/json"
"fmt"
"os/exec"
"strings"
)
func main() {
out, _ := exec.Command("python3", "-c", `
import pickle, json, urllib.request
data = pickle.load(urllib.request.urlopen(
"http://www.pythonchallenge.com/pc/def/banner.p"))
print(json.dumps(data))
`).Output()
var lines [][][]interface{}
json.Unmarshal(out, &lines)
for _, line := range lines {
var sb strings.Builder
for _, pair := range line {
char := pair[0].(string)
count := int(pair[1].(float64))
sb.WriteString(strings.Repeat(char, count))
}
fmt.Println(sb.String())
}
}
Rust
Same approach — use the pickle crate or delegate to Python:
// Using the `serde-pickle` crate (add to Cargo.toml:
// serde-pickle = "1.1"
// reqwest = { version = "0.11", features = ["blocking"] }
use serde_pickle::Value;
use reqwest::blocking::get;
fn main() {
let bytes = get("http://www.pythonchallenge.com/pc/def/banner.p")
.unwrap().bytes().unwrap();
let data: Value = serde_pickle::from_slice(&bytes, Default::default()).unwrap();
if let Value::List(lines) = data {
for line in lines {
if let Value::List(pairs) = line {
let row: String = pairs.iter().filter_map(|pair| {
if let Value::Tuple(items) = pair {
let ch = match &items[0] {
Value::String(s) => s.chars().next().unwrap(),
_ => return None,
};
let count = match &items[1] {
Value::I64(n) => *n as usize,
_ => return None,
};
Some(ch.to_string().repeat(count))
} else { None }
}).collect();
println!("{}", row);
}
}
}
}
Language Comparison
| Feature | Python | Go | Rust |
|---|---|---|---|
| Pickle support | pickle — built-in stdlib |
❌ None — external bridge required | serde-pickle crate (community) |
| Run-length decoding | char * count — string repetition operator |
strings.Repeat(char, count) |
ch.to_string().repeat(count) |
| Binary format portability | Python-native only | Not portable — use JSON/protobuf/msgpack instead | serde-pickle crate works but is niche |
| String repetition | "x" * 5 → "xxxxx" |
strings.Repeat("x", 5) |
"x".repeat(5) |
Key insight: pickle is a uniquely Python construct — it serializes live Python objects including arbitrary class instances. Go and Rust have no equivalent because they don't share Python's object model. For cross-language serialization, use JSON, MessagePack, or Protocol Buffers. This puzzle is a reminder that pickle should never be used for data exchange outside of trusted Python-to-Python pipelines.
pickleis also a security risk — never unpickle untrusted data, as it can execute arbitrary code on load.