Создание классов и объектов

В языке программирования Python классы создаются с помощью инструкции class, за которой следует произвольное имя класса, после которого ставится двоеточие, далее с новой строки и с отступом реализуется тело класса:

class ИмяКласса:
    код_тела_класса

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

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

ИмяКласса()

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

имя_переменной = ИмяКласса()

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

Пример "пустого" класса и двух созданных на его основе объектов:

>>> class A:
...     pass
... 
>>> a = A()
>>> b = A()

Класс как модуль

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

>>> class B:
...     n = 5
...     def adder(v):
...             return v + B.n
... 
>>> B.n
5
>>> B.adder(4)
9

Однако в случае классов используется немного иная терминология. Пусть имена, определенные в классе, называются атрибутами этого класса. В примере имена n и adder – это атрибуты класса B. Атрибуты-переменные часто называют полями или свойствами. Свойством является n. Атрибуты-функции называются методами. Методом в классе B является adder. Количество свойств и методов в классе может быть любым.

Класс как создатель объектов

Приведенный выше класс позволяет создавать объекты, но мы не можем применить к объекту метод adder():

>>> l = B()
>>> l.n
5
>>> l.adder(100)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: adder() takes 1 positional argument but 2 were given

В сообщении об ошибке говорится, что adder() принимает только один аргумент, а было передано два. Откуда взялся второй аргумент, и кто он такой, если в скобках было указано только одно число 100?

На самом деле классы – это далеко не модули. Они идут дальше модулей и обладают своими особенностями. Класс создает объекты, которые в определенном смысле являются его наследниками. Это значит, что если у объекта нет собственного поля n, то интерпретатор ищет его уровнем выше, то есть в классе. Таким образом, если мы присваиваем объекту поле с таким же именем как в классе, то оно перекрывает, т. е. переопределяет, поле класса:

>>> l.n = 10
>>> l.n
10
>>> B.n
5

Здесь l.n и B.n – это разные переменные. Первая находится в пространстве имен объекта l. Вторая – в пространстве класса B. Если бы мы не добавили поле n к объекту l, то интерпретатор бы поднялся выше по дереву наследования и пришел бы в класс, где бы и нашел это поле.

Что касается методов, то они также наследуются объектами класса. В данном случае у объекта l нет своего собственного метода adder, значит, он ищется в классе B. Однако от класса B может быть порождено множество объектов. Методы же чаще всего предназначаются для обработки объектов. Таким образом, когда вызывается метод, в него надо передать конкретный объект, который он будет обрабатывать.

Понятно, что передаваемый экземпляр, это объект, к которому применяется метод. Выражение l.adder(100) выполняется интерпретатором следующим образом:

  1. Ищу атрибут adder() у объекта l. Не нахожу.

  2. Тогда иду искать в класс B, так как он создал объект l.

  3. Здесь нахожу искомый метод. Передаю ему объект, к которому этот метод надо применить, и аргумент, указанный в скобках.

Другими словами, выражение l.adder(100) преобразуется в выражение B.adder(l, 100).

Таким образом, интерпретатор попытался передать в метод adder() класса B два параметра – объект l и число 100. Но мы запрограммировали метод adder() так, что он принимает только один параметр. В Python, да и многих других языках, определения методов не предполагают принятие объекта как само собой подразумеваемое. Принимаемый объект надо указывать явно.

По соглашению в Python для ссылки на объект используется имя self. Вот так должен выглядеть метод adder(), если мы планируем вызывать его через объекты:

>>> class B:
...     n = 5
...     def adder(self, v):
...             return v + self.n
... 

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

Протестируем обновленный метод:

>>> l = B()
>>> m = B()
>>> l.n = 10
>>> l.adder(3)
13
>>> m.adder(4)
9

Здесь от класса B создаются два объекта – l и m. Для объекта l заводится собственное поле n. Объект m, за неимением собственного, наследует n от класса B. Можно в этом убедиться, проверив соответствие:

>>> m.n is B.n
True
>>> l.n is B.n
False

В методе adder() выражение self.n – это обращение к свойству n, переданного объекта, и не важно, на каком уровне наследования оно будет найдено.

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

Изменение полей объекта

В Python объекту можно не только переопределять поля и методы, унаследованные от класса, также можно добавить новые, которых нет в классе:

>>> l.test = "hi"
>>> B.test
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'B' has no attribute 'test'
>>> l.test
'hi'

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

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

>>> class User:
...     def setName(self, n):
...             self.name = n
...     def getName(self):
...             try:
...                     return self.name
...             except:
...                     print("No name")
... 
>>> first = User()
>>> second = User()
>>> first.setName("Bob")
>>> first.getName()
'Bob'
>>> second.getName()
No name

Подобные методы в простонародье называют сеттерами (set – установить) и геттерами (get – получить).

Практическая работа

Напишите программу по следующему описанию. Есть класс "Воин". От него создаются два экземпляра-юнита. Каждому устанавливается здоровье в 100 очков. В случайном порядке они бьют друг друга. Тот, кто бьет, здоровья не теряет. У того, кого бьют, оно уменьшается на 20 очков от одного удара. После каждого удара надо выводить сообщение, какой юнит атаковал, и сколько у противника осталось здоровья. Как только у кого-то заканчивается ресурс здоровья, программа завершается сообщением о том, кто одержал победу.

Курс с примерами решений практических работ и всеми уроками: android-приложение, pdf-версия.

Комментарии

class android1:
    """Robot1"""
    weapon="Базука"
    hand=2
    def chweapon(self,newweapon):
        self.weapon=newweapon
    def chhand(self,newhand):
        self.hand=newhand
 
class android2:
    """Robot2"""
    weapon="пукалка"
    hand=4
    def chweapon(self,newweapon):
        self.weapon=newweapon
 
    def chhand(self,newhand):
        self.hand=newhand
 
robot1=android1()
robot2=android2()
 
print ("Имя-",robot1.__doc__,"Оружие=",robot1.weapon,"Рук-",robot1.hand)
print ("Имя-",robot2.__doc__,"Оружие=",robot2.weapon,"Рук-",robot2.hand)
 
robot2.chweapon("стингер")
print ("Имя-",robot1.__doc__,"Оружие=",robot1.weapon,"Рук-",robot1.hand)
print ("Имя-",robot2.__doc__,"Оружие=",robot2.weapon,"Рук-",robot2.hand)
 
robot2.chweapon(robot1.weapon)
print ("Имя-",robot1.__doc__,"Оружие=",robot1.weapon,"Рук-",robot1.hand)
print ("Имя-",robot2.__doc__,"Оружие=",robot2.weapon,"Рук-",robot2.hand)

Доброго времени суток, помогите, что я делаю не так?
хочу передать здоровье мышки в класс змеи, программа исполняется, но ничего не выводит на экран. Спасибо

class snake(object):
    hungry = True
    catch_mouse = False
    poison = 0
 
    def set_poison(self, newpoison):
        self.poison = newpoison
 
    def catch(self, flag_catch)
        self.catch_mouse = flag_catch
        if self.catch_mouse:
            self.hungry = False
 
    def atack_poison(self, mouse):
        if self.hungry == False:
            while mouse.health != 0:
                self.poison = self.poison - 10 - mouse.move_speed
                mouse.health =  mouse.health - 10
                print("Health:", mouse.health, "    ", "Poison:",
					self.poison)
 
 
 
class mouse(object):
    health = 0
    move_speed = 1
 
    def set_health(self, newhealth):
        health = newhealth
 
 
 
 
python = snake()
micky = mouse()
 
python.set_poison(120)
micky.set_health(100)
 
python.catch(True)
python.atack_poison(micky)

import random
 
class Warriror:
	heals = 100
 
	def hit(self, obj):
		if obj.heals != 0:	
			obj.heals -= 20
			if obj.heals == 0:
				print('Убит', end=' ') 
			return obj.heals	
		else:
			print('Он уже мертв')
 
 
war_1 = Warriror()
war_2 = Warriror()
while war_2.heals > 0 and war_1.heals > 0:
	count = random.random()
	if count > 0.5:
		print('war_2 ', war_1.hit(war_2))
	else:
		print('war_1 ', war_2.hit(war_1))

class warrior:
    hp = 100
    dmg = 20
    def hit(self, enemy):
        enemy.hp -= self.dmg
        print("-20, Left:", enemy.hp)
 
vatnik = warrior()
putin = warrior()
 
from random2 import random
 
while vatnik.hp > 0 and putin.hp > 0:
    a = random()
    if a > 0.5:
        print("Vatnik hits Putin")
        vatnik.hit(putin)
    else:
        print("Putin hits Vatnik")
        putin.hit(vatnik)
 
if vatnik.hp == 0:
    print("Putin wins, Vatnik has died")
else:
    print("Vatnik wins, Putin has died")

Ответ на от Karman

Я знаю что вы написали правильно,но я никак не могу понять.Почему не работает оператор or? Ведь тогда, цикл работает до тех пор,пока одно из его условий не возвратит False,а если использовать оператор and ,то цикл будет работать до тех пор ,пока оба условия не возвратят False.Не могли бы вы объяснить?

Ответ на от Sataev_Adilet

Вы неправильно рассуждаете. При or цикл работает до тех пор, пока хотя бы одно условие возвращает true. При or, чтобы цикл остановился, надо чтобы оба условия вернули false. 

При and достаточно одного false, чтобы цикл остановился. Цикл работает, только если оба условия возвращают true.

class warrior:
 
    def refill_health(self, amount_of_health):
        self.health = amount_of_health
 
    def attack(self, enemy):
        enemy.health -= randint(10, 25)
 
batman = warrior()
batman.refill_health(100)
 
superman = warrior()
superman.refill_health(100)
 
round_count = 0
 
while superman.health > 0 and batman.health > 0:
    superman.attack(batman)
    batman.attack(superman)
    round_count += 1
    print "Round {}: Batman's health is {}, Superman's health is {}".format(round_count, max(0,batman.health), max(0,superman.health))
 
print "Superman is winner" if superman.health > 0 else "Batman is winner"

import random
class Warrior:
    def __init__(self, name, value):
        self.health = value
        self.name = name
 
    def attack(self, enemy):
        enemy.health = enemy.health - 20
 
 
unit1 = Warrior("Ukraine", 100)
unit2 = Warrior("Russia", 100)
 
 
while unit1.health > 0 and unit2.health > 0:
    x = random.randint(0, 1+1)
    if x == 0:
        unit1.attack(unit2)
        print("{} attacked and {} left {} health".format(unit1.name, unit2.name, unit2.health))
    else:
        unit2.attack(unit1)
        print("{} attacked and {} left {} health".format(unit2.name, unit1.name, unit1.health))
 
if unit1.health == 0:
    print("Russia win")
else:
    print("Ukraine win")

Ответ на от Виталий

import random
class Warrior:
    def __init__(self, name, value2, value):
        self.health = value
        self.name = name
        self.ctd = value2 # chance to dodge
 
    def attack(self, enemy):
        enemy.health = enemy.health - 20
 
 
 
 
unit1 = Warrior("Рагнар", 6, 100)
unit2 = Warrior("Ульрик", 4, 100)
 
 
while unit1.health > 0 and unit2.health > 0:
    x = random.randint(0, 1)
    c = random.randint(1, 10)
    if x == 0:
        if unit2.ctd > c:
            print("{} увернулся от атаки {}a.".format(unit2.name, unit1.name))
        else:
            unit1.attack(unit2)
            print("{} атаковал {}. У {} осталось {} единиц здоровья.".format(unit1.name, unit2.name, unit2.name, unit2.health))
    else:
        if unit1.ctd > c:
            print("{} увернулся от атаки {}.".format(unit1.name, unit2.name))
        else:
             unit2.attack(unit1)
             print("{} атаковал {}. У {} осталось {} единиц здоровья.".format(unit2.name, unit1.name, unit1.name, unit1.health))
 
if unit1.health == 0:
    print(unit2.name, " победил!")
else:
    print(unit1.name, " победил!")
сделал на основе вашего

Работает: (результат можна приукрасить как по заданию)
import random
class War:
    def sethp(self, h):
        self.general = h
    def damage (self, d):
        hurt = self.general - d
        self.general = hurt
        if hurt >0:
            return hurt
        else:
            print('игрок: ')
 
 
 
 
unit = War()
wiki = War()
unit.sethp(1000)     #gamer 1
wiki.sethp(1000)     #gamer 2
 
while (unit.general > 0) and (wiki.general >0):
    m = random.randint(1,2)
    if m == 1:
        wiki.damage(20)
        print ('wiki потерпел урон, Health: ', wiki.general)
    else:
        unit.damage(20)
        print('unit потерпел урон, Health: ', unit.general)
input('press any key for ending!')
 
#инфа о здоровье: unit.general

import random
class Warriors:
    hp = 100
    def Hit(self):
        self.hp -= 20
 
Fight = bool
Asterix = Warriors()
Obelix = Warriors()
i = 1
while Fight : #new round
    if Asterix.hp <= 0:
        print("Обеликс победил!")
        break
    if Obelix.hp <= 0:
        print("Астерикс победил!")
        break
    print("Раунд номер " + str(i) + " в бой!")
    n = random.randint(0, 10)
    if n % 2 == 0:
        print("Обеликс наносит удар!")
        Asterix.Hit()
        print("У Астрикса осталось" + str(Asterix.hp) +"хп")
        print()
    else:
        n % 2 != 0
        print("Астерикс наносит удар!")
        Obelix.Hit()
        print("У Обеликса осталось" + str(Obelix.hp) + "хп")
        print()
    i += 1

from random import randint
 
class Unit:
 
    def heatPoints(self, hp):
        self.hp = hp
 
    def attack(enemy):
        enemy.hp -= 20
 
me = Unit()
enemy = Unit()
me.heatPoints(100)
enemy.heatPoints(100)
 
while me.hp> 0 and enemy.hp > 0:
    n = randint(1, 2)
    if n == 1:
        print(f"Enemy have {enemy.hp} hp")
        print(f"You attack")
        Unit.attack(enemy)
        print(f"Enemy have {enemy.hp} hp")
        print()
    else:
        print(f"You have {me.hp} hp")
        print(f"Enemy attack")
        Unit.attack(me)
        print(f"You have {me.hp} hp")
        print()
 
if me.hp == 0:
    print("You out of HP. Enemy won!")
elif enemy.hp == 0:
    print("Enemy out of HP. You won!")

import random
 
class Warrior:
    name = 'Warrior'
    hp = 100
    damage = 20
 
    def hit(self,enemy):
        enemy.hp -= self.damage
        print(enemy.name,enemy.hp)
 
Johan = Warrior()
Johan.name = "Johan"
Sebastian = Warrior()
Sebastian.name = "Sebastian"
 
while Johan.hp > 0 and Sebastian.hp > 0:
    hit_turne = random.randint(0, 1)
    if hit_turne:
        Johan.hit(Sebastian)
    else:
        Sebastian.hit(Johan)
 
if Johan.hp > 0:
    winner = Johan.name
else:
    winner = Sebastian.name
 
print('Победитель:',winner)

from random import randint
class Warrior:
    hp = 100
    name = ""
    def attak(self,enemy):
        enemy.hp -= 20
        print("{0} ранил {1} на 20 очков".format(self.name, enemy.name))
 
forest = Warrior()
rediska = Warrior()
forest.name = "Форест"
rediska.name = "Редиска"
 
def isWhoAtakk(t):
    if t == 1:
        forest.attak(rediska)
    else:
        rediska.attak(forest)
 
while 1:
    at = randint(0,1)
    isWhoAtakk(at)
    if forest.hp == 0:
        print("Победил {0}".format(rediska.name))
        break
    elif rediska.hp == 0:
        print("Победил {0}".format(forest.name))
        break
    else:
        continue

from random import randint
 
 
class unit:
    def __init__(self, name, hp, dmg):
        self.hp = hp
        self.dmg = dmg
        self.name = name
        print(self.name, " Количество hp = ", self.hp, "Количество dmg = ", self.dmg, end='\n\n')
 
    def __lt__(self, other):  # перегрузка оператора >
        print(other.name, " Наносит удар", self.name, " В размере ", other.dmg)
        self.hp -= other.dmg
        if self.hp <= 0:
            self.hp = 0
            print(" Победитель - ", other.name, "Проиграл - ", self.name)
            quit()
        print(other.name, " hp = ", other.hp, self.name, " hp = ", self.hp, end='\n\n')
 
 
a = unit("Диля", 100, 5)
b = unit("Димас", 300, 20)
i = 1
while i > 0:
    c = randint(0, 1)
    if c == 0:
        a > b
    else:
        b > a

from random import randint  #Импортируем для создания случайного порядка атаки
class Warrior:              #Создаем класс юнита
    hp = int(100)           #Задаем юниту кол-во HP
    dmg = int(20)           #Задаем юниту силу атаки
    def attack(self, enemy):            #Создаем функцию атаки с вносимыми параметрами для атакующего и атакуемого
        enemy.hp = enemy.hp - self.dmg  #Вычисление наносимого урона
        return(enemy.hp)                #Возвращаем значение HP для атакованного
w1 = Warrior()      #Создаем юнитов и задаем им класс воинов
w2 = Warrior()
while w1.hp > 0 and w2.hp > 0: #Создаём цикл с ограничением кол-ва HP юнитов на 0
    input('Нажмите Enter для атаки') #Задержка между атаками
    r = randint(1, 2)          #Генерируем случайную цифру 1 или 2
    #r = int(input('Введите номер атакующего война(1 или 2): ')) #Раскомментируем если вручную выбираем атакующего (нужно будет закомментить 2 строки выше)
    if r == 1:                 #Если сгенерировалась цифра 1
         w1.attack(w2)         #Первый воин атакует второго
         print("Воин 1 атакует Воина 2\nВоин 2 HP: ", w2.hp) #Выводим на экран инфу об атаке
    else:                      #Если сгенерировалась цифра 2
         w2.attack(w1)         #Второй воин атакует первого
         print("Воин 2 атакует Воина 1\nВоин 1 HP: ", w1.hp) #Выводим на экран инфу об атаке
    #print('Воин 1 HP: ', w1.hp,'\nВоин 2 HP: ', w2.hp)
if w1.hp > w2.hp:             #Определяем победителя по кол-ву HP
    print("Победил Воин 1")
else:
    print("Победил Воин 2")

import random as ra
 
 
class Warrior:
    hp = 100
 
    def setName(self, n):
        self.name = n
 
    def DG(self):
        return ra.randint(0, 20)
 
    def attack(self, enemy):
        enemy.hp -= self.DG()
 
 
unit_one = Warrior()
unit_two = Warrior()
unit_one.setName("Вася")
unit_two.setName("Петя")
 
while unit_one.hp > 0 and unit_two.hp > 0:
    chance = ra.randint(1, 2)
    if chance == 1:
        unit_one.attack(unit_two)
        print("Атакует " + unit_one.name)
        print("Здоровье Пети стало " + str(unit_two.hp))
    else:
        unit_two.attack(unit_one)
        print("Атакует " + unit_two.name)
        print("Здоровье Васи стало " + str(unit_one.hp))
 
if unit_one.hp <= 0:
    print("Победил " + unit_two.name + "!")
    print("У него осталось " + str(unit_two.hp) + " здоровья.")
else:
    print("Победил " + unit_one.name + "!")
    print("У него осталось " + str(unit_one.hp) + " здоровья.")

import random
 
class Warrior:
    health = 100
    def attack(self):
        self.health -= 20
 
firstWarrior = Warrior()
secondWarrior = Warrior()
while firstWarrior.health > 0 or secondWarrior.health > 0:
    i = random.randint(0, 2)
    if i == 0:
        Warrior.attack(secondWarrior)
        print("First warrior damage second warrior for 20 and health of second warrior now is ", secondWarrior.health)
    else:
        Warrior.attack(firstWarrior)
        print("Second warrior damage first warrior for 20 and health of first warrior now is ", secondWarrior.health)
if firstWarrior.health == 0:
    print("Second warrior win!")
else:
    print("First warrior win!")