简体   繁体   中英

How to prevent appending duplicates of class objects into Python lists?

I am creating a sport team database which stores information about a sports team. One of the issues I have come across in one of my methods was inability to prevent the same object from appending into a list twice. I do not want the user adding the same information twice, but I am not entirely sure how to resolve this issue.

I am working under Python Tkinter to create this program.

import tkinter as tk
from tkinter import ttk
from tkinter import messagebox


allTeamlist = []



class Team: 

 def __init__(self, team, coach):
   self.team = team
   self.coach = coach
   self.studentsinTeam = []


class MainScreen:
 def __init__(self):

  self.mainscreen = tk.Tk()
  self.mainscreen.title("GUI")
  self.mainscreen.geometry("700x400")

#####Team Buttons##########
  heading3 = tk.Label(self.mainscreen, text= "Team", foreground = "Red", font=("Arial", 10))
  heading3.pack()

  button6 = tk.Button(self.mainscreen, text = "Add New Team", command= self.ShowScreen6)
  button6.pack()

 def OpenWindow(self):
  tk.mainloop()

 def ShowScreen6(self):
  self.mainscreen.destroy()
  screen6 = AddTeamScreen()

class AddTeamScreen:

 def __init__(self):
  self.Tscreen1 = tk.Tk()
  self.Tscreen1.title("Add Team")
  self.Tscreen1.geometry("700x400")

  self.getTeam = tk.StringVar()
  self.getCoach = tk.StringVar()

  self.teamlabel = tk.Label(self.Tscreen1, text = "Add a new Team")
  self.teamlabel.pack()

  self.teamentry = tk.Entry(self.Tscreen1, textvariable= self.getTeam)
  self.teamentry.pack()

  self.coachlabel = tk.Label(self.Tscreen1, text= "Coach")
  self.coachlabel.pack()

  self.coachentry = tk.Entry(self.Tscreen1, textvariable = self.getCoach)
  self.coachentry.pack()

  self.addbutton = tk.Button(self.Tscreen1, text = "Add Team", command = self.addingteammethod)
  self.addbutton.pack()

 def addingteammethod(self):

  addTeam = self.getTeam.get()
  addCoach = self.getCoach.get()

  newTeamtoAdd = Team(addTeam, addCoach)

  if newTeamtoAdd in allTeamlist: 
   messagebox.showerror("Error", "Exists")

  elif newTeamtoAdd not in allTeamlist:
   allTeamlist.append(newTeamtoAdd)
   messagebox.showinfo("SUCCESS", "ADDED")
   print(allTeamlist)

mainscreen = MainScreen()
mainscreen.OpenWindow()

I am new OOP and Tkinter programming so I am still learning? How do I prevent this occurance from happening?

Take a look at this example:

class Team:

    def __init__(self, name, coach):
        self.name = name
        self.coach = coach

team1 = Team("The Teamsters", "Coachy McCoachFace")
team2 = Team("The Teamsters", "Coachy McCoachFace")
teams = [team1, team2]

print(f"Do team1 and team2 have the same identity?: {id(team1)==id(team2)}")
print(f"id(team1): {id(team1)}")
print(f"id(team2): {id(team2)}")

print(f"Are team1 and team2 equivalent?: {team1==team2}")

is_new_team_in_list = Team("The Teamsters", "Coachy McCoachFace") in teams
print(f"Is a new team with the same content in the list?: {is_new_team_in_list}")

Output:

Do team1 and team2 have the same identity?: False
id(team1): 46804752
id(team2): 47020080
Are team1 and team2 equivalent?: False
Is a new team with the same content in the list?: False

The first print statement checks to see if the two team objects have the same identity (if they are the same object in memory - both variables team1 and team2 are bound to the same Team object). This is false.

The next two print statements show the ids of the two team objects - as you can see they are different - therefore, there exist two separate team objects with the same content.

The next print statement determines whether or not the two team objects share the same content (if they are equivalent) - at least that's what it looks like, since we're using == . However, since we did not implement the __eq__ magic method for our Team class, the default behavior falls back to an identity comparison, which we already know will be false.

Finally, the last print statement checks to see if a brand new Team object with the same content will be found in the list of teams using in . The result is false again for the same reasons as above.

One solution is to implement __eq__ for your Team class:

class Team:

    def __init__(self, name, coach):
        self.name = name
        self.coach = coach

    def __eq__(self, other):
        if isinstance(other, Team):
            return self.name == other.name and self.coach == other.coach
        return False

team1 = Team("The Teamsters", "Coachy McCoachFace")
team2 = Team("The Teamsters", "Coachy McCoachFace")
teams = [team1, team2]

print(f"Do team1 and team2 have the same identity?: {id(team1)==id(team2)}")
print(f"id(team1): {id(team1)}")
print(f"id(team2): {id(team2)}")

print(f"Are team1 and team2 equivalent?: {team1==team2}")

is_new_team_in_list = Team("The Teamsters", "Coachy McCoachFace") in teams
print(f"Is a new team with the same content in the list?: {is_new_team_in_list}")

Output:

Do team1 and team2 have the same identity?: False
id(team1): 46016240
id(team2): 46936048
Are team1 and team2 equivalent?: True
Is a new team with the same content in the list?: True

Now you get the desired behavior. Note that the Team object's identities are still different, which is expected. You can also change the behavior of the __eq__ method to suit your needs. For example, you may want to treat two teams as being the same if only their names match.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM