实例对象
Python 的类
Python 中可用的原始数据结构(如数字,字符串和列表)旨在分别表示简单的事物,例如进行简单的数学运算,动物的名称和你喜欢的颜色。
如果你想代表更复杂的东西怎么办?
例如对于动物,我们可以创建一个 Animal()
类来跟踪动物的属性,如名称和年龄。
重要的是要注意一个类只提供结构 ——它是应该如何定义某个东西的模板,但它实际上并不提供任何真实的内容。该 Animal()
可以指定姓名和年龄是必要的界定动物,但它实际上并不会说出什么特定动物的姓名或年龄。
类和对象的概念
类
和 对象
是面向对象编程的两个核心概念
类
是对一群具有相同 特征
或者 行为
的事物的一个统称,是抽象的。
特征
被称为属性
行为
被称为方法
类和对象的关系
类
是模板,对象
是根据类
这个模板创建出来的,应该先有类,再有对象类
只有一个,而对象
可以有很多个不同的对象
之间属性
可能会各不相同类
中定义了什么属性和方法
,对象
中就有什么属性和方法
注意
例如 人(类)
是一个类对象, 人(类)
会有一些特征,例如身高、体重,还有一些行为,例如吃饭、睡觉。
但是人类没有具体的属性与特征,例如 人(类)
的年龄为 18
岁,一看就知道是个病句。
但是可以说 正心(人的具体某一个实例对象)
年年 18
岁(一听就知道在开玩笑)。
实例对象
实例对象是指有类对象初始化之后得到的对象。
初始化方法
当使用类对象创建实例对象时,__init__()
初始化方法就会被自动调用。初始化既是对象生命周期的开始,也是非常重要的一个步骤, 每个对象都必须正确地执行了初始化才能够正常地工作。
通过实现 __init__()
方法来初始化一个对象。每当创建一个对象,Python 会先创建一个空对象,然后自动调用该对象的 __init__()
函数,完成初始化操作。
class Person:
def __init__(self):
print("这是一个初始化方法")
# 使用 类名 + () 创建对象的时候,会自动调
zx = Person()
初始化属性
一个对象是一系列功能的集合,包括了方法和属性。object
类的默认行为包括设置、获取和删除属性。可以通过修改这些默认行为来决定对象中哪些属性是可用的。
如果希望在创建对象的同时,就设置对象的属性,可以对 __init__
方法进行改造
- 修改
__init__
方法的接收参数 - 在方法内部使用
self.属性 = 形参
接收外部传递的参数 - 定义属性之后,再使用
Person
类创建的对象,都会拥有该属性 - 在创建对象时,使用
类名(属性1, 属性2...)
调用
def __init__(self, name, high, weight):
"""初始化方法"""
self.name = name
self.high = high
self.weight = weight
当一个类定义完成之后,要使用这个类来创建对象,语法格式如下:
对象变量 = 类名()
完整代码
例如在玩游戏时,我们创建人物对象一般会需要人物的明显与年龄等特这个,我们可以用代码来模拟整个创建过程
"""
定义一个人(Person)类
人在出生时就会有名字、身高、体重等特征
人在刚出生是会吃、喝、哭等行为
"""
class Person(object):
def __init__(self, name, age):
"""初始化方法"""
self.name = name
self.age = age
def hello(self):
print('我的名字是:{},已经:{}岁了'.format(self.name, self.age))
zx = Person('正心', 18)
# 获取属性
print(zx.name)
print(zx.age)
# 在外部修改属性
zx.age = 18
# 再外部新增属性
zx.gender = '男'
zx.hello()
案例-实例对象
"""
创建一个游戏英雄类(Hero)
分别有以下属性
名字(name),武器(weapon),装备(equipment),血量(blood)
每个英雄类都有游戏技能,分别为(行为)
攻击(attack),对被攻击人造成对等的攻击力伤害
创建两个英雄
'黄忠', '弓箭', ['头盔', '靴子'], 100
'刘备', '剑', ['头盔', '盔甲'], 100
"""
参考代码
# Hero 类对象
class Hero:
def __init__(self, name, weapon, equipment, blood):
self.name = name
self.weapon = weapon
self.equipment = equipment
self.blood = blood
def attack(self):
return f'{self.name} 发动了攻击'
# 使用类对象创建一个实例对象
# 实例对象是具体到某一个人, 类对象是某一类事物的统称
hero1 = Hero('黄忠', '弓箭', ['头盔', '靴子'], 100)
hero2 = Hero('刘备', '剑', ['头盔', '盔甲'], 100)
print(hero1.name, hero1.weapon, hero1.equipment, hero1.attack())
print(hero1.equipment)
print(hero1.equipment[0])
print(hero1.equipment[1])
__init__ 方法(了解)
对象的生命周期主要包括了创建、初始化和销毁。后面课程会详细讨论对象的创建和销毁,本章专注于对象的初始化。
object 作为所有类的基类,已经为 __init__()
方法提供了默认实现,一般情况下不需要重写这个函数。如果没有对它进行重写,那么在创建对象时将不会产生其他变量的实例。在某些情况下,这种默认行为是可以接受的。
对于继承自 object
的子类,总可以对它的属性进行扩展。例如,对于下面这个类,实例化就不对函数(tom
)所需要的变量(name
和 age
)进行初始化。
class Person(object):
# def __init__(self):
# pass
def hello(self):
print('我的名字是:{},已经:{}岁了'.format(self.name, self.age))
Person
类的 hello
函数在返回值时使用了两个属性,可并没有在任何地方对其赋值。在 Python 中,这种看似奇怪的调用尚未赋值属性的操作却是合法的。
下面这段代码演示如何使用刚定义的 Person
类。
>>> tom = Person()
>>> tom.name = '汤姆'
>>> tom.age = '18'
>>> tom.hello()
我的名字是:汤姆,已经:18岁了
虽然这种 延迟赋值 的实现方式在 Python 中是合法的,但是却给调用者带来了潜在的困惑,因此要尽量避免这样的用法。
然而,这样的设计看似又提供了灵活性,意味着在 __init__()
方法被调用时不必为所有的属性赋值。这看似是不错的选择,一个可选属性即可以看作是某子类中的成员,且无须对这个子类进行显式地定义就可以完成对原生机制的扩展。然而这种多态机制不但给程序带来了隐藏的不确定性,也会相应产生很多令人费解的 if
语句。
因此,延迟初始化属性的设计在某种情形下可能会有用,可是这样也可能会导致非常糟糕的设计。
在 Zen of python poem 一书中曾提出过这样的建议:
“显式而非隐式”。 对于每个__init__()
方法,都应当显式地指定要初始化的变量。
self 指代实例对象
在类封装的方法内部,self
就表示当前调用方法的实例对象。 由哪一个对象调用实例方法,方法内的 self
就是哪一个对象的引用。 在方法内部可以通过 self.属性名
访问实例对象的属性,也可以通过 self.方法名
访问实例对象的方法。
class Hero:
def __init__(self, name, weapon, equipment, blood):
self.name = name # 把传进来的参数绑定到后面实例化的对象上
self.weapon = weapon
self.equipment = equipment
self.blood = blood
# self 指代的就是实例化的一个一个对象
# 实例方法, 类模板里面的方法, 默认都需要接收一个self参数
# 接收 self 参数的都是实例方法, 被绑定在实例对象上面
def return_self(self):
return self
hero1 = Hero('黄忠', '弓箭', ['头盔', '靴子'], 100)
attr = hero1.return_self()
print(id(hero1))
print(id(attr))
hero2 = Hero('刘备', '剑', ['头盔', '盔甲'], 100)
attr2 = hero2.return_self()
print(id(hero2))
print(id(attr2))
- 在类的外部,通过
变量名.
访问对象的属性和方法 - 在类封装的方法中,通过
self.
访问对象的属性和方法
带参数的实例方法
实例对象的方法与普通函数之间的区别在于第一个参数会接收 self
实例对象。其余的用法都是类似的
"""
创建一个游戏英雄类,
分别有以下属性
名字(name),武器(weapon),装备(equipment),血量(blood)
每个英雄类都有游戏技能,分别为(行为)
攻击(attack)与逃跑(run)
创建两个英雄
'黄忠', '弓箭', ['头盔', '靴子'], 100
'刘备', '剑', ['头盔', '盔甲'], 100
黄忠攻击刘备,刘备血量 -10
"""
参考代码
class Hero:
def __init__(self, name, weapon, equipment, blood):
self.name = name
self.weapon = weapon
self.equipment = equipment
self.blood = blood
def attack(self, hero=None):
if hero:
print(self.name, '攻击了', hero.name)
hero.blood -= 10
print(hero.name, '血量还剩下', hero.blood)
else:
print(self.name, '正在发动攻击')
def run(self):
print(self.name, '逃跑了')
def return_data(self):
# 把重要的数据保存
return self.name, self.weapon, self.equipment, self.blood
hz = Hero('黄忠', '弓箭', ['头盔', '靴子'], 100)
lb = Hero('刘备', '剑', ['头盔', '盔甲'], 100)
print(lb.blood)
hz.attack(lb) # 黄忠攻击了刘备
lb.run() # 刘备逃跑了
lb.attack(hz) # 刘备杀回来了
hz.run() # 黄忠逃跑了
print('刘备血量:', lb.blood)
print('黄忠血量:', hz.blood)