URL: https://linuxfr.org/forums/programmation-python/posts/deuxieme-mouture-script-multi-clock Title: Deuxième mouture script multi clock Authors: Eh_Dis_Mwan Date: 2019年02月01日T17:21:18+01:00 License: CC By-SA Tags: pthon, beginner et oldman Score: 4 Bonjour, Comme décris dans un précédent post https://linuxfr.org/forums/programmation-python/posts/mon-premier-code-python , j'ai fait mon premier script python ( et accessoireent, j'ai découvert le programmation objet également) , qui n'était pas beau du tout J'y ai donc bossé, en fait, en repartant généralement from scratch (je connais l'algo , donc le réécrire n'était pas très compliqué) Et , effectivement, j'ai bien vu ma lacune concernant l'utilisation de self dans les classes Donc, j'ai essayé qu'il passe pylint, ce qui est le cas (je suisparti de -60 à 10 , chouette) Ensuite, j'ai mis la classe clock dans un module et merger les classe App et la classe qui gérait le menu : un menu n'est il pas l'application sans les clocks ? Voilà ce que ça donne (j'ai conscience qu'il n'est pas super, mais j'ai aussi conscience qu'il est moins moche qu'auparavant), j'aurai aussi une question à la fin ```python import sys from tkinter import ( ACTIVE, Menu, Toplevel, Listbox, Button, Tk, Scrollbar, Frame, ) from tkinter.colorchooser import askcolor import os import pytz from Modules import clock class App: """ Main App """ def __init__(self): self.conf = dict() self.conffile = dict() self.conf["timezone"] = [] self.conf["colors"] = [] self.obj = dict() self.root = Tk() self.root.title("Clocks- 土圭") bin_path = os.path.dirname(os.path.realpath(__file__)) self.conffile["tz"] = "{}/tz.conf".format(bin_path) self.conffile["colors"] = "{}/colors.conf".format(bin_path) self.readconftz() print("timezones initialization...OK") print(self.conf["timezone"]) self.readconfcolor() print("Colors initialization...OK") print(self.conf["colors"]) self.create_clock() self.create_menu() self.root.mainloop() def create_clock(self): """ creation of Clock """ self.obj["local"] = clock.Clock( window=self.root, tz="local", place=[0, 1], color=["#880088", "white", "black", "yellow"], ) print("local clock created") self.conf["col"] = 1 self.conf["row"] = 1 for i in self.conf["timezone"]: self.add_clock(i) print("clock for {} created".format(i)) if self.conf["col"] < 9: self.conf["col"] += 1 else: self.conf["col"] = 0 self.conf["row"] += 1 def create_menu(self): menu_bar = Menu(self.root) ope = Menu(menu_bar, tearoff=0) ope.add_command(label="Add Clock", command=self.popup_add_clock) colors = Menu(menu_bar, tearoff=0) for i in self.conf["colors"]: colors.add_command( label=i, background=i, command=lambda x=i: self.setcolors(x) ) self.remove = Menu(ope, tearoff=0) ope.add_cascade(label="Remove Clock", menu=self.remove) ope.add_command( label="Refresh", command=lambda: os.execv(__file__, sys.argv) ) menu_bar.add_cascade(label="Add/Remove", menu=ope) menu_bar.add_cascade(label="Set Colors", menu=colors) self.root.config(menu=menu_bar) for i in self.conf["timezone"]: self.remove.add_command( label=i, command=lambda x=i: self.removetz(x) ) def removetz(self, city): self.obj[city].remove() self.conf["timezone"].remove(city) with open(self.conffile["tz"], "w") as conffile: for i in self.conf["timezone"]: conffile.write("{}\n".format(i)) def setcolors(self, colors): newcolors = askcolor(colors)[1] if newcolors == None: pass else: newcolor = [ newcolors if x == colors else x for x in self.conf["colors"] ] print(self.conf["colors"]) print(newcolor) with open(self.conffile["colors"], "w") as conffile: for i in newcolor: conffile.write("{}\n".format(i)) os.execv(__file__, sys.argv) def popup_add_clock(self): def addtz(): t_z = listbox.get(ACTIVE) with open(self.conffile["tz"], "a") as conffile: conffile.write("{}\n".format(t_z)) self.add_clock(listbox.get(ACTIVE)) self.remove.add_command( label=t_z, command=lambda x=t_z: self.removetz(x) ) list_tz = [ x for x in list(pytz.all_timezones) if x not in self.conf["timezone"] ] print(list_tz) popup = Toplevel() frame = Frame(popup) frame.grid(column=0, row=0, columnspan=2) listbox = Listbox(frame) listbox.grid(column=0, row=0) listbox.insert("end", *list_tz) scrollbar = Scrollbar(frame, orient="vertical", command=listbox.yview) scrollbar.grid(column=2, row=0, sticky="ns") listbox.config(yscrollcommand=scrollbar.set) Button(popup, text="Add it", command=addtz).grid(column=0, row=1) Button(popup, text="Close", command=popup.destroy).grid( column=1, row=1 ) def add_clock(self, i): if (self.conf["col"] + self.conf["row"]) % 2 == 0: color = [ self.conf["colors"][1], self.conf["colors"][0], self.conf["colors"][3], self.conf["colors"][2], ] else: color = self.conf["colors"] self.obj[i] = clock.Clock( window=self.root, tz=i, place=[self.conf["col"], self.conf["row"]], color=color, ) def readconftz(self): """ initialize clocks to create """ try: with open(self.conffile["tz"], "r") as conffile: timezones = conffile.readlines() timezones = list(map(lambda s: s.strip(), timezones)) temp_timezones = [x.split("/") for x in timezones] timezones = [] for lists in temp_timezones: lists.reverse() temp_timezones.sort() for lists in temp_timezones: lists.reverse() self.conf["timezone"].append("/".join(lists)) for i in self.conf["timezone"]: if not i : self.conf["timezone"].remove(i) except FileNotFoundError: self.conf["timezone"] = ["Etc/UTC"] except PermissionError: self.conf["timezone"] = ["Etc/UTC"] if not self.conf["timezone"]: self.conf["timezone"] = ["Etc/UTC"] def readconfcolor(self): """ initialize colors """ try: with open(self.conffile["colors"], "r") as conf_file: colors = conf_file.readlines() self.conf["colors"] = list(map(lambda s: s.strip(), colors)) for i in self.conf["colors"]: if not i : self.conf["colors"][self.conf["colors"].index(i)]='white' if i=='None' : self.conf["colors"][self.conf["colors"].index(i)]='white' except FileNotFoundError: self.conf["colors"] = ["bisque", "maroon", "black", "green"] except PermissionError: self.conf["colors"] = ["bisque", "maroon", "black", "green"] except IndexError: self.conf["colors"] = ["bisque", "maroon", "black", "green"] def main(*args): """ main """ print("Launching the App") App() return args if __name__ == "__main__": sys.exit(main(sys.argv[1:])) ``` Puis le module clock: ```python from tkinter import Frame, Label, Entry, StringVar, Button from tkinter import messagebox import datetime import pytz class Clock: """ For displaying the clocks """ def __init__(self, **kwargs): """ init variables for one Clock """ self.dict_clock = dict() self.dict_clock["hourvar"] = StringVar() self.dict_clock["t_z"] = kwargs.get("tz") self.dict_clock["place"] = kwargs.get("place") self.dict_clock["color"] = kwargs.get("color") self.root = kwargs.get("window") self.dict_clock["separator"] = [".", ":"] self.dict_clock["old_day"] = 32 self.dict_clock["old_year"] = 100000 self.init_display() self.update() def init_display(self): """ create widgets """ framebg = [self.dict_clock["color"][0], self.dict_clock["color"][1]] clockbg = [self.dict_clock["color"][2], self.dict_clock["color"][3]] col = self.dict_clock["place"][0] row = self.dict_clock["place"][1] self.dict_clock["frme"] = Frame(self.root, bg=framebg[0], width=15) self.dict_clock["frme"].grid(row=row, column=col) self.dict_clock["label"] = Label( self.dict_clock["frme"], bg=framebg[0], fg=framebg[1], font=("Helvetica", 14, "underline"), width=15, relief="groove", borderwidth=1, highlightcolor=framebg[0], ) self.dict_clock["label"].grid(row=0, column=0) self.dict_clock["entry"] = Entry( self.dict_clock["frme"], bg=clockbg[0], fg=clockbg[1] ) self.dict_clock["entry"].config( textvariable=self.dict_clock["hourvar"], width=5, font=("Sans", 22, "bold"), ) self.dict_clock["entry"].grid(row=1, column=0) self.dict_clock["labelday"] = Label( self.dict_clock["frme"], bg=framebg[0], fg=framebg[1] ) self.dict_clock["labelday"].config( width=10, height=2, font=("Courier", 10, "bold") ) self.dict_clock["labelday"].grid(row=2, column=0) def update(self): """ update the widgets """ if self.dict_clock["t_z"] != "local": self.timezone = pytz.timezone(self.dict_clock["t_z"]) self.date = datetime.datetime.now(self.timezone) table = self.dict_clock["t_z"].split("/") city = table[-1] else: self.date = datetime.datetime.now() city = "local" minute = str(self.date.minute).zfill(2) day = str(self.date.day).zfill(2) if int(self.dict_clock["old_day"]) < int(day): messagebox.showinfo("info", "{} changed day".format(city)) month = str(self.date.month).zfill(2) year = str(self.date.year).zfill(2) if int(self.dict_clock["old_year"]) < int(year): messagebox.showinfo("info", "HAPPY NEW YEAR {}".format(city)) hour = str(self.date.hour).zfill(2) self.dict_clock["separator"] = self.dict_clock["separator"][::-1] self.dict_clock["label"].config(text=city) self.dict_clock["labelday"].config( text="{}-{}-{}".format(day, month, year) ) self.dict_clock["hourvar"].set( "{}{}{}".format(hour, self.dict_clock["separator"][0], minute) ) self.dict_clock["old_day"] = day self.dict_clock["old_year"] = year self.root.after(500, self.update) def remove(self): self.dict_clock["frme"].grid_forget() ``` Ma question est la suivante: il ne peux pas y avoir plus de 10 (de mémoire) variable de classe, que j'ai contourner en créeant des dictionnaires. N'est ce pas unpythonic de le permettre ? Le code devient moins lisible, concrètement, cela ne change pas grand chose. Les docstrings ne sont pas super précis , mais c'est plus par flegme que pour autre chose J'ai aussi lu que lambda, map etc.. étaient unpythonic, mais comment mapper les options des commandes si un menu est réalisé par une boucle ? (ici le menu pour supprimer des horloges)