<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def graph_edges(self):
 """ Returns a generator for iterating over graph edges The edge of a graph is described by the two adjacent node and the branch object itself. Whereas the branch object is used to hold all relevant power system parameters. Yields ------ int Description #TODO check Note ---- There are generator functions for nodes (`Graph.nodes()`) and edges (`Graph.edges()`) in NetworkX but unlike graph nodes, which can be represented by objects, branch objects can only be accessed by using an edge attribute ('branch' is used here) To make access to attributes of the branch objects simpler and more intuitive for the user, this generator yields a dictionary for each edge that contains information about adjacent nodes and the branch object. Note, the construction of the dictionary highly depends on the structure of the in-going tuple (which is defined by the needs of networkX). If this changes, the code will break. """


        # get edges with attributes
        edges = nx.get_edge_attributes(self._graph, 'branch').items()

        # sort them according to connected nodes
        edges_sorted = sorted(list(edges), key=lambda _: (''.join(sorted([repr(_[0][0]),repr(_[0][1])]))))

        for edge in edges_sorted:
            yield {'adj_nodes': edge[0], 'branch': edge[1]}