The way I did it was with lists, so I have:
ranks = ["" "2" "3" "4"...."Q" "K" "A"]
suits = ["S" "H" "C" "D"]
then permuted the above to create the deck:
deck = [["2" "S"] ["2" "H"]....]
and represented the hands like:
player = [["2" "S"] ["2" "H"]]
bot = [["3" "S"] ["3" "H"]]
then board:
board = [["4" "S"] ["4" "H"] ["4" "D"] ["4" "C"] ["5" "S"] ["6" "S"]]
then evaluated the hands from:
playerFinalHand = [player board]
### = [[["2" "S"] ["2" "H"]] [["4" "S"] ["4" "H"] ["4" "D"] ["4" "C"] ["5" "S"] ["6" "S"]]]
The reasoning was for evaluation, so if I want to compare hand-strengths (pair > pair ?), or check if said hand is a straight, I just compared the indices on the ranks list (since the computer things that "Q" > "K").
I took some minor inspiration from here:
https://www.udacity.com/course/cs212. I think he uses a list of strings as well, but not the same representations that I used.
Norvig doesn't really make an argument either way, but it all breaks down to how you want to evaluate the hands. If you are going to use the 2+2 evaluator, then you may have to try other ways, but I don't know how those work.
I think representing the deck as a list is better since it is easier to mutate and Python -- if that is what you are using -- has cleaner list operations than any other data structure, IMO.