Подскажите как можно изменить переменные в «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
вам надо вызвать 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
DanisDanis
18.3k4 золотых знака19 серебряных знаков52 бронзовых знака
2
Ну, все методы вызываются с помощью ()
. То есть, ваш вызов должен быть:
X = A().update_A()
Это должно сработать.
И добавьте ещё return self
в конце метода, иначе не будет работать в одну строку и придётся делать так:
X = A()
X.update_A()
ответ дан 27 ноя 2020 в 6:42
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, классы (Все метки)
Всем привет.
Условно такой.
Опять же условно такой. В классе Human есть метод пополняющий бюджет:
здесь я обращаюсь напрямую к классу House и его переменной deposit. Вопрос: как сделать так, чтобы класс Human в методе do_work менял значение переменной deposit в том классе House в котором находится (типа в родительском классе)?
__________________
0 |
Автоматизируй это! 6482 / 4175 / 1140 Регистрация: 30.03.2015 Сообщений: 12,331 Записей в блоге: 29 |
|
14.10.2022, 10:41 |
2 |
Human — дочерний. твой папа тоже дом? нет? тогда не городи такого вместо ду_ворк нужен эдд_хоусе_депозит с передачей суммы. В нем вызываем self.house.deposit+value, а вот как в self.house попадет в объект хуман -решай сам — или в конструкторе или сеттером.
2 |
anton78spb 914 / 542 / 253 Регистрация: 05.09.2021 Сообщений: 968 |
||||
14.10.2022, 11:05 |
3 |
|||
Вопрос: как сделать так, чтобы класс Human в методе do_work менял значение переменной deposit в том классе House в котором находится (типа в родительском классе)? Надо сделать так, чтобы класс Human знал в списке какого класса House он находится. Соответственно ему это надо где-то сообщить. Можно это сделать при инициализации.
Код house_1.deposit = 150 house_2.deposit = 0 ** Process exited - Return Code: 0 ** Press Enter to exit terminal Добавлено через 57 секунд
2 |
0 / 0 / 0 Регистрация: 13.10.2022 Сообщений: 11 |
|
14.10.2022, 22:39 [ТС] |
4 |
вместо ду_ворк нужен эдд_хоусе_депозит с передачей суммы У меня по условию задачи do_work. Ну да ладно, значит нельзя мою задумку реализовать. Спасибо.
Надо сделать так Да, к этому я тоже пришел. Но я не хотел добавлять Дом в Проживающего, хотел реализовать логику добавления Проживающего в Дом.
0 |
Catstail Модератор 33880 / 18907 / 3981 Регистрация: 12.02.2012 Сообщений: 31,707 Записей в блоге: 13 |
||||||||||||||||
15.10.2022, 06:21 |
5 |
|||||||||||||||
Когда человек вместо «объект» пишет «класс», первое, что нужно сделать — это усвоить разницу между классом и объектом. И наследование тут на при чем. «Кто ясно мыслит — ясно излагает». Есть дом:
Есть жилец:
Создаем новый дом:
Добавляем жильцов:
Что не так?
0 |
0 / 0 / 0 Регистрация: 13.10.2022 Сообщений: 11 |
|
16.10.2022, 13:37 [ТС] |
6 |
Что не так? Спасибо, но вопрос не в этом состоял. Но с формулировкой, согласен, немного ошибся. Могу перефразировать.
0 |
Модератор 33880 / 18907 / 3981 Регистрация: 12.02.2012 Сообщений: 31,707 Записей в блоге: 13 |
|
16.10.2022, 13:41 |
7 |
Как сделать так, чтобы объект Human, который находится в контейнере House изменял значение переменной deposit, которая так же находится в контейнере House? — сделать сеттер для этой переменной и вызвать его в нужном месте.
0 |
0 / 0 / 0 Регистрация: 13.10.2022 Сообщений: 11 |
|
16.10.2022, 13:51 [ТС] |
8 |
сделать сеттер для этой переменной и вызвать его в нужном месте Это понятно. А как узнать имя контейнера, чтобы вызвать сеттер этой переменной, если контейнеров может быть несколько? Изначально же неизвестно имя контейнера. Людей может быть несколько, домов может быть несколько, у жителей каждого дома свой бюджет. Как узнать из какого дома житель?
0 |
Модератор 33880 / 18907 / 3981 Регистрация: 12.02.2012 Сообщений: 31,707 Записей в блоге: 13 |
|
16.10.2022, 13:54 |
9 |
если контейнеров может быть несколько? — это как? Что-то ты накрутил… Приведи лаконичный пример.
0 |
0 / 0 / 0 Регистрация: 13.10.2022 Сообщений: 11 |
|
16.10.2022, 14:25 [ТС] |
10 |
Приведи лаконичный пример Я живу в доме номер 5, у меня свой бюджет. В доме номер 8 живет другой человек, или несколько людей не важно. Я могу пополнить только свой бюджет, который находится в доме номер 5. Зачем мне пополнять чужой? Изначально я не знаю в каком доме я поселюсь. Чтобы было еще проще представить. Допустим, я не умею обращаться с деньгами и все заработанные деньги складываю в тумбочку. Зачем мне приходить в чужой дом и складывать свои деньги в их тумбочку, типа, пусть здесь полежат, я потом за ними приду.
0 |
Alexarh 2344 / 1401 / 616 Регистрация: 01.11.2021 Сообщений: 2,203 |
||||
16.10.2022, 14:38 |
11 |
|||
BBKay, только в твоем коде человек не знает в каком доме он живет. Его куда-то запихнули, а он даже не знает об этом. Вот дом будет знать своих жильцов. Добавлено через 5 минут Или можно сделать так, в методе добавить параметр дом, на который должен работать человек.
Соответственно придется каждый раз передавать человеку в этот метод дом, в который он должен «заплатить».
0 |
Catstail Модератор 33880 / 18907 / 3981 Регистрация: 12.02.2012 Сообщений: 31,707 Записей в блоге: 13 |
||||
16.10.2022, 14:48 |
12 |
|||
РешениеBBKay, смотри:
0 |
0 / 0 / 0 Регистрация: 13.10.2022 Сообщений: 11 |
|
16.10.2022, 15:08 [ТС] |
13 |
О. Благодарю. А это строчка что означает?
human.house=self не дошел еще до таких конструкций.
0 |
Модератор 33880 / 18907 / 3981 Регистрация: 12.02.2012 Сообщений: 31,707 Записей в блоге: 13 |
|
16.10.2022, 15:11 |
14 |
А это строчка что означает? — ха! Это самое главное! У человека есть поле «дом, где он живет». Вот я туда и помещаю туда self, т.е. ссылку на дом.
0 |
0 / 0 / 0 Регистрация: 13.10.2022 Сообщений: 11 |
|
16.10.2022, 15:18 [ТС] |
15 |
Ясно, разберемся, еще раз спасибо.
0 |