Dicts/JSON, **kwargs, decorators, with-blocks, lambdas — the Hugging Face reading patterns
Do this before Course 7. The GenAI half of the certificate (Hugging Face, LangChain) reads differently from the sklearn half: dicts everywhere, **kwargs, decorators, with blocks, lambdas. Five patterns, and all of it opens up.
The LLM stack passes labelled data, not positional lists:
enc = {"input_ids": [101, 7592, 102], "attention_mask": [1, 1, 1]}
print(enc["input_ids"]) # read by name
enc["labels"] = [1] # add by name
print(enc.keys()) # what's in the box?
When Course 7 shows enc = tokenizer("Hello world", return_tensors='pt') — that result behaves like this dict. enc['input_ids'], enc['attention_mask']: keys in a labelled box. JSON, the format of every API and dataset file in Courses 11–13, is this same structure written as text; {"prompt": ..., "chosen": ..., "rejected": ...} is a dict per training example.
import json
text = json.dumps(enc) # dict → text (to save/send)
back = json.loads(text) # text → dict (to use)
**kwargs and the double-star — the syntax you'll see hourlyTwo related uses. First, in a call — unpack a dict into named arguments:
settings = {"epochs": 3, "batch_size": 16}
train(**settings) # EXACTLY: train(epochs=3, batch_size=16)
Now decode the line from the Course 9 notes that looks like wizardry:
out = model.generate(**tok("Once upon a time", return_tensors='pt'), max_new_tokens=50)
Inside-out: tokenize the text → get a dict-like with input_ids and attention_mask → ** spreads those into generate as named arguments, alongside max_new_tokens. One line, three ideas you already own.
Second, in a definition — accept any named arguments:
def flexible(**kwargs): # kwargs arrives as a dict
print(kwargs)
flexible(lr=0.1, epochs=3) # {'lr': 0.1, 'epochs': 3}
That's why Hugging Face functions accept dozens of options you never see listed: they take **kwargs and pass them along. (*args is the same trick for positional arguments — a tuple instead of a dict.)
Rewrite without the star: LoraConfig(**{"r": 8, "lora_alpha": 16})
@ line above a functionCourse 12 defines tools like this:
@tool
def get_frame_rate(codec: str) -> str:
"""Return the standard frame rate for a codec."""
...
A decorator wraps a function to give it extra behaviour. @tool is exactly get_frame_rate = tool(get_frame_rate) — the function is handed to tool, which returns an upgraded version (here: one registered so an LLM agent can call it).
You need to read decorators, not write them. When you see @something, think: "the function below is being handed to something for superpowers."
Two more pieces of that snippet, while we're here:
codec: str and -> str are type hints — documentation for humans and tools. Python doesn't enforce them. (Course 12's notes: the LLM reads these hints to learn how to call your tool.)def is the docstring — and for agent tools, the notes are emphatic: the docstring IS the tool's spec.with — blocks that clean up after themselveswith open("notes.txt") as f:
text = f.read()
# file is closed here, automatically, even if something failed
with runs a block under a manager that handles setup/teardown. Files close themselves. And now this line from every evaluation loop in Courses 4–13 decodes:
with torch.no_grad():
preds = model(X_test)
"For this indented block, PyTorch: don't build the gradient machinery." Cheaper and correct at inference — the notes use it every time a model is evaluated. Same shape as the file example: enter a context, do the block, the context restores things after.
A lambda is a one-line unnamed function:
double = lambda x: x * 2 # same as: def double(x): return x * 2
clips = ["b.mov", "a.mov", "c.mov"]
clips.sort(key=lambda name: name.lower()) # pass a FUNCTION as an argument
The deeper idea: functions are values. They can be stored, passed, returned. That's what made decorators possible (tool(get_frame_rate) — a function passed to a function), what key= is, and what .map(...) does across LangChain and the datasets library in Courses 12–13.
lambda t: t > 10 as a def.dataset.map(lambda ex: tokenizer(ex["text"])) — what gets passed to the lambda, and what does it return? (Hint: ex is a dict. You know dicts now.)From the Course 12 notes — the RAG chain:
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
rag_chain.invoke("What is the retention policy?")
{...} is a dict: two labelled slots being prepared.RunnablePassthrough(), StrOutputParser() — classes being instantiated. Primer 3.| pipe is LangChain's own operator (not standard Python): "output of the left becomes input of the right." The notes explain the semantics; the syntax is just objects overloading an operator..invoke(...) — a method call on the assembled object.Nothing left in this certificate's code that you can't at least parse. Whenever a line resists: unfold it (comprehensions), name the construct (**? decorator? context manager?), check shapes/keys, and if it still resists — highlight it and ask the teacher to walk it line by line. That's what it's there for.
json.dumps/loads convertf(**d) unpacks a dict into named args; def f(**kwargs) catches any named args as a dict@decorator = "hand the function below to this wrapper" — read, don't writex: str -> str) are documentation, not enforcement; a tool's docstring is its specwith ctx: = managed block; with torch.no_grad(): = "no gradient machinery in here"lambda x: expr = tiny nameless function; functions are values you can pass around| is its own pipe operator: left's output feeds right