Generating a list of non-primes is much simpler than generating a list of primes. To begin, we need to think about what a prime number is. A prime number is one that is only divisible by 1 and itself. Therefore, if we want to generate a list of non-primes under 50 we can do so by generating multiples.
noprimes = set(j for i in range(2, 8) for j in range(i*2, 50, i))
We are using a set in this case because we only want to include each multiple once. The function range(2, 8) will generate the numbers 2-7. In this example we are using set comprehension to iterate through the numbers 2 through 7. During each iteration we will use the number to iterate through the range 2i through 50 with an interval of i.
Hopefully that isn't too complicated! As an example, the first time we iterate through the outer loop, we generate the number 2. Then we iterate through the inner loop using 2 to produce this range: range(4, 50, 2). This produces: 4, 6, 8, 10, etc until we hit 50. Each of these numbers will be added to our noprimes set.
The next time through we generate the number 3. Then in our inner loop we will produce range(6, 50, 3) which will add 6, 9, 12, 15, etc to our noprimes set.
As you can see, this simply generates multiples. Once we calculate all the multiples through 7 we can be sure that we've generated all of the multiples. Anything 8 or higher will simply duplicate the work we've already done.