Unterschied zwischen Variablen innerhalb und außerhalb von __init__() (Klassen- und Instanzattribute)

Lesezeit: 8 Minuten

Benutzeravatar von Teifion
Teifion

Gibt es neben dem Namen überhaupt einen Unterschied zwischen diesen Klassen?

class WithClass ():
    def __init__(self):
        self.value = "Bob"
    def my_func(self):
        print(self.value)

class WithoutClass ():
    value = "Bob"

    def my_func(self):
        print(self.value)

Macht es einen Unterschied, ob ich die nutze oder nicht __init__ Methode zum Deklarieren der Variablen value?

Meine Hauptsorge ist, dass ich es auf eine Weise verwende, wenn mir das später weitere Probleme bereiten wird.

  • Eine ausführliche Antwort mit Beispielen in der doppelten Frage: stackoverflow.com/a/9056994/911945

    – Anton Tarasenko

    27. Oktober 2018 um 15:23 Uhr

Benutzeravatar von S.Lott
S. Lott

Variables Set außen __init__ gehören zur Klasse. Sie werden von allen Instanzen geteilt.

Innerhalb erstellte Variablen __init__ (und alle anderen Methodenfunktionen) und mit vorangestellt self. gehören zur Objektinstanz.

  • Das ist nicht das, was Python für mich tut. Listen/Diktate/usw. werden von allen Instanzen gemeinsam genutzt, wenn Sie sie nicht in erstellen __init__().

    – zu viel php

    8. Oktober 2009 um 11:43 Uhr

  • @too much php: Alle Variablen der Klassenmethode (unabhängig von der Veränderlichkeit – Listen und Diktate sind veränderbar) werden geteilt. Bei unveränderlichen Objekten ist die gemeinsame Nutzung nicht interessant. Bei veränderlichen Objekten (Listen und Diktate) ist die gemeinsame Nutzung von Bedeutung.

    – S. Lott

    8. Oktober 2009 um 11:58 Uhr

  • Ich vermutete, dass dies der Fall sein könnte, dachte mir aber, dass es von der Frage selbst ablenken könnte, wenn ich meine Annahmen darlege. Prost auf die Klärung 🙂

    – Teifion

    8. Oktober 2009 um 18:54 Uhr

  • Ich dachte, das war, was passierte, aber es war mir sehr unklar. Danke für die Klärung.

    – dimo414

    22. Februar 2011 um 10:49 Uhr

  • Das ist etwas irreführend. EIN varnameVariablensatz außerhalb der drin gehört zur Klasse und kann über gelesen werden self.varname denselben Wert für alle Instanzen erzeugen. Wenn jedoch ein Wert über eine Instanzreferenz zugewiesen wird (wie in self.varname = X) a Neu self.varname wird erstellt nur für diesen Fall, wodurch die Klassenvariable verdeckt wird. Die Klassenvariable bleibt über eine Klassenreferenz erreichbar (zB: WithClass.varname). Und Klassenvariablen können auch von jeder Methode aus festgelegt werden, indem der Klassenname vorangestellt wird (WithClass.myvar = X) anstelle einer Instanzreferenz (self.myvar = X).

    – Lobotomik

    8. März 2017 um 11:26 Uhr

Ohne Selbst

Erstellen Sie einige Objekte:

class foo(object):
    x = 'original class'

c1, c2 = foo(), foo()

Ich kann die c1-Instanz ändern, und die c2-Instanz wird davon nicht betroffen:

c1.x = 'changed instance'
c2.x
>>> 'original class'

Aber wenn ich die Klasse foo ändere, werden auch alle Instanzen dieser Klasse geändert:

foo.x = 'changed class'
c2.x
>>> 'changed class'

Bitte beachten Sie, wie Python Scoping hier funktioniert:

c1.x
>>> 'changed instance'

Mit Selbst

Das Ändern der Klasse wirkt sich nicht auf die Instanzen aus:

class foo(object):
    def __init__(self):
        self.x = 'original self'

c1 = foo()
foo.x = 'changed class'
c1.x
>>> 'original self'

  • Beachten Sie, dass dieses Beispiel nur für neue Typklassen funktioniert, bei alten haben sie das gleiche Ergebnis

    – Abdelouahab

    4. Januar 2015 um 0:57 Uhr

  • @Abdelouahab, ist das so? Ich habe es mit alten Stilklassen versucht und das gleiche Ergebnis wie neue Stilobjekte erhalten. Python 2.7.8

    – Bauer

    6. August 2015 um 1:01 Uhr

alejandros Benutzeravatar
Alejandro

Ich möchte etwas zu den Antworten hinzufügen, die ich in diesem Thread und diesem Thread (der auf diesen verweist) gelesen habe.

Haftungsausschluss: Diese Bemerkungen stammen von den Experimenten, die ich durchgeführt habe

Variablen außerhalb __init__:

Dies sind in der Tat statische Klassenvariablen und sind daher für alle Instanzen der Klasse zugänglich.

Variablen drin __init__:

Der Wert dieser Instanzvariablen sind nur für die jeweilige Instanz zugänglich (über die self Hinweis)

Mein Beitrag:

Eine Sache, die Programmierer bei der Verwendung beachten müssen statische Klassenvariablen ist, dass sie von beschattet werden können Instanzvariablen (Wenn Sie auf die zugreifen statische Klassenvariablen durch die self Hinweis).

Erläuterung:

Früher dachte ich, dass beide Arten der Deklaration der Variablen genau gleich seien (dumm), und das lag teilweise daran, dass ich über die auf beide Arten von Variablen zugreifen konnte self Hinweis. Als ich jetzt in Schwierigkeiten geriet, habe ich das Thema recherchiert und aufgeräumt.

Das Problem mit dem Zugriff statische Klassenvariablen durch die
self Referenz ist, dass es nur auf die verweist statische Klassenvariable wenn es keine gibt Instanzvariable mit demselben Namen, und um die Sache noch schlimmer zu machen, versuchen Sie, a neu zu definieren statische Klassenvariable durch die self Verweis funktioniert nicht, weil ein Instanzvariable entsteht, die dann das bisher Zugängliche überschattet statische Klassenvariable.

Um dieses Problem zu umgehen, sollten Sie immer referenzieren statische Klassenvariablen durch den Namen der Klasse.

Beispiel:

#!/usr/bin/env python

class Foo:
    static_var="every instance has access"

    def __init__(self,name):
        self.instance_var="I am %s" % name

    def printAll(self):
        print 'self.instance_var = %s' % self.instance_var
        print 'self.static_var = %s' % self.static_var
        print 'Foo.static_var = %s' % Foo.static_var

f1 = Foo('f1')

f1.printAll()

f1.static_var="Shadowing static_var"

f1.printAll()

f2 = Foo('f2')

f2.printAll()

Foo.static_var="modified class"

f1.printAll()
f2.printAll()

Ausgabe:

self.instance_var = I am f1
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = every instance has access
self.instance_var = I am f2
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = modified class
self.instance_var = I am f2
self.static_var = modified class
Foo.static_var = modified class

Ich hoffe, das ist hilfreich für jemanden

  • Das ist hier die wichtigste Antwort

    – gowthz

    27. Dezember 2021 um 10:13 Uhr

Neils Benutzeravatar
Neil

nach der Antwort von S.Lott werden Klassenvariablen an die Metaklasse übergeben Neu -Methode und kann über das Wörterbuch aufgerufen werden, wenn eine Metaklasse definiert ist. Auf Klassenvariablen kann also bereits zugegriffen werden, bevor Klassen erstellt und instanziiert werden.

zum Beispiel:

class meta(type):
    def __new__(cls,name,bases,dicto):
          # two chars missing in original of next line ...
          if dicto['class_var'] == 'A':
             print 'There'
class proxyclass(object):
      class_var="A"
      __metaclass__ = meta
      ...
      ...

class User(object):
    email="none"
    firstname="none"
    lastname="none"

    def __init__(self, email=None, firstname=None, lastname=None):
        self.email = email
        self.firstname = firstname
        self.lastname = lastname

    @classmethod
    def print_var(cls, obj):
        print ("obj.email obj.firstname obj.lastname")
        print(obj.email, obj.firstname, obj.lastname)
        print("cls.email cls.firstname cls.lastname")
        print(cls.email, cls.firstname, cls.lastname)

u1 = User(email="abc@xyz", firstname="first", lastname="last")
User.print_var(u1)

Im obigen Code hat die User-Klasse 3 globale Variablen, jede mit dem Wert „none“. u1 ist das Objekt, das durch Instanziieren dieser Klasse erstellt wird. Die Methode print_var gibt den Wert von Klassenvariablen der Klasse User und Objektvariablen des Objekts u1 aus. In der unten gezeigten Ausgabe wird jede der Klassenvariablen User.email, User.firstname und User.lastname Wert hat 'none'während die Objektvariablen u1.email, u1.firstname und u1.lastname Werte haben 'abc@xyz', 'first' und 'last'.

obj.email obj.firstname obj.lastname
('abc@xyz', 'first', 'last')
cls.email cls.firstname cls.lastname
('none', 'none', 'none')

In Python kommt eine Klasse mit Elementfunktionen (Methoden), Klassenvariablen, Attribute/Instanzvariablen (und wahrscheinlich Klassenmethoden zu):

class Employee:

    # Class Variable
    company = "mycompany.com"

    def __init__(self, first_name, last_name, position):
        # Instance Variables
        self._first_name = first_name
        self._last_name = last_name
        self._position = position

    # Member function
    def get_full_name(self):
        return f"{self._first_name} {self._last_name}"

Durch Erstellen einer Instanz des Objekts

my_employee = Employee("John", "Wood", "Software Engineer")

Wir lösen im Wesentlichen aus __init__ das wird die initialisieren Instanzvariablen des neu geschaffenen Employee. Das bedeutet, dass _first_name, _last_name und _position sind explizite Parameter des Spezifischen my_employee Beispiel.

Ebenfalls, Mitgliedsfunktionen Informationen zurückgeben oder den Status einer bestimmten Instanz ändern.


Jetzt jede außerhalb des Konstruktors definierte Variable __init__ gelten als Klassenvariablen. Diese Variablen werden von allen Instanzen der Klasse gemeinsam genutzt.

john = Employee("John", "Wood", "Software Engineer")
bob = Employee("Bob", "Smith", "DevOps Engineer0")

print(john.get_full_name())
print(bob.get_full_name())
print(john.company)
print(bob.company)

>>> John Wood
>>> Bob Smith
>>> mycompany.com
>>> mycompany.com

Sie können auch verwenden Klassenmethoden um die Klassenvariable für alle Instanzen der Klasse zu ändern. Zum Beispiel:

@classmethod
def change_my_companys_name(cls, name):
    cls.company = name

und nun change_my_companys_name()

bob.change_my_companys_name("mynewcompany.com")

wirkt sich auf alle Instanzen der Klasse aus Employee:

print(bob.company)
print(john.company)

>>> mynewcompany.com
>>> mynewcompany.com

Benutzeravatar von John Friday
Johannes Freitag

Beispielcode:

class inside:
    def __init__(self):
        self.l = []

    def insert(self, element):
        self.l.append(element)


class outside:
    l = []             # static variable - the same for all instances

    def insert(self, element):
        self.l.append(element)


def main():
    x = inside()
    x.insert(8)
    print(x.l)      # [8]
    y = inside()
    print(y.l)      # []
    # ----------------------------
    x = outside()
    x.insert(8)
    print(x.l)      # [8]
    y = outside()
    print(y.l)      # [8]           # here is the difference


if __name__ == '__main__':
    main()

  • Aber wenn ich L verwende, um ein int zu speichern, kann ich das L sogar für das äußere x ändern, ohne das L des äußeren y zu ändern …

    – Oskar Hofmann

    5. Juli 2021 um 11:29 Uhr

1398940cookie-checkUnterschied zwischen Variablen innerhalb und außerhalb von __init__() (Klassen- und Instanzattribute)

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy