<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Extracting attributes and aliasing
Step1:  Let's define a generator xx which selects random elements from items, and two other generators yy and zz which extract individual attributes from these elements.
Step2:  When xx is reset, internally this also automatically resets yy and zz with the same seed (because they are "dependent generators" whose parent is xx).
Step3:  This also works if xx, yy, zz are defined inside a CustomGenerator.
Step4:  Just for illustration, let's repeat the last example but with a different set of items (produced by another custom generator, although this doesn't really matter).
Step5:  
Step6:  Using ExtractAttribute we can produce \"derived\" generators which extract the attributes aaa, bbb from the elements produced by g.
Step7:  Class Lookup
Create mapping from lowercase to uppercase letters.
Step8:  Create generator g which selects a random letter and generator h which looks up each letter in the lowercase->uppercase mapping.
<ASSISTANT_TASK:>
Python Code:
letters = 'abcdefghijklmnopqrstuvwxyz'
Foobar = namedtuple('Foobar', ('foo', 'bar'))
items = [Foobar(c+c, c+c+c) for c in letters]
items[:3]
Explanation: Extracting attributes and aliasing
End of explanation
xx = SelectOne(items)
yy = xx.foo
zz = xx.bar
Explanation: Let's define a generator xx which selects random elements from items, and two other generators yy and zz which extract individual attributes from these elements.
End of explanation
xx.reset(seed=12345)
print_generated_sequence(xx, num=10, sep='\n')
print_generated_sequence(yy, num=10)
print_generated_sequence(zz, num=10)
Explanation: When xx is reset, internally this also automatically resets yy and zz with the same seed (because they are "dependent generators" whose parent is xx).
End of explanation
class QuuxGenerator(CustomGenerator):
    xx = SelectOne(items)
    yy = xx.foo
    zz = xx.bar
    ww = yy  # alias
g = QuuxGenerator()
list(g.generate(10, seed=12345))
Explanation: This also works if xx, yy, zz are defined inside a CustomGenerator.
End of explanation
class FoobarGenerator(CustomGenerator):
    foo = Integer(0, 100)
    bar = HashDigest(length=8)
fg = FoobarGenerator()
items2 = list(fg.generate(10, seed=12345))
items2
class QuuxGenerator(CustomGenerator):
    xx = SelectOne(items2)
    yy = xx.foo
    zz = xx.bar
g = QuuxGenerator()
g.reset(seed=99999); print_generated_sequence(g, num=10, sep='\n')
Explanation: Just for illustration, let's repeat the last example but with a different set of items (produced by another custom generator, although this doesn't really matter).
End of explanation
class QuuxGenerator(CustomGenerator):
    aaa = Integer(0, 100)
    bbb = HashDigest(length=6)
g = QuuxGenerator()
Explanation: 
End of explanation
h1 = ExtractAttribute(g, 'aaa')
h2 = ExtractAttribute(g, 'bbb')
g.reset(seed=99999)
print_generated_sequence(g, num=10, sep='\n')
print_generated_sequence(h1, num=10)
print_generated_sequence(h2, num=10)
Explanation: Using ExtractAttribute we can produce \"derived\" generators which extract the attributes aaa, bbb from the elements produced by g.
End of explanation
letters = 'abcdefghijklmnopqrstuvwxyz'
mapping = dict([(c, c.upper()) for c in letters])
Explanation: Class Lookup
Create mapping from lowercase to uppercase letters.
End of explanation
g = SelectOne(letters)
h = Lookup(g, mapping)
g.reset(seed=12345)
print_generated_sequence(g, num=20)
print_generated_sequence(h, num=20)
Explanation: Create generator g which selects a random letter and generator h which looks up each letter in the lowercase->uppercase mapping.
End of explanation
<END_TASK>