Q:

How do i change these two balls into many of them?

i recently start learning about python, and made simple source of 2 balls in canvas which are moving with 2d vector rule. i want multiply the number of balls with list in python. here is source of that.
import time
import random
from tkinter import *
import numpy as np
import math
window = Tk()
canvas = Canvas(window,width=600,height=400)
canvas.pack()

canvas.create_rectangle(50,50,550,350)

R = 15
x1 = random.randrange(50+R,550-R)
y1 = random.randrange(50+R,350-R)
x2 = random.randrange(50+R,550-R)
y2 = random.randrange(50+R,350-R)
vx1 = random.randrange(1 , 10)
vy1 = random.randrange(1 , 10)
vx2 = random.randrange(1 , 10)
vy2 = random.randrange(1 , 10)
ntime = 100000
dt = .1

for iter in range(ntime):

    x1 += vx1*dt
    y1 += vy1*dt
    x2 += vx2*dt
    y2 += vy2*dt
    c1 = canvas.create_oval(x1-R,y1-R,x1+R,y1+R,fill="red")
    c2 = canvas.create_oval(x2-R,y2-R,x2+R,y2+R,fill="blue")
    if (x1 > 550-R):
        vx1 = -vx1
    if (x1 < 50+R ):
        vx1 = -vx1
    if (x2 > 550-R):
        vx2 = -vx2
    if (x2 < 50+R ):
        vx2 = -vx2
    if (y1 > 350-R) or (y1 < 50+R):
        vy1 = -vy1
    if (y2 > 350-R) or (y2 < 50+R):
        vy2 = -vy2
    if (x2-x1)**2 + (y2-y1)**2 <= 4*R*R:

        vector1 = np.array([x1,y1])
        vector2 = np.array([x2,y2])
        vvector1 = np.array([vx1,vy1])
        vvector2 = np.array([vx2,vy2])
        nvector = np.array([x2-x1,y2-y1])
        un = (nvector)/((sum(nvector*nvector))**(1/2))
        tvector = np.array([y1-y2,x2-x1])
        ut = tvector/((sum(nvector*nvector))**(1/2))
        vector1midn = sum(vvector1*un)
        vector2midn = sum(vvector2*un)
        vector1midt = sum(vvector1*ut)
        vector2midt = sum(vvector2*ut)
        vector1after = vector2midn*un + vector1midt*ut
        vector2after = vector1midn*un + vector2midt*ut
        vx1 = vector1after[0]
        vy1 = vector1after[1]
        vx2 = vector2after[0]
        vy2 = vector2after[1]

    txt = canvas.create_text(100,30,text=str(iter),font=('consolas', '20', 
'bold'))

    window.update()
    time.sleep(0.002)

    if iter == ntime-1 : break  

    canvas.delete(c1)
    canvas.delete(c2)
    canvas.delete(txt)

window.mainloop()

exact question is, how do i change c1,c2 , above there , into many of them without simply typing every single ball.

A:

Question: How do i change these two balls into many of them?

Create a class object for each Ball or pair of Balls.
This results in, all Balls using the same rules.

Note: I show only one Ball per class object, not a pair of Balls and without collision detection!

class Ball:
    R = 15

    def __init__(self, parent=None, color=None):
        self.parent = parent

        # Define shortcuts
        radius = self.R

        # Random bbox Ellipse coordinates of the ball.
        x = random.randrange(50 + radius, 550 - radius)
        y = random.randrange(50 + radius, 350 - radius)
        coord1 = (x - radius, y - radius, x + radius, y + radius)

        # Random direction
        x = random.randrange(1, 10)
        y = random.randrange(1, 10)
        self.direction = (x, y)

        # Save the bbox coordinate of the ball
        self.coord1 = self.bbox(coord1, self.direction)

    def bbox(self, coord1=None, direction=None):
        # Return if NO move
        if coord1 is None:
            return self.coord1

        return (coord1[0] + direction[0],
                coord1[1] + direction[1],
                coord1[2] + direction[0],
                coord1[3] + direction[1]
                )

    def vector_rule(self):
        # Get the estimated new bbox coordinate of the Ball
        coord1 = self.bbox(self.coord1, self.direction)

        # Define shortcuts
        R = self.R
        x1 = coord1[0]
        y1 = coord1[1]
        vx1 = self.direction[0]
        vy1 = self.direction[1]

        # Boundary check
        if (x1 > 530 - R):
            vx1 = -vx1

        if (x1 < 35 + R):
            vx1 = -vx1

        if (y1 > 330 - R) or (y1 < 35 + R):
            vy1 = -vy1

        # Save the new direction - could be the same as before
        self.direction = (vx1, vy1)

        # Save the new bbox coordinate of the Ball
        self.coord1 = self.bbox(self.coord1, self.direction)

        # Return the move offsets
        return self.direction

Usage:  

Create a class BallCanvas, in .create_balls(... loop to create class Ball objects and Canvas create_oval(... objects.
Accumulate both in a list, loop this list to move the Balls using canvas.move(..., according the result of Ball.vector_rules(....
class BallCanvas(tk.Canvas):
    def __init__(self, parent, width, height):
        self.parent = parent
        super().__init__(parent, width=width, height=height)
        self.create_rectangle(50, 50, 550, 350)
        self.grid(row=1)

        self.balls = []
        self.create_balls()

    def create_balls(self):
        for n in range(5):
            for color in ['red', 'blue']:
                ball = Ball()
                self.balls.append((self.create_oval(ball.bbox(), fill=color, tags='ball'), ball))

    def move_balls(self):
        for id, ball in self.balls:
            new_x, new_y = ball.vector_rule()
            self.move(id, new_x, new_y)

Main Application:  

Move the Ball objects using Tkinter .after(150, ....
This means. all Ball objects moved every 150ms.
class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.geometry("610x430+650+280")

        self.canvas = BallCanvas(self, width=600, height=400)

        self.count = 200
        self.after(500, self.move)

    def move(self):
        self.count -= 1    
        self.canvas.move_balls()

        if self.count > 0:
            self.after(150, self.move)

if __name__ == "__main__":
    App().mainloop()

Tested with Python: 3.5

