Как изменить переменную класса python

Подскажите как можно изменить переменные в "init" из метода "update_A", в чем ошибка? Заранее спасибо за ответ! class A(object): def __init__(self): self.name = 'Bor...

Подскажите как можно изменить переменные в «init» из метода «update_A», в чем ошибка? Заранее спасибо за ответ!

class A(object):
    def __init__(self):
        self.name = 'Boris'
        self.age = 12
        
    def update_A(self):
        self.name = 'Ivan'
        self.age = 30
        
X = A().update_A
print(X.name(), X.age())

задан 27 ноя 2020 в 6:38

АЛЕКСЕЙ Корин's user avatar

вам надо вызвать update_A. У вас self.name и self.age это не методы поэтому надо убрать круглые скобки

class A(object):
    def __init__(self):
        self.name = 'Boris'
        self.age = 12
        
    def update_A(self):
        self.name = 'Ivan'
        self.age = 30
        
X = A()
X.update_A() 
print(X.name, X.age) 

а если хотите чтобы работало в одну строку то надо добавить return self в конец метода update_A

class A(object):
    def __init__(self):
        self.name = 'Boris'
        self.age = 12
        
    def update_A(self):
        self.name = 'Ivan'
        self.age = 30
        return self

X = A().update_A() 
print(X.name, X.age)

ответ дан 27 ноя 2020 в 6:45

Danis's user avatar

DanisDanis

18.3k4 золотых знака19 серебряных знаков52 бронзовых знака

2

Ну, все методы вызываются с помощью (). То есть, ваш вызов должен быть:

X = A().update_A()

Это должно сработать.

И добавьте ещё return self в конце метода, иначе не будет работать в одну строку и придётся делать так:

X = A()
X.update_A()

ответ дан 27 ноя 2020 в 6:42

DGDays's user avatar

DGDaysDGDays

2,7232 золотых знака13 серебряных знаков45 бронзовых знаков

4

При изучении объектно-ориентированного программирования на Python может возникнуть несколько сложностей, когда дело доходит до разграничения переменных класса и экземпляра. В этом руководстве я объясню разницу между переменными класса и экземпляра и приведу примеры, демонстрирующие различные варианты использования.

Переменные класса и экземпляра

Во-первых, быстрый обзор, если вы новичок в объектно-ориентированном программировании. Класс — это шаблон для создания объектов, а экземпляр — это сам объект. Классы часто представляют что-то в реальном мире, так что представьте, хотите ли вы создать класс, списка студентов. Вы можете создать класс с именем Student, который представляет собой шаблон, который определяет различные атрибуты студента. Таким образом, каждый студент является экземпляром класса Student.

При работе с данными любого типа некоторые атрибуты будут уникальными, а некоторые будут общими. Рассмотрим пример с учениками: у каждого учащегося в этом классе один и тот же номер и один учитель, но у каждого из них есть уникальное имя, возраст и любимый предмет.

Переменные класса

Переменные класса обычно являются переменными, которые являются общими для всех экземпляров. И они определены так:

class Student:
   teacher = 'Mrs. Jones'  # переменная класса

Каждый экземпляр класса будет иметь одинаковое значение для этих переменных:

tom = Student()
susan = Student()

print(tom.teacher)
>> "Mrs. Jones"

print(susan.teacher)
>> "Mrs. Jones"

Переменные экземпляра

Переменные экземпляра (также называемые атрибутами данных) уникальны для каждого экземпляра класса и определяются в методе класса, например:

class Student:
   teacher = 'Mrs. Jones'  # переменная класса   

   def __init__(self, name):
       self.name = name  # переменная экземпляра

Посмотрите, как каждый экземпляр теперь содержит уникальное значение name:

tom = Student('Tom')
susan = Student('Susan')

print(tom.name)
>> "Tom"

print(susan.name)
>> "Susan"

Резюме

Это был только базовый обзор переменных класса и экземпляра. Мы углубимся в следующие шаги, но наиболее важный вывод заключается в том, что переменные класса обычно используются для значений, которые являются общими для всех экземпляров класса, в то время как переменные экземпляра используются для значений, уникальных для каждого экземпляра.

Чего ожидать от переменных класса

Переменные класса являются общими для всех экземпляров класса. Напоминаем, что они определены так:

class Student:
   teacher = 'Mrs. Jones'

Иными словами, переменные класса ссылаются на одно и то же место в памяти. Смотрите следующее:

tom = Student()
susan = Student()

id(tom.teacher) == id(susan.teacher)
>> True

Функция id возвращает адрес объекта в памяти для реализации CPython.

Таким образом, с помощью функции id мы можем подтвердить, что атрибут teacher ссылается на то же место в памяти.

Изменение переменной класса

Что произойдет, если мы изменим переменную класса даже после создания экземпляров?

tom = Student()

tom.teacher
>> Mrs. Jones

Student.teacher = 'Mr. Smith'

tom.teacher
>> Mr. Smith

Как и следовало ожидать, поскольку переменная teacher ссылается на общее местоположение в памяти, она также обновляется в экземпляре.

Изменение переменной экземпляра

Это, вероятно, наиболее очевидное и ожидаемое поведение, поэтому не стесняйтесь пропустить этот шаг. Но я все же покажу несколько примеров для полноты.

Рассмотрим наш класс Student с переменными класса и экземпляра:

class Student:
   teacher = 'Mrs. Jones'

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

Мы видим, что каждый экземпляр класса имеет уникальный адрес памяти для имени:

tom = Student('Tom')
susan = Student('Susan')

id(tom.name) == id(susan.name)
>> False

Как и следовало ожидать, обновление атрибута name в одном экземпляре не влияет на другой:

tom.name
>> Tom

susan.name
>> Susan

tom.name = 'Thomas'
tom.name
>> Thomas

susan.name
>> Susan

Переменные экземпляра переопределяют переменные класса (и методы)

Важно отметить, что переменные экземпляра (или атрибуты данных) переопределяют переменные класса.

Помните следующее?

tom = Student()
susan = Student()

id(tom.teacher) == id(susan.teacher)
>> True

Что произойдет, если мы изменим атрибут teacher прямо в одном из случаев:

tom.teacher = 'Mr. Clark'

Это важно отметить: переменные экземпляров не нужно объявлять, они создаются всякий раз, когда им присваиваются, а переменные экземпляра переопределяют переменные класса. Это означает, что в экземпляре Tom teacher больше не ссылается на переменную класса, а на вновь созданную переменную экземпляра.

И, естественно, экземпляр Сьюзен не затронут:

tom.teacher
>> Mr. Clark

susan.teacher
>> Mrs. Jones

Надеюсь, вы видите, как такое поведение может привести к путанице. По этой причине важно сохранять организованные имена переменных. Если переменная объявлена как переменная класса, она (обычно) не должна быть переопределена. Переменные экземпляра могут быть определены в очевидных местах, например, метод __init__. Часто хорошо придумать соглашение об именовании переменных. Например, методы класса должны быть глаголами, существительными переменных класса и существительными переменных экземпляра с префиксом «_».

Использование изменяемых объектов в качестве переменных класса

В связи с предыдущим шагом, будьте осторожны при использовании изменяемых объектов в качестве переменных класса. Вы можете быть удивлены поведением.

Представьте, что мы хотим получить список результатов тестов студента. Мы могли бы составить такой класс:

class Student:
   teacher = 'Mrs. Jones'
   test_scores = []

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

   def add_score(self, score):
       self.test_scores.append(score)

У нас есть переменная класса для хранения баллов, и у нас есть метод класса для добавления баллов. Теперь давайте добавим несколько баллов.

tom = Student('Tom')
susan = Student('Susan')

tom.add_score(90)
susan.add_score(100)

Можете ли вы угадать, какую ошибку мы только что сделали?

tom.test_scores
>> [90, 100]

Да, test_scores — это переменная класса, а не переменная экземпляра. Каждый экземпляр просто добавляет значения в переменную класса. Мы действительно хотим, чтобы каждый экземпляр содержал свой собственный список test_scores.

Так что лучший класс может выглядеть так:

class Student:
   teacher = 'Mrs. Jones'

   def __init__(self, name):
       self.name = name
       self.test_scores = []

   def add_score(self, score):
       self.test_scores.append(score)

И теперь наша проблема решена!

Заключение

Надеюсь, вы узнали разницу между переменными класса и экземпляра и что ожидать от каждой из них. Если я что-то упустил в этом руководстве или у вас есть отличные примеры путаницы переменных класса и экземпляра, пожалуйста, прокомментируйте ниже. Я был бы рад добавить их в это руководство!

26 апреля, 2017 11:54 дп
14 147 views
| Комментариев нет

Python

В объектно-ориентированном программировании переменные можно использовать на уровне класса или объекта. Переменная – это символ, который заменяет какое-либо значение в программе.

Если какая-либо переменная будет иметь одно и то же значение во всех объектах программы, её можно определить на уровне класса. Если значение переменной будет изменяться в зависимости от объекта, такую переменную нужно определить на уровне экземпляра (объекта).

DRY (don’t repeat yourself, рус. не повторяйся) – это принцип программирования, который подразумевает снижение повторений кода в рамках программы.

Данное руководство научит пользоваться переменными класса и объектными переменными (или переменными экземпляра) в объектно-ориентированном программировании в Python.

Переменные класса

Переменные класса определяются на уровне класса и применяются ко всем объектам, созданным на его основе. Такая переменная, как правило, имеет одно и то же значение внутри всех объектов на основе этого класса (если только она не используется для инициализации переменной).

Переменная класса, определяемая вне метода, как правило, пишется под заголовком класса и перед методом конструктора и другими методами.

Читайте также: Создание классов и определение объектов в Python 3

Переменная класса выглядит так:

class Shark:
animal_type = "fish"

Создайте тестовую программу shark.py. В этом файле можно создать экземпляр класса Shark (например, new_shark) и вывести переменную с помощью точечной нотации:

class Shark:
animal_type = "fish"
new_shark = Shark()
print(new_shark.animal_type)

Запустите программу:

python shark.py
fish

Программа отобразила значение переменной.

Добавьте в класс больше переменных и отобразите их:

class Shark:
animal_type = "fish"
location = "ocean"
followers = 5
new_shark = Shark()
print(new_shark.animal_type)
print(new_shark.location)
print(new_shark.followers)

Как и другие виды переменных Python, переменные класса могут содержать любой тип данных. В данной программе переменные будут содержать строки и целые числа.

Читайте также: Типы данных в Python 3

Снова запустите программу:

python shark.py

На экране появится:

fish
ocean
5

Объект new_shark имеет доступ ко всем переменным класса и может отобразить их на экране.

Объектные переменные

Объектные переменные имеют индивидуальное значение внутри того или иного объекта.

В отличие от переменных класса, объектные переменные определяются внутри метода.

К примеру, в классе Shark переменные name и age являются объектными.

class Shark:
def __init__(self, name, age):
self.name = name
self.age = age

Объектные переменные определяются при создании класса Shark, а затем передаются объекту в качестве параметров метода конструктора или другого метода.

class Shark:
def __init__(self, name, age):
self.name = name
self.age = age
new_shark = Shark("Wally", 5)

Как и переменные класса, объектные переменные можно отобразить:

class Shark:
def __init__(self, name, age):
self.name = name
self.age = age
new_shark = Shark("Wally", 5)
print(new_shark.name)
print(new_shark.age)

Запустите программу:

python shark.py
Wally
5

Полученный результат состоит из значений переменных, которые были инициализированы для объекта new_shark.

Создайте ещё один объект класса Shark (например, stevie):

class Shark:
def __init__(self, name, age):
self.name = name
self.age = age
new_shark = Shark("Wally", 5)
print(new_shark.name)
print(new_shark.age)
stevie = Shark("Stevie", 8)
print(stevie.name)
print(stevie.age)

Объект stevie, как и объект new_shark, передает индивидуальные параметры экземпляра класса Shark.

Объектные переменные имеют разные значения внутри каждого объекта.

Работа с переменными класса и объекта

Переменные класса и объектные переменные часто используются вместе. Давайте рассмотрим пример кода, в котором использованы оба вида переменных.

class Shark:

# Переменные класса
animal_type = "fish"
location = "ocean"
# Метод конструктора с объектными переменными name и age
def __init__(self, name, age):
self.name = name
self.age = age
# Метод с объектной переменной followers
def set_followers(self, followers):
print("This user has " + str(followers) + " followers")
def main():
# Первый объект определяет объектные переменные метода конструктора
wally = Shark("Wally", 5)
# Отображение объектной переменной name
print(wally.name)
# Отображение переменной класса location
print(wally.location)
# Второй объект
stevie = Shark("Stevie", 8)
# Отображение объектной переменной name
print(stevie.name)
# Использование метода set_followers и передача объектной переменной followers
stevie.set_followers(77)
# Отображение переменной класса animal_type
print(stevie.animal_type)
if __name__ == "__main__":
main()

Запустите программу:

python shark.py

Вы получите такой результат:

Wally
ocean
Stevie
This user has 77 followers
fish

Заключение

В объектно-ориентированном программировании переменные на уровне класса называются переменными класса, а переменные на уровне объекта называются объектными переменными.

Переменные класса можно использовать для инициализации объектов с определенным значением, присвоенным переменным. Объектные переменные имеют индивидуальное значение внутри каждого объекта.

Это позволяет разрабатывать программы по принципу DRY и уменьшить повторение кода.

Tags: DRY, Python, Python 3

В этой статье мы расскажем про переменные класса и экземпляра в Python. Мы разберем, чем они отличаются и как с ними работать.

Объектно-ориентированное программирование позволяет использовать переменные на уровне класса или на уровне экземпляра класса. Переменные – это, по сути, символы, заменяющие значение, которое вы используете в программе.

На уровне класса переменные называются переменными класса, на уровне экземпляра – переменными экземпляра.

Когда мы ожидаем, что переменные будут общими для всех экземпляров класса или когда мы хотим инициализировать переменную, мы можем определить эту переменную на уровне класса. Если же мы ожидаем, что переменные будут значительно отличаться в разных экземплярах, мы можем определить их на уровне экземпляра класса.

Одним из принципов разработки программного обеспечения является принцип DRY (Don’t repeat yourself), который означает «Не повторяйся». Этот принцип направлен на ограничение повторов (дублирования) в коде. Объектно-ориентированное программирование придерживается принципа DRY, поскольку он снижает избыточность.

Для начала

У вас должен быть установлен Python 3 и настроена среда программирования на вашем компьютере или сервере, подходящая для вашей операционной системы (Ubuntu, CentOS, Debian и т.д.)

Переменные класса определяются в конструкторе класса. Поскольку они принадлежат самому классу, переменные класса разделяются всеми экземплярами класса. Поэтому они, как правило, будут иметь одинаковое значение для каждого экземпляра. Исключение — если вы используете переменную класса для инициализации переменной.

Переменные класса определяются вне всех методов. Обычно они размещаются прямо под заголовком класса, перед методом конструктора и другими методами.

Примечание. Чтобы следовать примерам кода в этом руководстве, откройте интерактивную оболочку Python в своей локальной системе, выполнив команду python3. Затем вы можете копировать, вставлять или редактировать примеры, добавляя код после символов >>>.

Сама по себе переменная класса выглядит следующим образом:

class Shark:
    animal_type = "fish"

Здесь переменной animal_type присвоено значение «fish».

Мы можем создать экземпляр класса Shark (назовем его new_shark) и вывести переменную, используя точечную нотацию:

class Shark:
    animal_type = "fish"

new_shark = Shark()
print(new_shark.animal_type)

Запустим нашу программу:

$ python shark.py

И получим следующий результат:

fish

Программа возвращает значение нашей переменной.

Теперь давайте добавим ещё несколько переменных класса и выведем их:

class Shark:
    animal_type = "fish"
    location = "ocean"
    followers = 5

new_shark = Shark()
print(new_shark.animal_type)
print(new_shark.location)
print(new_shark.followers)

Как и любая другая переменная, переменные класса могут содержать данные любого типа (из доступных в Python). В этой программе есть строки (animal_type и location) и целое число (followers). Давайте снова запустим программу с помощью команды python shark.py и просмотрим на результат:

# Output
fish
ocean
5

Экземпляр new_shark имеет доступ ко всем переменным класса и может выводить их при запуске программы.

Переменные класса позволяют нам определять переменные при построении класса. Затем эти переменные и связанные с ними значения становятся доступными для каждого экземпляра класса.

Переменные экземпляра класса в Python

Переменные экземпляра принадлежат экземплярам класса. Это означает, что для каждого объекта или экземпляра класса переменные экземпляра различны.

В отличие от переменных класса, переменные экземпляра определяются внутри методов.

Например, в приведенном ниже коде переменные класса Shark name и age являются переменными экземпляра:

class Shark:
    def __init__(self, name, age):
        self.name = name
        self.age = age

При создании объекта класса Shark нам нужно определить эти переменные, которые передаются как параметры в методе конструктора или другом методе.

class Shark:
    def __init__(self, name, age):
        self.name = name
        self.age = age

new_shark = Shark("Sammy", 5)

Так же, как и в случае с переменными класса, мы можем вывести переменные экземпляра в консоль:

class Shark:
    def __init__(self, name, age):
        self.name = name
        self.age = age

new_shark = Shark("Sammy", 5)
print(new_shark.name)
print(new_shark.age)

Когда мы запустим указанную выше программу, используя python shark.py, мы получим следующий вывод:

# Output
Sammy
5

Полученный нами вывод состоит из значений переменных, которые мы инициализировали для экземпляра new_shark.

[python_ad_block]

Давайте создадим еще один объект класса Shark под названием stevie:

class Shark:
    def __init__(self, name, age):
        self.name = name
        self.age = age

new_shark = Shark("Sammy", 5)
print(new_shark.name)
print(new_shark.age)

stevie = Shark("Stevie", 8)
print(stevie.name)
print(stevie.age)

# Output:
# Sammy
# 5
# Stevie
# 8

Объект stevie, как и объект new_shark, передает параметры, специфичные для данного конкретного экземпляра класса Shark, чтобы присвоить значения переменным экземпляра.

То есть переменные экземпляра, принадлежащие объектам класса, позволяют каждому объекту или экземпляру иметь разные значения, присвоенные этим переменным.

Работа с переменными класса и экземпляра одновременно

Переменные класса и переменные экземпляра часто используются одновременно. Поэтому давайте рассмотрим такой пример, используя созданный нами класс Shark. Комментарии в программе описывают каждый этап процесса.

class Shark:

    # Переменные класса
    animal_type = "fish"
    location = "ocean"

    # Метод-конструктор с переменными экземпляра name и age
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # Метод с переменной экземпляра followers
    def set_followers(self, followers):
        print("This user has " + str(followers) + " followers")


def main():
    # Первый объект. Установка переменных экземпляра метода-конструктора
    sammy = Shark("Sammy", 5)

    # Вывод переменной экземпляра name
    print(sammy.name)

    # Вывод переменной класса location
    print(sammy.location)

    # Второй объект
    stevie = Shark("Stevie", 8)

    # Вывод переменной экземпляра name
    print(stevie.name)

    # Использование метода set_followers и передача переменной экземпляра followers
    stevie.set_followers(77)

    # Вывод переменной класса animal_type
    print(stevie.animal_type)

if __name__ == "__main__":
    main()

Когда мы запустим программу, используя python shark.py, мы получим следующий результат:

# Output
Sammy
ocean
Stevie
This user has 77 followers
fish

Здесь мы использовали переменные класса и экземпляра в двух объектах класса Shark: sammy и stevie.

Заключение

В объектно-ориентированном программировании переменные на уровне класса называются переменными класса, а на уровне объекта – переменными экземпляра класса.

Это различие позволяет нам использовать переменные класса для инициализации объектов с определенным значением, присвоенным переменным, а переменные экземпляра — чтобы каждый объект мог иметь свои переменные.

Использование переменных, относящихся к классу или экземпляру, помогает придерживаться принципа DRY. То есть способствует уменьшению повторов в коде.


От редакции Pythonist. Рекомендуем также почитать статью «Чем отличаются методы класса, статические и «простые» методы».


Перевод статьи «Understanding Class and Instance Variables in Python 3».

Переменные экземпляра класса предназначены для данных, уникальных для каждого экземпляра класса, а переменные класса (атрибуты данных класса) — для атрибутов и методов, общих для всех экземпляров класса.

class Dog:

    # атрибут данных (переменная класса), 
    # общая для всех экземпляров класса
    kind = 'canine'

    def __init__(self, name):
        # переменная экземпляра класса
        # уникальна для каждого экземпляра
        self.name = name

>>> d = Dog('Fido')
>>> e = Dog('Buddy')

# переменная `kind` будет общая для 
# всех экземпляров объекта `Dog`
>>> d.kind
# 'canine'
>>> e.kind    
# 'canine'

# переменная `name` будет уникальна 
# для каждого из экземпляров
>>> d.name
# 'Fido'
>>> e.name    
# 'Buddy'

Как говорилось в материале «Классы в языке Python», общие данные могут иметь неожиданный эффект при использовании изменяемых объектов, таких как списки и словари. Например, список tricks (трюки, которые может делать отдельная собака) в примере ниже не следует использовать как атрибут данных/переменную класса, потому что для всех экземпляров класса Dog будет использоваться только один атрибут данных tricks:

class Dog:

    # ошибочное использование атрибута tricks -
    #  переменной класса
    tricks = []

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

    def add_trick(self, trick):
        self.tricks.append(trick)

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')

# неожиданно разделяется всеми собаками
>>> d.tricks
# ['roll over', 'play dead']

Правильный дизайн класса должен использовать tricks не как атрибут данных класса, а как переменную экземпляра класса:

class Dog:
    def __init__(self, name):
        self.name = name
        # создает новый пустой список 
        # трюков для каждой собаки
        self.tricks = []

    def add_trick(self, trick):
        self.tricks.append(trick)

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks
# ['roll over']
>>> e.tricks
# ['play dead']

Если одно и то же имя атрибута встречается как в экземпляре класса, так и в самом классе, то поиск атрибута определяет приоритет экземпляра класса:

>>> class Warehouse:
        purpose = 'storage'
        region = 'west'

>>> w1 = Warehouse()
>>> print(w1.purpose, w1.region)
# storage west
>>> w2 = Warehouse()
>>> w2.region = 'east'
>>> print(w2.purpose, w2.region)
# storage east

На атрибуты данных класса могут ссылаться как методы, так и обычные пользователи — «клиенты» объекта. Другими словами, классы не могут использоваться для реализации чисто абстрактных типов данных. Фактически, ничто в Python не позволяет принудительно скрывать данные — все основано на соглашении.

Клиенты должны использовать переменные класса с осторожностью — клиенты могут испортить инварианты, поддерживаемые методами, изменив их атрибуты данных. Обратите внимание, что клиенты могут добавлять свои собственные атрибуты данных к объекту экземпляра, не влияя на достоверность методов, до тех пор, пока избегаются конфликты имен — опять же, соглашение об именовании может сэкономить здесь много головной боли.

В Python нет сокращений для ссылки на атрибуты данных или другие методы изнутри методов. Это повышает удобочитаемость методов: нет возможности путать локальные переменные и переменные экземпляра при просмотре метода.

Вместо использования привычной точечной нотации для доступа к атрибутам можно использовать встроенные функции:

  • getattr(obj, name [, default]) — для доступа к атрибуту name объекта класса obj.
  • hasattr(obj, name) — проверить, есть ли в классе obj атрибут name.
  • setattr(obj, name, value) — задать атрибут name со значением value. Если атрибут не существует, он будет создан.
  • delattr(obj, name) — удалить атрибут name из объекта класса obj.

Встроенные атрибуты класса.

Классы Python хранят встроенные атрибуты, к которым можно получить доступ как к любому другому атрибуту данных.

  • __dict__ — словарь, содержащий пространство имен класса.
  • __doc__ — строка документации класса. None если, документация отсутствует.
  • __name__ — имя класса.
  • __module__ — имя модуля, в котором определяется класс.
  • __bases__ — кортеж, содержащий базовые классы, в порядке их появления. Кортеж будет пустым, если наследование не было.
  • __mro__ — Порядок разрешения методов в множественном наследовании.

Где хранятся атрибуты класса и экземпляра класса?

Python не был бы Python без четко определенного и настраиваемого поведения атрибутов. Атрибуты в Python хранятся в магическом методе с именем __dict__. Получить доступ к нему можно следующим образом:

class MyClass:
    class_attr = "Class"

    def __init__(self):
        self.instance_attr = "Instance"

>>> my_object = MyClass()
# атрибут экземпляра класса
>>> my_object.__dict__
# {'instance_attribute': 'Instance'}

# атрибут экземпляра класса
>>> MyClass.__dict__['class_attr']
# 'Class'

>>> my_object.class_attr
'Class'
>>> my_object.instance_attr
'Instance'

Я пытаюсь изменить статическую переменную в Python

>>> class A():
...     i = 0
...     def add_i(self):
...             self.i = self.i + 1
...
>>> A.i
0
>>> a = A()
>>> a.add_i()
>>> A.i
0
>>> a.i
1

Когда я вызываю a.add_i(), почему он не увеличивает «статическую» переменную i?

6 ответов

Лучший ответ

Когда вы назначаете self.i, вы создаете новую переменную instance с именем i:

>>> print id(A.i), id(a.i)
9437588 9437576

Следующее изменится A.i вместо привязки a.i:

A.i = A.i + 1

Или короче:

A.i += 1

Существуют копии переменной i. Когда вы вызываете a.add_i(), a.i увеличивается, а A.i становится тем же.

#a.i = 1, A.i = 1
a.add_i()
#a.i = 2, A.i = 2

Подумай о том, что случилось бы, если бы ты

a = A()
b = A()
a.add_i()

print A.i()


1

Martol1ni
5 Янв 2014 в 13:34

Чтобы изменить переменную уровня класса, вы можете определить метод уровня класса

In [15]: class A():
   ....:    i = 0
   ....:    @classmethod
   ....:    def incr(cls):
   ....:         cls.i += 1
   ....:         

In [16]: 

In [16]: A.incr()

In [17]: A.i
Out[17]: 1

In [18]: A().incr()

In [19]: A.i
Out[19]: 2

< Сильный > EDIT :

Или ссылаться на класс внутри метода (а не экземпляра)

def incr(self):
    A.i += 1

Если атрибут уровня класса изменчив, и вы хотите изменить его (не присваивание), например, для списка, вы можете сделать это любым способом

In [29]: class Class4Test(object):
    mylist = []
    @classmethod
    def add2list_class(cls, val):
        cls.mylist.append(val)
    def add2list_by_class(self, val):
        Class4Test.mylist.append(val)
    def add2list_by_inst(self,val):
        self.mylist.append(val)
   ....:         

In [30]: obj = Class4Test()

In [31]: obj.add2list_by_inst('val1')

In [32]: obj.add2list_by_class('val2')

In [33]: Class4Test.add2list_class('val3')

In [34]: obj.add2list_class('val4')

In [35]: Class4Test.mylist
Out[35]: ['val1', 'val2', 'val3', 'val4']


0

volcano
5 Янв 2014 в 14:43

Следующий код показывает, что именно происходит:

class A():
    i = 0
    def add_i(self):
        print 'n-----In add_i function-----'
        print 'BEFORE: a.__dict__ :',a.__dict__
        print 'BEFORE: id(self)   : %dn' % id(self.i)
        self.i = self.i + 1
        print 'self.i = self.i + 1  donen'
        print 'AFTER: a.__dict__ :',a.__dict__
        print 'AFTER: id(self)   : %d' % id(self.i)
        print '-----end of add_i function-----n'

a = A()

print 'nA.i     ==',A.i
print 'id(A.i) ==',id(A.i)
print 'A.__dict__.keys() :',A.__dict__.keys()

print 'na.i     ==',a.i
print 'id(a.i) ==',id(a.i)
print 'a.__dict__.keys() :',a.__dict__.keys()

a.add_i()

print 'nA.i     ==',A.i
print 'id(A.i) ==',id(A.i)
print 'A.__dict__.keys() :',A.__dict__.keys()

print 'na.i     ==',a.i
print 'id(a.i) ==',id(a.i)
print 'a.__dict__.keys() :',a.__dict__.keys()

Результат

A.i     == 0
id(A.i) == 10021948
A.__dict__.keys() : ['i', 'add_i', '__module__', '__doc__']

a.i     == 0
id(a.i) == 10021948
a.__dict__.keys() : []

-----In add_i function-----
BEFORE: a.__dict__ : {}
BEFORE: id(self)   : 10021948

self.i = self.i + 1  done

AFTER: a.__dict__ : {'i': 1}
AFTER: id(self)   : 10021936
-----end of add_i function-----


A.i     == 0
id(A.i) == 10021948
A.__dict__.keys() : ['i', 'add_i', '__module__', '__doc__']

a.i     == 1
id(a.i) == 10021936
a.__dict__.keys() : ['i']

__dict__ объекта предоставляет пространство имен объекта, то есть отображение имен на объекты, содержащее его атрибуты.

Сразу после того, как класс A и его экземпляр a созданы, только A имеет атрибут i,
a нет.
Фактически в этот момент пространство имен a является недействительным, и когда интерпретатор встречает a.i, он делает это:

Экземпляр класса имеет пространство имен, реализованное в виде словаря, который первое место, в котором ссылки на атрибуты ищутся. Когда атрибут там не найден, а класс экземпляра имеет атрибут с этим именем, поиск продолжается с классом атрибутов . см. 3 Модель данных 3.2 Стандартная иерархия типов
в справочнике по языку Python

То есть, поскольку i не является атрибутом экземпляра a, интерпретатор отправляется на поиск в пространстве имен A: там он находит атрибут i и возвращает этот атрибут в результате вызова a.i

.

Теперь, когда a.add_i() выполняется, инструкция self.i = self.i + 1 обрабатывается следующим образом:

  • во-первых, выполняется поиск self.i: поскольку i не является атрибутом self (то есть a), возвращаемый объект фактически является A.i.

  • во-вторых, self.i + 1 затем создает новый объект, значение которого является увеличенным значением A.i. Но теперь этот объект ОТЛИЧЕН от объекта имени A.i: у него другая идентичность, то есть другая локализация в памяти.

  • в-третьих, есть назначение: self.i = ..... Это означает, что имя i создается в пространстве имен self (то есть a) и привязывается к только что созданному объекту со значением приращения.

Таким образом, между началом функции add_i() и ее концом значение self.i изменилось.
Следовательно, значение a.i после инструкции a.add_i() больше не такое, как раньше.

.

Глубокое понимание процессов Python требует рассмотрения игр, в которые идентификаторы (имена) и объекты играют в пространствах имен, иного пути нет.


2

eyquem
5 Янв 2014 в 16:09

Потому что вы вызываете метод для экземпляра класса, который имеет собственную копию i. Этот код будет делать то, что вы хотите.

class A(object):
    i = 0
    def add_i(self):
        self.__class__.i += 1      

>> a = A()
>> a.add_i()
>> A.i
1


1

aychedee
5 Янв 2014 в 17:02

Потому что a.add_i() не является статическим методом и может увеличивать только не статические переменные


0

kernel72
5 Янв 2014 в 13:33

BBKay

0 / 0 / 0

Регистрация: 13.10.2022

Сообщений: 11

1

Изменить значение переменной родительского класса

14.10.2022, 10:13. Показов 685. Ответов 14

Метки python, классы (Все метки)


Всем привет.
Возможно не совсем туда написал, но по теме, вроде подходит. На форуме подобного не нашел, возможно не те ключевые слова подобрал.
Суть в следующем. Есть класс House.

Python
1
2
3
4
class House:
    def __init__(self, deposit):
        self.residents = list()
        self.deposit = deposit

Условно такой.
residents — список проживающих, deposit — общий бюджет. Список проживающих — это экземпляры класса Human.

Python
1
2
3
class Human:
    def __init__(self, name):
        self.name = name

Опять же условно такой. В классе Human есть метод пополняющий бюджет:

Python
1
2
    def do_work(self):
        House.deposit += 150

здесь я обращаюсь напрямую к классу House и его переменной deposit.
Когда есть один экземпляр класса House, все работает. Но подозреваю, что когда будет несколько экземпляров класса, то не будет работать. Формально House — родительский класс, Human — дочерний.

Вопрос: как сделать так, чтобы класс Human в методе do_work менял значение переменной deposit в том классе House в котором находится (типа в родительском классе)?

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Автоматизируй это!

Эксперт Python

6482 / 4175 / 1140

Регистрация: 30.03.2015

Сообщений: 12,331

Записей в блоге: 29

14.10.2022, 10:41

2

Цитата
Сообщение от BBKay
Посмотреть сообщение

Human — дочерний.

твой папа тоже дом? нет? тогда не городи такого

вместо ду_ворк нужен эдд_хоусе_депозит с передачей суммы. В нем вызываем self.house.deposit+value, а вот как в self.house попадет в объект хуман -решай сам — или в конструкторе или сеттером.



2



anton78spb

914 / 542 / 253

Регистрация: 05.09.2021

Сообщений: 968

14.10.2022, 11:05

3

Цитата
Сообщение от BBKay
Посмотреть сообщение

Вопрос: как сделать так, чтобы класс Human в методе do_work менял значение переменной deposit в том классе House в котором находится (типа в родительском классе)?

Надо сделать так, чтобы класс Human знал в списке какого класса House он находится. Соответственно ему это надо где-то сообщить. Можно это сделать при инициализации.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class House:
    def __init__(self, deposit):
        self.residents = list()
        self.deposit = deposit
        
class Human:
    def __init__(self, name, house):
        self.name = name
        self.house = house
        
    def do_work(self):
        self.house.deposit += 150
        
house_1 = House(0)
house_2 = House(0)
human = Human('Vasiliy', house_1)
house_1.residents.append(human)
human.do_work()
print(f"{house_1.deposit = }")
print(f"{house_2.deposit = }")

Код

house_1.deposit = 150
house_2.deposit = 0


** Process exited - Return Code: 0 **
Press Enter to exit terminal

Добавлено через 57 секунд
Пока оформлял, Welemir1, уже все объяснил.



2



0 / 0 / 0

Регистрация: 13.10.2022

Сообщений: 11

14.10.2022, 22:39

 [ТС]

4

Цитата
Сообщение от Welemir1
Посмотреть сообщение

вместо ду_ворк нужен эдд_хоусе_депозит с передачей суммы

У меня по условию задачи do_work. Ну да ладно, значит нельзя мою задумку реализовать. Спасибо.

Цитата
Сообщение от anton78spb
Посмотреть сообщение

Надо сделать так

Да, к этому я тоже пришел. Но я не хотел добавлять Дом в Проживающего, хотел реализовать логику добавления Проживающего в Дом.
Ладно, спасибо.



0



Catstail

Модератор

Эксперт функциональных языков программированияЭксперт Python

33880 / 18907 / 3981

Регистрация: 12.02.2012

Сообщений: 31,707

Записей в блоге: 13

15.10.2022, 06:21

5

Когда человек вместо «объект» пишет «класс», первое, что нужно сделать — это усвоить разницу между классом и объектом. И наследование тут на при чем. «Кто ясно мыслит — ясно излагает».

Есть дом:

Python
1
2
3
4
5
class House:
    def __init__(self,...,список-жильцов=None):
        ...
    def addHuman(self,human):
        self.ListOfHuman.append(human) # нужно проверить, нет ли дублирования, но это детали

Есть жилец:

Python
1
2
class Human:
    def __init__(self,....):

Создаем новый дом:

Python
1
h1=House(...) # список жильцов пуст

Добавляем жильцов:

Python
1
2
3
4
j1=Human("Вася","Пупкин")
h1.addHuman(j1)
j2=Human("Альберт","Эйнштейн")
h1.addHuman(j2)

Что не так?



0



0 / 0 / 0

Регистрация: 13.10.2022

Сообщений: 11

16.10.2022, 13:37

 [ТС]

6

Цитата
Сообщение от Catstail
Посмотреть сообщение

Что не так?

Спасибо, но вопрос не в этом состоял. Но с формулировкой, согласен, немного ошибся.

Могу перефразировать.
Как сделать так, чтобы объект Human, который находится в контейнере House изменял значение переменной deposit, которая так же находится в контейнере House?



0



Модератор

Эксперт функциональных языков программированияЭксперт Python

33880 / 18907 / 3981

Регистрация: 12.02.2012

Сообщений: 31,707

Записей в блоге: 13

16.10.2022, 13:41

7

Цитата
Сообщение от BBKay
Посмотреть сообщение

Как сделать так, чтобы объект Human, который находится в контейнере House изменял значение переменной deposit, которая так же находится в контейнере House?

— сделать сеттер для этой переменной и вызвать его в нужном месте.



0



0 / 0 / 0

Регистрация: 13.10.2022

Сообщений: 11

16.10.2022, 13:51

 [ТС]

8

Цитата
Сообщение от Catstail
Посмотреть сообщение

сделать сеттер для этой переменной и вызвать его в нужном месте

Это понятно. А как узнать имя контейнера, чтобы вызвать сеттер этой переменной, если контейнеров может быть несколько? Изначально же неизвестно имя контейнера.

Людей может быть несколько, домов может быть несколько, у жителей каждого дома свой бюджет. Как узнать из какого дома житель?



0



Модератор

Эксперт функциональных языков программированияЭксперт Python

33880 / 18907 / 3981

Регистрация: 12.02.2012

Сообщений: 31,707

Записей в блоге: 13

16.10.2022, 13:54

9

Цитата
Сообщение от BBKay
Посмотреть сообщение

если контейнеров может быть несколько?

— это как? Что-то ты накрутил… Приведи лаконичный пример.



0



0 / 0 / 0

Регистрация: 13.10.2022

Сообщений: 11

16.10.2022, 14:25

 [ТС]

10

Цитата
Сообщение от Catstail
Посмотреть сообщение

Приведи лаконичный пример

Я живу в доме номер 5, у меня свой бюджет. В доме номер 8 живет другой человек, или несколько людей не важно. Я могу пополнить только свой бюджет, который находится в доме номер 5. Зачем мне пополнять чужой?

Изначально я не знаю в каком доме я поселюсь.

Чтобы было еще проще представить. Допустим, я не умею обращаться с деньгами и все заработанные деньги складываю в тумбочку. Зачем мне приходить в чужой дом и складывать свои деньги в их тумбочку, типа, пусть здесь полежат, я потом за ними приду.



0



Alexarh

2344 / 1401 / 616

Регистрация: 01.11.2021

Сообщений: 2,203

16.10.2022, 14:38

11

BBKay, только в твоем коде человек не знает в каком доме он живет. Его куда-то запихнули, а он даже не знает об этом. Вот дом будет знать своих жильцов.

Добавлено через 5 минут
Выше предложили решение, надо дать понять человеку в каком доме он живет, добавить ему этот атрибут в класс.

Или можно сделать так, в методе добавить параметр дом, на который должен работать человек.

Python
1
2
def do_work(self, house):
    house.deposit += 150

Соответственно придется каждый раз передавать человеку в этот метод дом, в который он должен «заплатить».



0



Catstail

Модератор

Эксперт функциональных языков программированияЭксперт Python

33880 / 18907 / 3981

Регистрация: 12.02.2012

Сообщений: 31,707

Записей в блоге: 13

16.10.2022, 14:48

12

Лучший ответ Сообщение было отмечено BBKay как решение

Решение

BBKay, смотри:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class House:
    def __init__(self):
        self.hlist=[]
        self.blist=[]
        
    def addHuman(self,human):  # добавить человека в дом
        self.hlist.append(human) 
        self.blist.append(0)
        human.house=self            # у человека есть поле "house"
        
    def getBal(self):                    # дать полный баланс дома
        return sum(self.blist)
        
 
class Human:
    def __init__(self,fio):
        self.fio=fio
        self.house=None
        
    def rep_bal(self,summa):     # пополнить баланс
        if self.house is None:
            raise "Человек не прикреплен ни к какому дому"
        else:
            house=self.house # ссылка на дом, в котором живет человек
            n=len(house.hlist)
            for i in range(n):
                if house.hlist[i] is self:
                    house.blist[i]+=summa
                    break
                    
house_1=House()
house_2=House()
 
man_1=Human("Вася Пупкин")
man_2=Human("Миша Кошкин")
 
house_1.addHuman(man_1)
house_1.addHuman(man_2)
 
man_1.rep_bal(111);
man_2.rep_bal(222);
 
print(house_1.getBal())



0



0 / 0 / 0

Регистрация: 13.10.2022

Сообщений: 11

16.10.2022, 15:08

 [ТС]

13

О. Благодарю.

А это строчка что означает?

Цитата
Сообщение от Catstail
Посмотреть сообщение

human.house=self

не дошел еще до таких конструкций.



0



Модератор

Эксперт функциональных языков программированияЭксперт Python

33880 / 18907 / 3981

Регистрация: 12.02.2012

Сообщений: 31,707

Записей в блоге: 13

16.10.2022, 15:11

14

Цитата
Сообщение от BBKay
Посмотреть сообщение

А это строчка что означает?

— ха! Это самое главное! У человека есть поле «дом, где он живет». Вот я туда и помещаю туда self, т.е. ссылку на дом.



0



0 / 0 / 0

Регистрация: 13.10.2022

Сообщений: 11

16.10.2022, 15:18

 [ТС]

15

Ясно, разберемся, еще раз спасибо.



0



Понравилась статья? Поделить с друзьями:

Читайте также:

  • Как изменить переменную внутри функции python
  • Как изменить переменную вне функции python
  • Как изменить переменную php через js
  • Как изменить пароль электронной почты на телефоне айфон
  • Как изменить переменную path linux

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии