Q:

Modificar una variable global desde una función

Tengo un problema. Anteriormente me ayudaron a solucionar un problema con unas funciones; fue muy útil, arreglé ese problema pero llegué a otro, por supuesto jaja. 
Para dar un valor al terminar la aplicación (cuestiones de la función de la app) necesito darle un valor a n desde dentro de la función, pero me dice que la tengo que definir. Pero si la defino al imprimir el valor me da el valor que definí, como si no hubiera servido de nada. 
He tratado de hacer global la variable pero sigue diciendo que la variable no está definida.
Esta es la parte del código que muestra el problema:
import tkinter as tk  

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        # Lo que se hace aqui no es relevante
        # para el problema

    def p1():
        global n
        n = 1

    def p2():
        global n
        n = n + 2

    # Y así en varias funciones más

A:

En general, usar una variable global no es buena idea. Al final de esta respuesta te daré una alternativa.
Pero si quieres usar una variable global, el problema con tu código es que ¡no hay tal variable! 
Cuando dentro de una función pones global n, básicamente le dices a python que, si la función en algún momento intenta cambiar el valor de un símbolo llamado n, el intérprete no debe crear una variable local con ese nombre (que es lo que haría por defecto si no hubieras puesto global n). En su lugar, debe usar la variable global llamada n. Pero esa variable no existe en tu código.
Basta que la añadas. Por ejemplo, antes del  class SampleApp pones
n = 0

Eso ya creará la variable global, con un valor inicial de 0. Cuando las funciones que declaran global n modifiquen el valor de n, lo harán de esa variable global.
Observa que no basta con que la variable exista. Además las funciones deben declararla como global, pues si no cuando por ejemplo p1() hace n=1, se crearía  una variable local en esa función que no afectaría a la global (además la variable local se destruye una vez la función termina).
Alternativa
En lugar de variables globales puedes usar atributos del objeto. Un atributo de un objeto es similar a una variable, pero que pertenece sólo a ese objeto. Se usan escribiendo self.n por ejemplo. 
No obstante en tu caso particular, usar este enfoque te obligaría a cambiar bastantes cosas en el código. Cada una de las funciones p1(), p2(), etc. deberían declarar un parámetro self para poder actuar sobre self.n, pero eso cambiaría la forma en que luego enlazas esos métodos con los botones de tu GUI, ya que tal como lo tienes haces command=SampleApp.p1, por ejemplo, por lo que los estás tratando como métodos de clase y no de objeto. En su lugar deberías poner command=controller.p1 y así con todas las demás (ya que controller es el objeto instancia de la clase SampleApp).
Repito que aunque esto es más correcto, en tu caso puede resultarte más confuso ya que a la vista de tu código se aprecia que no entiendes correctamente los conceptos de programación orientada a objetos.
Actualización
Tras comentarios adicionales del usuario, parece que el problema no estaba solo en el uso de esa variable global, sino en que al mostrar esa variable al final del programa parecía no haber cambiado de valor.
El hecho es que la variable se muestra en una etiqueta, la cual forma parte de un frame que se crea al iniciar el programa. La etiqueta toma una copia del valor que n tiene en ese momento, y ya que estamos al principio su valor es 0. Aunque después se modifique el valor de n, la etiqueta sigue teniendo su valor original 0, hasta que es mostrada al final del todo.
Lo cierto es que la estructura de tu código es un laberinto... pero sin entrar a rehacerlo todo, tal como lo tienes, lo más sencillo será que cambies lo que muestra esa etiqueta justo antes de mostrarla. Aunque el frame se crea al principio, no se muestra hasta el final, y ya que tienes un método específico para mostrar los frames, puede ser ahí donde mires si el frame a mostrar es el último y en ese caso le cambies el texto a la etiqueta por el valor que n tenga en ese instante.
Este sería el nuevo método show_frame():
  def show_frame(self, page_name):
      '''Show a frame for the given page name'''
      frame = self.frames[page_name]
      if page_name == "LastPage":
        frame.children["resultado"]["text"] = n
      frame.tkraise()

Como ves, miramos si page_name es "LastPage", y entonces antes de mostrar ese frame, usamos frame.children para acceder a sus "hijos" (las etiquetas y botones que lo componen) y seleccionamos el hijo llamado  "resultado" (que será la etiqueta para mostrar el valor de n), y cambiamos su texto por el valor que n tiene en ese momento.
En la clase LastPage, cuando creas esa etiqueta debes darle el nombre "resultado", para que el código anterior funcione. Así:
      total = tk.Label(self, bg="black", fg= "white", name="resultado",
                       text=n, font=controller.title_font)

