Buggy python submission (verdict: Time Limit Exceeded):
from collections import deque
import heapq

def initialize(value, n):
    return [value]*n

class Graph:
    def __init__(self, n_vertices, edge_list, directed=True):
        self.n_vertices = n_vertices
        self.edge_list = edge_list
        self.directed = directed
        self.n_component = None

        self.V = [Vertex(i) for i in range(n_vertices)]
        self.E = []

        if directed:
            for i, e in enumerate(edge_list):
                tail, head = self.V[e[0]], self.V[e[1]]
                edge = Edge((tail, head), i)
                self.E.append(edge)
                tail.incident.append(edge)
                tail.out_neighbor.append(head)
                head.in_neighbor.append(tail)
            self.n_edges = len(self.E)

        else:
            i = 0
            for e in edge_list:
                tail, head = self.V[e[0]], self.V[e[1]]
                edge = Edge((tail, head), i)
                self.E.append(edge)
                tail.incident.append(edge)
                tail.out_neighbor.append(head)
                head.in_neighbor.append(tail)
                i += 1

                edge = Edge((head, tail), i)
                self.E.append(edge)
                head.incident.append(edge)
                head.out_neighbor.append(tail)
                tail.in_neighbor.append(head)
                i += 1
            self.n_edges = len(self.E)//2

    def __str__(self):
        return "a graph with {0} vertices and {1} edges".format(self.n_vertices, self.n_edges)

    def underlying_graph(self):
        if self.directed:
            return Graph(self.n_vertices, self.edge_list, directed=False)
        else:
            return self
    
    def indeg(self, v):
        return len(v.in_neighbor)

    def outdeg(self, v):
        return len(v.out_neighbor)
    
    def set_vertex_value(self, value_dict):
        for v_name, val_list in value_dict.items():
            for i, v in enumerate(self.V):
                v.set_value(v_name, val_list[i])
    
    def calc_component(self):
        # find the component of a graph by DFS.
        g = self.underlying_graph()
        comp = [None]*self.n_vertices
        counter = 0

        while None in comp:
            idx = comp.index(None)
            for i in g.DFS(idx):
                comp[i] = counter
            counter += 1

        self.n_components = counter

        return comp
    
    def DFS(self, init_idx=0):
        init = {'DFS': initialize(None, self.n_vertices),
                'DFS order': initialize(None, self.n_vertices)}
        self.set_vertex_value(init)

        s = self.V[init_idx]
        length = 0

        stck = []
        stck.append((s, length))
        visited = []
        finished = []
        counter = 0

        while stck:
            v, l = stck.pop()

            if v['DFS'] is not None:
                continue
            visited.append(v.idx)
            v['DFS'] = l
            v['DFS order'] = counter
            counter += 1

            all_visited = True
            for u in v.out_neighbor:
                if u['DFS'] is None:
                    all_visited = False
                    stck.append((u, l+1))

            if all_visited:
                finished.append(visited.pop())

        while len(visited) != 0:
            finished.append(visited.pop())

        return finished

class Vertex(dict):
    def __init__(self, idx):
        self.idx = idx
        self.in_neighbor = []
        self.out_neighbor = []
        self.incident = []
        self.component = None

    def __eq__(self, other):
        if not isinstance(other, Vertex):
            return NotImplemented
        return self.idx == other.idx

    def __lt__(self, other):
        if not isinstance(other, Vertex):
            return NotImplemented
        return self.idx < other.idx

    def __ne__(self, other):
        return not self.__eq__(other)

    def __le__(self, other):
        return self.__lt__(other) or self.__eq__(other)

    def __gt__(self, other):
        return not self.__le__(other)

    def __ge__(self, other):
        return not self.__lt__(other)

    def __str__(self):
        return "vertex {}".format(self.idx)

    def set_value(self, val_name, value):
        self[val_name] = value


class Edge(dict):
    def __init__(self, ends, idx):
        self.tail = ends[0]
        self.head = ends[1]
        self.ends = list(ends)
        self.idx = idx

    def __eq__(self, other):
        if not isinstance(other, Edge):
            return NotImplemented
        return self.idx == other.idx

    def __lt__(self, other):
        if not isinstance(other, Edge):
            return NotImplemented
        return self.idx < other.idx

    def __ne__(self, other):
        return not self.__eq__(other)

    def __le__(self, other):
        return self.__lt__(other) or self.__eq__(other)

    def __gt__(self, other):
        return not self.__le__(other)

    def __ge__(self, other):
        return not self.__lt__(other)

    def __str__(self):
        if self.idx is None:
            return "edge ({0}, {1})".format(self.tail, self.head)
        else:
            return "edge {0}: ({1}, {2})".format(self.idx, self.tail, self.head)

    def is_selfloop(self):
        if self.tail == self.head:
            return True
        else:
            return False

    def set_value(self, val_name, value):
        self[val_name] = value

N, M = map(int, input().split())
info = []
for _ in range(M):
    x, y, _ = map(int, input().split())
    info.append((x-1, y-1))

g = Graph(N, info, directed=False)
g.calc_component()

print(g.n_components)

Fixed submission:
from collections import deque
import heapq        

N, M = map(int, input().split())
edges = {i: [] for i in range(N)}
for _ in range(M):
    x, y, _ = map(int, input().split())
    edges[x-1].append(y-1)
    edges[y-1].append(x-1)

ans = 0
visited = [False]*N
for i in range(N):
    if visited[i]:
        continue
    stack = [i]
    while stack:
        v = stack.pop()
        for u in edges[v]:
            if not visited[u]:
                visited[u] = True
                stack.append(u)
    ans += 1
print(ans)