0
votes

Les objets Python à l'intérieur d'autres objets ne sont pas isolés

Je m'attendais à ce que les éléments d'objet à l'intérieur d'autres objets python soient isolés. Cependant, le code suivant montre que mon résultat attendu est incorrect. Il semble que python utilise une liste_éléments centrale pour tous les éléments du Groupe . Comment puis-je réparer cela?

python3 --version
Python 3.5.2

Résultat

len =  4
bb2 =  bb1

Version

class Item:
    name = ''
    def __init__(self, name):
        self.name = name


class Group:
    item_list = []

    def __init__(self, item):
        self.item_list.append(item)

g2 = Group(Item('bb1'))
g2.item_list.append(Item('bb2'))

group_list = []
group_list.append(Group(Item('aaa')))
group_list.append(g2)
group_list.append(Group(Item('ccc')))

print('len = ', len(group_list[-1].item_list))
print('bb2 = ', group_list[1].item_list[1].name)


4 commentaires

Votre liste_éléments ainsi que nom sont des variables de classe (pensez à statique en C ++). Placez-les dans le constructeur, comme self.item_list = [] pour en faire des variables d'instance.


class Group: \ n self.item_list = [] me donne NameError: le nom 'self' n'est pas défini .


À l'intérieur du constructeur (c'est-à-dire à l'intérieur de def __init__ . Ne définissez rien au niveau de la classe.


pour référence future: vous pouvez utiliser id () pour vérifier quels objets sont identiques en mémoire. Avec [id (group.item_list) pour groupe dans group_list] vous verrez que toutes les listes sont identiques.


4 Réponses :


1
votes

Les variables déclarées en dehors de la méthode __init__ (dans ce cas item_list ) sont partagées entre toutes les instances d'une classe (appelées variables de classe), c'est pourquoi votre le résultat attendu est faux.

D'un autre côté, les variables à l'intérieur de __init__ n'appartiennent qu'à l'instance donnée de cette classe.


0 commentaires

1
votes

Vos variables de classe d'utilisation, qui sont des variables statiques C ++ similaires à l'intérieur des classes (c'est-à-dire que cette variable est partagée par TOUTES les instances de classe). Vous devez le mettre dans le __init__ (constructeur) pour que chaque classe crée sa propre version:

class Item:
    def __init__(self, name):
        self.name = name

class Group:
    def __init__(self, item):
        self.item_list = []
        self.item_list.append(item)

    # Though typically you would also have a function like this:
    def add_item(self, item):
        self.item_list.append(item)

g2 = Group(Item('bb1'))
g2.item_list.append(Item('bb2'))

group_list = []
group_list.append(Group(Item('aaa')))
group_list.append(g2)
group_list.append(Group(Item('ccc')))

print('len = ', len(group_list[-1].item_list))
print('bb2 = ', group_list[1].item_list[1].name)


0 commentaires

2
votes

Eh bien, tout d'abord, nous devons faire une différence entre les attributs de classe et les attributs d'instance. Un attribut de classe (comme item_list ) appartient à la classe elle-même (dans ce cas "Group"), il sera donc accessible en appelant Group.item_list code>. D'autre part, vous pouvez définir une item_list pour chaque instance de Group en définissant self.item_list = [] dans le constructeur de classe Group ( __init __ code >). Le tableau Group.item_list sera unique pour toute la classe et sera donc adapté pour stocker les éléments que vous souhaitez partager entre les instances (comme g2 ). Le tableau self.item_list (qui sera différent pour chaque instance de Group) contiendra des valeurs exclusivement pour l'instance elle-même, donc chaque Groupe aura sa propre liste_éléments . Je pense que vous visez la deuxième approche (variables d'instance) donc vous devriez déplacer la définition de item_list = [] à l'intérieur du constructeur de classe. Le résultat devrait ressembler à ceci:

class Item:

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


class Group:

    def __init__(self, item):
        self.item_list = []
        self.item_list.append(item)

item1 = Item("itemName")
group1 = Group(item1)

# This should print an array containing the *item1* instance
print(group1.item_list)
print(group1.item_list[0] == item1)


0 commentaires

1
votes

Les attributs instance vs classe sont traités dans d'autres réponses. Je tiens à ajouter que vous pouvez éviter d'avoir des variables d'instance partagées en utilisant un type immuable (par exemple, tuple) au lieu d'un type mutable (par exemple, liste) pour les attributs de classe. Ainsi, ils ne seront pas partagés entre les instances tout en vous permettant de définir les attributs de classe.

class Item:
    name = ''
    def __init__(self, name):
        self.name = name

class Group:

    item_list = tuple()

    def __init__(self, item):
        self.item_list += (item,)


0 commentaires