私はPython3.2GUIアプリケーションをリエンジニアリング(「オブジェクト」化)しており、tkinter GUIオブジェクト(ボタンラベル)をユーザーの言語(起動時に決定され、変更されることはありません)に自動的に適合させます。最初のステップとして、大きな単一のソースファイルを複数のモジュールファイルに分割します。一部の関数を問題なく独自のモジュールファイルに移動できましたが、他の「実績のある」関数は、独自のモジュールファイルから呼び出された場合は機能しません。
「IndexError:string index out of range」エラーは、あるモジュールに存在し、別の(兄弟)モジュールによって設定された変数(「Database_to_use」、以下を参照)を使用しようとすると発生します。変数を変更するプロシージャがメインラインモジュールにある場合、エラーは発生しません。スコーピングの問題や名前の衝突が疑われましたが、私が読んで行ったすべてのことから、両方の可能性が排除されたようです。
「インポート」、点線の参照を使用しており、変更関数にグローバル宣言を配置しています。ドット付き表記は、エンティティの名前を「名前変更」するためにも使用されており、エンティティが存在する場所の実装の詳細から名前を抽象化します。また、モジュール名の変更の範囲をモジュール内の1行に制限します。このアプローチが名前の非表示の問題を引き起こしていないことを確認しました。問題のあるモジュールと問題のある関数(以下の「SelectSqlDatabase」モジュール)の名前を変更した後も、同じ問題が発生しました。ところで、私はグローバルの長所と短所もよく知っています(最終的には消えます)。
次の抜粋では、コードを大幅に編集して(たとえば、1つのボタンのコードのみを表示)、問題を理解するために不可欠ではないものをすべて削除しました。
まず、「SetUpLanguageInUse.py」モジュール。これは、問題のある「Database_to_use」(および問題のない「Main_Title」)変数の場所です。
English = 'English'
Francais = 'Francais'
Database_to_use = "dummy string forces this variable into the global namespace"
Main_Title = "dummy string forces this variable into the global namespace"
def SetUpLanguageInUse( user_language ):
import __main__ # needed to modify the global value
if ( user_language == English ):
__main__.Main_Title = 'Monthly Summary of Reports'
__main__.Database_to_use = ( '', 'Build', 'Staging', 'Production' )
elif ( user_language == Francais ):
__main__.Main_Title = 'Resume Mensuel de Rapports'
__main__.Database_to_use = ( '', 'Construire', 'Relais', 'Production' )
.....
return
上記のモジュールに関するいくつかの所見:
a)問題はユーザーの言語とは無関係です。b)()の代わりに[]を使用しても、問題は解決しませんでした。c)関数内(および/または前)に「globalDatabase_to_use」行を挿入しても効果がありませんでした
d)ダミーの文字列割り当てを削除しても効果がありませんでした
e)メインラインの最初の行(以下を参照)がこの関数を呼び出します。関数に「グローバル」行が含まれている場合、変数は更新されませんでした。「メイン」を使用する理由がわかります。動作しますが、「グローバル」行が存在する場合に変更が機能しないのはなぜですか。
次に、「SelectSqlDatabase.py」モジュールは、問題の関数を保持します。
from tkinter import *
from tkinter import ttk
import LanguageInUse
Database_to_use = LanguageInUse.Database_to_use
Database_List = ( '', 'server1', 'server2', 'server3' )
SQL_Database = "To be determined"
# ----- the problematic function
def SelectSqlDatabase( SelectDatabaseFrame ) :
global SQL_Database
UserSelection = StringVar( value = "Empty" )
Build_DB = Radiobutton( SelectDatabaseFrame,
text = Database_to_use[ 1 ], # the problematic line
variable = UserSelection,
value = Database_List[ 1 ] )
SQL_Database = UserSelection.get()
return
最後にメインライン。このファイルでは、「SelectSqlDatabase」関数はコメントであり、「SelectSqlDatabase.py」の関数と同じであることに注意してください。このコードを「現状のまま」実行すると(つまり、「SelectSqlDatabase.py」の関数を使用して)、次のエラーが発生します。
ファイル"...\ SelectSqlDatabase.py"、65行目、SelectSqlDatabase text = Database_to_use [1]、
IndexError:文字列インデックスが範囲外です
しかし、関数のコメントを解除すると(これにより、「SelectSqlDatabase.py」で関数が非表示になります)、アプリケーションは正しく実行されます。
from tkinter import *
from tkinter import ttk
import LanguageInUse
import SelectSqlDatabase
Database_to_use = LanguageInUse.Database_to_use
Database_List = SelectSqlDatabase.Database_List
English = LanguageInUse.English
SetUpLanguageInUse = LanguageInUse.SetUpLanguageInUse
SQL_Database = SelectSqlDatabase.SQL_Database
SelectSqlDatabase = SelectSqlDatabase.SelectSqlDatabase # gets overridden
# ----- the problematic function
'''
def SelectSqlDatabase( SelectDatabaseFrame ) :
global SQL_Database
UserSelection = StringVar( value = "Empty" )
Build_DB = Radiobutton( SelectDatabaseFrame,
text = Database_to_use[ 1 ], # the problematic line
variable = UserSelection,
value = Database_List[ 1 ] )
SQL_Database = UserSelection
return
'''
'''----------'''
def ChooseDataSourceFrame( mainframe ) :
ChooseSourceFrame = ttk.LabelFrame( mainframe, ... )
SelectDatabaseFrame = ttk.LabelFrame( ChooseSourceFrame )
SelectSqlDatabase( SelectDatabaseFrame )
return
'''***** MAINLINE ***** '''
SetUpLanguageInUse( English ) #TODO: make language a startup parameter
mainframe = ttk.Frame( ... )
ChooseDataSourceFrame( mainframe )
完全を期すために、一度は( "Database_to_use"をパラメーターとして渡すことで)このエラーを排除できましたが、次のような他の厄介なことが起こりました
。a)役に立たないダミータイトルを表示するGUI(「SetUpLanguageInUse」の呼び出しを事実上無視する) )、b)「Database_to_use」にget()関数がないというエラーメッセージが表示される、またはc)「SQL_Database」で返される値がデフォルト値(「未定」)またはUser_Choiceのデフォルト値(」ユーザーが選択したデータベースの代わりに「空」)。
要約すると、私の目的は、ユーザーが選択した(つまり、「Database_List」から抽出された)データベースサーバーに「SQL_Database」を設定することです。tkinterは、「Database_to_use」内に渡された(言語に依存する)文字列を表示します。
私はこの問題の実験と研究に多くの時間を費やしてきましたが、まったく役に立ちませんでした。私が読んだすべてのこと(Python 3.2.3チュートリアルを含む)は、私がしていることが正しいことを示唆していますが、私は単純な何かを見落としていると感じています。どこが間違っているのですか?