Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
List overwritten
#1
My list is overwritten, but I don't see why. The objects are new instances and the list assignment is doing using copy, but the first object's list values are lost after I created the second one.

My code:
class Hex:
    @classmethod

    def __init__(self, cdHex, myList):
        self.cdHex = cdHex
        self.myList = myList.copy()
        
    def getmyList(self):
        return(self.myList)
    
d_hexes={}
d_hexes2={}

hexAct='A'
myList=[2]
d_hexes.update({hexAct:Hex(hexAct,myList)})
d_hexes2.update({hexAct:myList})

print('First')
print(d_hexes[hexAct].getmyList())
print(d_hexes['A'].getmyList())
print(d_hexes2['A'])

hexAct='B'
myList=[3]
d_hexes.update({hexAct:Hex(hexAct,myList)})
d_hexes2.update({hexAct:myList})

print('Second')
print(d_hexes[hexAct].getmyList())
print(d_hexes['A'].getmyList())
print(d_hexes2['A'])
     
exit()
Console results:
Output:
First [2] [2] [2] Second [3] [3] [2]
The second [3] should be [2].

Please, help.
deanhystad write Aug-06-2024, 02:41 PM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#2
__init__ is not a class method. By definition __init__ is an instance method, because it is called when a new instance of a class is created.

When I remove the @classmethod and run your code I get this:
Output:
First [2] [2] [2] Second [3] [2] [2]
@classmethod is used when a method does not use any instance variables (variables that are added to the instance after it is created, usually in the __init__ method), but does use variables that are defined for the class. As an example I modified your hex class to maintain a list of instances and added a classmethod that searches the instances for a matching cdHex value.
class Hex:
    instances = []

    def __init__(self, cdHex, myList):
        self.cdHex = cdHex
        self.myList = myList.copy()
        self.instances.append(self)

    def getmyList(self):
        return self.myList

    @classmethod
    def find(cls, cdHex):
        return [x for x in cls.instances if x.cdHex == cdHex]


Hex("A", [2])
Hex("B", [3])
print(a = Hex.find("A"))
print(b = Hex.find("C"))
[<__main__.Hex object at 0x0000013B05A9DCF0>]
[]
Notice I can call Hex.find() without using an instance of Hex. I could call Hex.find() without creating any instances of Hex. Also notice that the first argument to __init__() is called "self", and the first argument to find() is "cls". The arguments can be named anything, but the convention is to use "self" to refer to an instance of the class and "cls" to refer tot he class. Class methods are passed the class as the first argument and instance methods are passed an instance of the class as the first argument.
Reply
#3
To help understand why declaring __init__() a class method caused your problem, refer to the output of this code:
class Hex:
    @classmethod
    def __init__(self, cdHex, myList):
        self.cdHex = cdHex
        self.myList = myList.copy()

    def getmyList(self):
        return self.myList


before = set(dir(Hex))
a = Hex("A", [2])
print(a.__dict__)  # Print instance variables unique to "a"
print(set(dir(Hex)) - before)  # Print any class variables that were added to Hex by making "a"
Output:
{} {'myList', 'cdHex'}
Because __init__() was declared a class method, the first argument is the class Hex, not an instance of Hex. cdHex and myList are added to the class, and become variables shared by all instances of the class. See what happens when @classmethod is removed:
class Hex:
    def __init__(self, cdHex, myList):
        self.cdHex = cdHex
        self.myList = myList.copy()

    def getmyList(self):
        return self.myList


before = set(dir(Hex))
print(a.__dict__)  # Print instance variables unique to "a"
print(set(dir(Hex)) - before)  # Print any class variables that were added to Hex by making "a"
Output:
{'cdHex': 'A', 'myList': [2]} set()
Now cdHex and myList are instance variables. Each instance of Hex will have their own variables that are not shared with other instances of the class.
Reply
#4
Thank you deanhystad, I hadn't understood well what @Classmetod was for. After you explained it, everything makes sense.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020