登录 实例对象
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)