init()函数是Python中一个特殊的函数,它在创建对象时自动执行,用于初始化对象的属性。 当我们创建一个类的实例时,Python会自动调用该类的init函数,并传入该对象自身作为第一个参数(通常习惯上命名为self),然后我们可以在init函数中为对象的属性赋初始值。
1.1.1不带参数的init魔法方法
示例:
class Washer():
def __init__(self): # 初始化魔法方法
# 添加属性
print('这是初始化魔法方法')
self.height = 1000
self.width = 300
def print_info(self, name):
"""获取属性"""
print('洗衣机的高度是:', self.height)
print(name)
xiaotiane = Washer()
xiaotiane.print_info('nihao')
1.1.2带参数的init魔法方法
示例:
class Washer():
def __init__(self, height, width): # 初始化魔法方法
# 添加属性
self.height = height
self.width = width
def print_info(self):
"""获取属性"""
print('洗衣机的高度是:', self.height)
print('洗衣机的高度是:', self.width)
xiaotiane = Washer(1000, 300)
xiaotiane.print_info()
当print输出一个对象的时候,默认打印的是对象的内存空间地址,如果在类中定义了str魔法方法之后,那么此时在打印对象的时候就是打印的这个方法的返回值。
示例:
class Washer():
def wash(self):
print('洗衣服===')
def __str__(self): # 类的说明或者类的状态
return '这是洗衣机的使用说明'
xiaotiane = Washer()
print(xiaotiane)
当删除一个对象的时候,Python解释器会自动调用del魔法方法
示例:
class Washer():
def wash(self):
print('洗衣服===')
def __del__(self):
"""删除对象"""
print(f'{self}对象已经被删除')
xiaotiane = Washer()
del xiaotiane
print(xiaotiane) # 报错
注意:
如果一个类有多个对象,每个对象的属性是各自独立保存的,都是独立的地址。
但是实例方法是所有对象所共享的,只占用一份内存空间,类会通过self参数来判断是那个对象调用了该实例方法。
Python中面向对象中的继承就是指的是多个类之间的一个从属关系,即子类默认继承父类的所有方法和属性。
所谓单继承就是指子类只继承一个父类
示例:
# 定义父类
class Master(object):
def __init__(self):
self.kongfu = '一剑仙人跪'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
# 定义子类
class Prentice(Master):
pass
# 用子类创建对象,调用父类的属性和方法
xiaoxu = Prentice()
print(xiaoxu.kongfu) # 子类对象调用父类的属性
xiaoxu.battle() # 子类的对象调用父类的方法
总结:
子类在继承的时候,在定义类的时候,小括号中写的就是父类的名字
父类的方法和属性都会被子类继承
所谓多继承就是指一个子类同时继承多个父类。
示例:
# 定义第一个父类
class Master(object):
def __init__(self):
self.kongfu = '一剑仙人跪'
self.name = '李淳罡'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
# 定义第二个父类
class Maid(object):
def __init__(self):
self.kongfu = '霸王卸甲'
self.name = '青鸟'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
def aaa(self):
print('这是侍女类的aaa方法')
# 定义子类类
class Prentice(Master, Maid):
def __init__(self):
self.kongfu = '剑气滚龙壁'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
# 用徒弟创建对象,调用师傅的属性和方法
xiaoxu = Prentice()
print(xiaoxu.kongfu)
# 子类的魔法属性__mro__ 决定了属性和方法的查找顺序
print(Prentice.__mro__)
总结:
多继承可以继承多个父类,也继承了所有父类的属性和方法
注意:如果多个父类中有同名的方法和属性,则默认使用第一个父类的属性和方法(根据类中魔法属性mro的顺序来查找的)
多个父类中,不同名的属性和方法,不会有任何影响
示例:
# 定义第一个父类
class Master(object):
def __init__(self):
self.kongfu = '一剑仙人跪'
self.name = '李淳罡'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
# 定义第二个父类
class Maid(object):
def __init__(self):
self.kongfu = '霸王卸甲'
self.name = '青鸟'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
def aaa(self):
print('这是侍女类的aaa方法')
# 定义子类
class Prentice(Master, Maid):
def __init__(self):
self.kongfu = '剑气滚龙壁'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
# # 用子类创建对象,调用父类的属性和方法
# xiaoxu = Prentice()
# print(xiaoxu.kongfu)
# xiaoxu.battle()
print(Prentice.__mro__)
示例:
# 定义第一个父类
class Master(object):
def __init__(self):
self.kongfu = '一剑仙人跪'
self.name = '李淳罡'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
# 定义第二个父类
class Maid(object):
def __init__(self):
self.kongfu = '霸王卸甲'
self.name = '青鸟'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
def aaa(self):
print('这是侍女类的aaa方法')
# 定义子类
class Prentice(Master, Maid):
def __init__(self):
self.kongfu = '剑气滚龙壁'
def battle(self):
self.__init__()
print(f'运用了{self.kongfu}和敌人battle')
# 把父类的同名方法和属性再次封装就可以了
def master_battle(self):
# 父类名.方法名(self)
Master.__init__(self)
Master.battle(self)
# Master().battle() # 不推荐使用
# # 用子类创建对象,调用父类的属性和方法
xiaoxu = Prentice()
# print(xiaoxu.kongfu)
xiaoxu.battle()
xiaoxu.master_battle()
xiaoxu.battle()
核心点:无论何时何地,self都表示的是子类的对象,在调用父类方法时,通过传递self参数,来控制方法和属性的访问和修改。
Master().battle() # 不推荐使用,因为相当于重新创建了一个新的父类对象,占用不必要的内存。
所谓多层继承就是父类被子类1继承,然后子类1(父类)被子类2继承
示例:
# 定义第一个父类
class Master(object):
def __init__(self):
self.kongfu = '一剑仙人跪'
# self.name = '李淳罡'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
# 定义第二个父类
class Maid(object):
def __init__(self):
self.kongfu = '霸王卸甲'
self.name = '青鸟'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
def aaa(self):
print('这是侍女类的aaa方法')
# 定义子类
class Prentice(Master, Maid):
def __init__(self):
self.kongfu = '剑气滚龙壁'
def battle(self):
self.__init__()
print(f'运用了{self.kongfu}和敌人battle')
# 把父类的同名方法和属性再次封装就可以了
def master_battle(self):
# 父类名.方法名(self)
Master.__init__(self)
Master.battle(self)
# Master().battle() # 不推荐使用
class Daughter(Prentice):
pass
xiaodigua = Daughter()
print(xiaodigua.kongfu)
xiaodigua.battle()
xiaodigua.master_battle()
使用super()方法可以自动查找父类,调用的顺序遵循__mro__
类属性的顺序,比较适合单继承使用
注意:如果继承了多个父类,且父类有同名方法和属性,则默认只执行第一个父类的同名方法和属性(且同名方法只执行一次,目前super不支持多个父类的同名方法).
示例:
# 定义第一个父类
class Master(object):
def __init__(self):
self.kongfu = '一剑仙人跪'
# self.name = '李淳罡'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
# 定义第二个父类
class Maid(Master):
def __init__(self):
self.kongfu = '霸王卸甲'
self.name = '青鸟'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
def aaa(self):
print('这是侍女类的aaa方法')
def bbb(self):
super().__init__()
super().battle()
# 定义子类
class Prentice(Maid):
def __init__(self):
self.kongfu = '剑气滚龙壁'
def battle(self):
self.__init__()
print(f'运用了{self.kongfu}和敌人battle')
# 把父类的同名方法和属性再次封装就可以了
def master_battle(self):
# 父类名.方法名(self)
Master.__init__(self) # 如果定义的类名修改,那么这个里面的代码也要修改
Master.battle(self)
def old_battle(self):
# 方案一 super().方法()
# super().__init__()
# super().battle()
# 方案二 super(类名,self).方法()
super(Maid, self).__init__()
super(Maid, self).battle()
xiaoxu = Prentice()
xiaoxu.old_battle()
print(Prentice.__mro__)
xiaoxu.battle()
xiaoxu.bbb()
在Python中,可以为实例方法和属性设置私有权限,即设置某个实例属性和实例方法不继承给子类。
设置私有属性和私有方法的语法是:在属性和方法前面加上两个下划线。
示例:
# 定义父类
class Master(object):
def __init__(self):
self.kongfu = '一剑仙人跪'
self.__name = '李淳罡'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
def __print_info(self):
print(self.__name)
# 定义子类
class Prentice(Master):
pass
# 用子类创建对象,调用父类的属性和方法
xiaoxu = Prentice()
# print(xiaoxu.__name)
# xiaoxu.print_info()
# laoli = Master()
# print(laoli.__name)
# xiaoxu.__print_info()
# laoli.__print_info()
总结:对象不能访问私有属性和私有方法,子类无法继承父类的私有属性和私有方法。
在Python中,一般定义方法名get_xxxx用来表示获取私有属性,定义set_xxxxx用来表示修改私有属性值,这是约定俗称的命名方法,不是强制要求。
示例:
# 定义父类
class Master(object):
def __init__(self):
self.kongfu = '一剑仙人跪'
self.__name = '李淳罡'
def battle(self):
print(f'运用了{self.kongfu}和敌人battle')
def get_name(self):
return self.__name
def set_name(self):
self.__name = '老徐'
# 定义子类
class Prentice(Master):
pass
# 用子类创建对象,调用父类的属性和方法
xiaoxu = Prentice()
print(xiaoxu.get_name())
xiaoxu.set_name()
print(xiaoxu.get_name())
总结:
继承的特点:
子类默认拥有父类的所有属性和方法,除了私有属性和私有方法。
多态指的是一类事物有多
多态指的是一类事物有多种形态(一个抽象类有多个子类,因而多态的概念依赖于继承)
定义:多态是一种使用对象的方式,子类重写父类方法,调用不同的子类对象的同一父类方法时,产生不同的对象。
好处:调用灵活,有了多态,更加容易编写出来通用的代码,做出通用的编程,以适应不同的需求。
实现步骤:
定义父类,并提供公共方法
定义子类,并重写父类方法
传递子类对象给调用者,可以看到不同的子类的执行结果。
示例:
# 需求:狗有很多种,有抓坏人的 有找毒品的 警察带不同狗工作可以做不同的事
# 定义父类
class Dog(object):
def work(self):
pass
# 定义子类
class ArmyDog(Dog):
def work(self):
print('抓坏人,小偷')
class DrugDog(Dog):
def work(self):
print('找毒品')
class Person(object):
def work_with_dog(self, dog):
dog.work()
# 创建对象,实现不同的功能,传入不同的对象,观察执行结果
ad = ArmyDog()
dd = DrugDog()
xiaofu = Person()
xiaofu.work_with_dog(ad)
xiaofu.work_with_dog(dd)
6.1.1 设置和访问类属性
类属性就是类对象所拥有的属性,他被该类的所有对象所共有
类属性可以使用类对象或者实例对象访问
示例:
class Wife(object):
gender = '女' # 类属性
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age
def print_info(self):
print(self.name)
print(self.age)
xiaoxu = Wife('张磊', 18)
# xiaoxu.print_info()
xiaoxu1 = Wife('张磊2', 30)
# xiaoxu1.print_info()
# print(xiaoxu1.gender) # 实例对象访问类属性
# print(xiaoxu.gender)
# print(Wife.gender) # 类对象访问类属性
# # id地址一样
# print(id(xiaoxu1.gender))
# print(id(xiaoxu.gender))
# # id地址不一样
print(id(xiaoxu1.name))
print(id(xiaoxu.name))
总结:
记录的某项数据始终保持一致的时候,则可以定义类属性
实例属性要求每一个对象为其开辟一份独立的内存空间记录属性值,而类属性为全局所共有,仅占用一份内存空间,更加的节省资源。
6.1.2?修改类属性
类属性只能通过类对象来修改,不能通过实例对象来修改,如果这样操作了,只是重新为此实例对象重新添加了一个实例属性而已。
示例:
class Wife(object):
gender = '女' # 类属性
def __init__(self, name, age):
self.name = name
self.age = age
def print_info(self):
print(self.name)
print(self.age)
xiaozhang = Wife('张磊', 18)
xiaozhang1 = Wife('张磊1', 30)
# 通过类对象修改类属性
# print(Wife.gender)
# Wife.gender = '中性'
# print(Wife.gender)
# print(xiaozhang.gender)
# print(xiaozhang1.gender)
# 不能通过实例对象修改类属性
xiaozhang.gender = '中性'
print(Wife.gender)
print(xiaozhang.gender)
print(xiaozhang1.gender)