The following workaround works without the need for local saved icon files or disk writes.
Tested with Python v3.13.7 (Windows 10/11) and Python v3.4.4 (Windows XP/7):
from tkinter import *
tk = Tk()
icon=PhotoImage(height=64, width=64)
icon.put("#FF0000", to=(0,0))
tk.iconphoto(False, icon)
lab = Label(tk, text=' Python Window with replaced icon ')
lab.pack()
tk.mainloop()
Explanations:
Create a new PhotoImage with a size of 64 x 64 pixels:
icon=PhotoImage(height=64, width=64)
Sets the color "#FF0000" (color 'red' as hex-values) to one pixel at coordinates (0,0):
icon.put("#FF0000", to=(0,0))
works same as:
icon.put("#FF0000", to=(0,0,1,1))
# to=(x_start, y_start, x_end, y_end)
Add the image as window icon and automatically scale it down to 16 x 16 pixels, so that the single colored pixel becomes invisible:
tk.iconphoto(False, icon)
Set colorized tkinter window icon (one color):
icon=PhotoImage(height=4, width=4) 
icon.put("#FF0000", to=(0,0,1,1)) 
tk.iconphoto(False, icon)
Set colorized tkinter window icon (four colors):
icon=PhotoImage(height=16, width=16)
icon.put("#FF0000", to=(0,0,8,8))
icon.put("#00FF00", to=(8,0,16,8))
icon.put("#FFFF00", to=(0,8,8,16))
icon.put("#0000FF", to=(8,8,16,16))
tk.iconphoto(False, icon)
Alternative to set colorized window icon (four colors):
icon=PhotoImage(height=16, width=16)
icon.put( ('{' + '#FF0000 ' *8 + '#00FF00 ' *8 + '} ') *8 + ('{' + '#FFFF00 ' *8 + '#0000FF ' *8 + '} ') *8, to=(0,0,16,16))
tk.iconphoto(False, icon)
For colorized images using put() see also:
Why is Photoimage put() slow?