You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter货币转换器JSONDecodeError问题求助及代码优化建议

Hey there! Let's break down your problem step by step. That JSON decode error happens because the API response you're trying to parse isn't valid JSON—most likely because your request is failing (returning an empty string or an error page) when run inside the convert function. Here's why that's happening and how to fix it:


First, Fix the Immediate Error

  1. Extract the actual currency code from dropdown selections
    Your dropdown has options like 'ALL: Albania [Lek]', but currency APIs only accept the 3-letter currency code (like ALL). Right now, you're passing the entire string to the API, which causes a malformed request. Add this code inside your convert function to extract the code:

    # Get selected values and extract currency codes
    selected_from = currencyBase_ToConvert_Box.get()
    currencyBase_ToConvert = selected_from.split(':')[0].strip()
    
    selected_to = currencyBase_Converted_Box.get()  # Assumes this is your target currency dropdown
    currencyBase_Converted = selected_to.split(':')[0].strip()
    
  2. Debug the API response
    Before parsing JSON, verify if your request was successful. Add these lines right after making the API call to see what's being returned:

    r = requests.get(your_api_url_here)  # Replace with your actual API call
    print(f"Status Code: {r.status_code}")  # Should return 200 for successful requests
    print(f"Response Content: {r.text}")  # View raw response to spot errors
    

    If you see status codes like 400/403/404, your request is invalid (wrong parameters, missing API key, etc.). Fix the API URL or parameters to match the service's documentation.

  3. Fix variable scoping issues
    If you're relying on global variables inside the convert function, you need to declare them with the global keyword (or better yet, avoid globals entirely):

    def convert():
        global value_Converted  # Declare if you need to update a global variable
        # Rest of your code
    

Next, Pythonic Code Optimizations

Let's clean up your code to make it more maintainable, readable, and idiomatic:

  1. Replace the countries list with a dictionary
    This makes mapping display names to currency codes much simpler:

    CURRENCY_MAP = {
        'ALL': 'Albania [Lek]',
        'AMD': 'Armenia [Armenian Dram]',
        'AUD': 'Australia [Australian Dollar]',
        # Add all your remaining currencies here
    }
    # Generate dropdown options dynamically
    DROPDOWN_OPTIONS = [f"{code}: {name}" for code, name in CURRENCY_MAP.items()]
    
  2. Use a class to organize your UI logic
    Classes eliminate messy global variables and keep related code grouped together:

    import requests
    import tkinter as tk
    from tkinter import ttk, messagebox
    
    class CurrencyConverter:
        def __init__(self, root):
            self.root = root
            self.root.title("Simple Currency Converter")
            
            # Currency data
            self.currency_map = {
                'USD': 'United States [US Dollar]',
                'EUR': 'Eurozone [Euro]',
                'GBP': 'United Kingdom [Pound Sterling]',
                'CNY': 'China [Yuan Renminbi]',
                # Add all your currencies here
            }
            self.dropdown_options = [f"{code}: {name}" for code, name in self.currency_map.items()]
            
            # Initialize UI
            self.create_widgets()
            
        def create_widgets(self):
            # Amount input
            ttk.Label(self.root, text="Amount:").grid(row=0, column=0, padx=5, pady=5)
            self.amount_var = tk.StringVar()
            self.amount_entry = ttk.Entry(self.root, textvariable=self.amount_var)
            self.amount_entry.grid(row=0, column=1, padx=5, pady=5)
            
            # From currency dropdown
            ttk.Label(self.root, text="From:").grid(row=1, column=0, padx=5, pady=5)
            self.from_currency_var = tk.StringVar()
            self.from_dropdown = ttk.Combobox(self.root, textvariable=self.from_currency_var, values=self.dropdown_options)
            self.from_dropdown.grid(row=1, column=1, padx=5, pady=5)
            self.from_dropdown.current(0)  # Set default selection
            
            # To currency dropdown
            ttk.Label(self.root, text="To:").grid(row=2, column=0, padx=5, pady=5)
            self.to_currency_var = tk.StringVar()
            self.to_dropdown = ttk.Combobox(self.root, textvariable=self.to_currency_var, values=self.dropdown_options)
            self.to_dropdown.grid(row=2, column=1, padx=5, pady=5)
            self.to_dropdown.current(1)  # Set default selection
            
            # Convert button
            self.convert_btn = ttk.Button(self.root, text="Convert", command=self.convert)
            self.convert_btn.grid(row=3, column=0, columnspan=2, padx=5, pady=10)
            
            # Result display
            self.result_var = tk.StringVar(value="Result will appear here")
            ttk.Label(self.root, textvariable=self.result_var).grid(row=4, column=0, columnspan=2, padx=5, pady=5)
            
        def fetch_exchange_rate(self, from_code, to_code):
            """Fetch exchange rate from a reliable API"""
            try:
                # Example using exchangerate-api (free tier available)
                response = requests.get(f"https://v6.exchangerate-api.com/v6/YOUR_API_KEY/pair/{from_code}/{to_code}")
                response.raise_for_status()  # Raise error for HTTP issues
                data = response.json()
                return data["conversion_rate"]
            except requests.exceptions.RequestException as e:
                messagebox.showerror("Error", f"Failed to fetch rate: {str(e)}")
                return None
            except KeyError:
                messagebox.showerror("Error", "Unexpected API response format")
                return None
            
        def convert(self):
            """Handle conversion logic with validation"""
            # Validate amount input
            try:
                amount = float(self.amount_var.get())
            except ValueError:
                messagebox.showerror("Invalid Input", "Please enter a valid number")
                return
            
            # Extract currency codes
            from_code = self.from_currency_var.get().split(':')[0].strip()
            to_code = self.to_currency_var.get().split(':')[0].strip()
            
            # Handle same currency conversion
            if from_code == to_code:
                self.result_var.set(f"{amount:.2f} {from_code} = {amount:.2f} {to_code}")
                return
            
            # Fetch rate and calculate result
            rate = self.fetch_exchange_rate(from_code, to_code)
            if rate:
                converted_amount = amount * rate
                self.result_var.set(f"{amount:.2f} {from_code} = {converted_amount:.2f} {to_code}")
    
    if __name__ == "__main__":
        root = tk.Tk()
        app = CurrencyConverter(root)
        root.mainloop()
    
  3. Add user-friendly error handling
    The code above uses messagebox to display clear errors for invalid input, network failures, or API issues instead of crashing silently.

  4. Follow requests best practices

    • Use response.raise_for_status() to automatically catch HTTP errors.
    • Avoid hardcoding API keys—store them in environment variables for security.
    • Use params instead of string concatenation for API parameters (safer and cleaner).

Final Notes

  • Ensure you're using a working currency API—many free services require an API key (like exchangerate-api's free tier).
  • Test your API call outside the function first to confirm it returns valid JSON before integrating it into the UI.

内容的提问来源于stack exchange,提问作者Tessalarius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:51:13