Есть ли хороший пример page object pattern на python?
Пример лень гуглить, проще ответить на ваш вопрос. 
Page Object разделяет автотесты на три уровня: 
1 - Локаторы. Это, фактически, набор констант.
Выделять их в отдельные файлы и классы нужно по двум, основным, причинам:  
- Так их проще поддерживать и актуализировать. А борьба с "устаревшими" локаторами - это чуть ли не половина всей работы по поддержке автотестов в рабочем состоянии. 
- Для того, что бы можно было ссылаться на один и тот же элемент в рамках разных страниц.
2 - Страницы и их объекты: 
На этом уровне абстракции содержится бизнес логика приложения и её интерфейсное воплощение.
Такой подход, опять же, позволяет упрощать поддержку. Структура автотестов соответствует структуре интерфейса. 
3 - Логика тестов. 
Здесь уже содержатся конкретные степы и assertы для оных. 
Такое деление позволяет чётко понимать, что и где тебе надо менять в зависимости от ситуации. 
Поменялся элемент, но логика приложения осталась прежняя - заменил локатор. Поменялась логика и структура приложения - актуализируешь Page. Нужно актуализировать\дополнить сам тест (т.е. последовательность степов и Expected Result) -> меняешь сам тест. 
Надеюсь поможет. :)
у нас свой фреймворк, мы делаем end-to-end тестирование embedded системы через GUI.
я не выношу локаторы, они прописаны в классе в функциях.
Некоторые у нас выносят в локаторы в отдельные файлы. Можно и так, однако я не вижу преимущества. 
Так я точно знаю какие локаторы относятся к какой странице. Начала вылетать функция, поправил локатор, не стало страницы, выкинул, поправил последовательность в тесте. Старые локаторы "автоматически" удаляются вместе со старыми page-объектами. 
В нашем случае нам не приходится ссылатъся на один и тот же элемент в рамках разных страниц, потому что у нас дерево виджетов построено от страницы, и даже если виджеты одинаково называются это совершенно разные обьекты. В веб-тестировании, однако, это не так, поэтому аргумент резонный. 
tf тут это ссылка на тест-фреймворк, который дает нам базовые функции для взаимодействия с GUI. class LoginView:
	def __init__(self):
	  self.viewname='ABC'
	def enter(self):
	  tf.executeApiCall()
	def wait_for_view(self):
		tf.wait_for_view(self.viewname)
	def press_cancel_button(self):
		tf.press_widget('xyz.ABC')
	def enter_username(self, u):
		tf.enter_string('xyz.ABC.inputfield', u)
	def check_error_popup_visible(self,expect):
		if expect==True:
			tf.wait_for_view(view='xyz.ABC.LoginErrorPopup')
		else:
	 		tf.wait_for_view(notinview='xyz.ABC.LoginErrorPopup')
	def press_login_button(self):
		tf.press_widget('xyz.ABC.Login')
на стороне теста выглядит как-то такusername='Kolya'
main_view = MainView()
login_view = LoginView()
login_view.enter()
login_view.wait_for_view()
login_view.enter_username(u=username)
login_view.press_login_button()
login_view.check_error_popup_visible(expect=True)
login_view.confirm_error_popup()
login_view.check_error_popup_visible(expect=False)
login_view.check_inputfield_text_equals(expect=username)
login_view.leave()
main_view.wait_for_view()