对象:具体的事物
好处:可以复用、灵活性更高
面向对象:
多个对象——>提取对象的特征和动作——>封装到一个类中
先有需求——>找出特征——>定义类
类:所有对象都要有共同的特征和共同的方法
class 类名(父类):
属性:特性
...
方法:动作
...
只要遇到 class,就在内存里边开辟空间,但可以不放东西。然后使用类来构建出一个个实际的对象。
# 定义类
class Phone():
pass
# 用类来生成实际的对象,类名加() 就找到原来的类地址,创建一个和类相同的空间,地址不同
xiaohua = Phone()
print(xiaohua)
xiaoming = Phone()
print(xiaoming)
>>>
<__main__.Phone object at 0x00000197A0D6A208>
<__main__.Phone object at 0x00000197A0D6A128>
# 定义类
class Phone():
brand = 'huawei'
# 直接用类里边的属性
xiaohua = Phone()
print(xiaohua.brand)
xiaoming = Phone()
print(xiaoming.brand)
>>>
huawei
huawei
# 定义类
class Phone():
brand = 'huawei'
# 修改类中的属性
xiaohua = Phone()
xiaohua.brand = 'iPhone'
print(xiaohua.brand)
xiaoming = Phone()
print(xiaoming.brand)
>>>
iPhone
huawei
类属性:类自带的属性
对象属性:对象在调用了这个类生成对象以后,动态生成的自己的属性。
# 定义类和属性,只要定义类,就会产生一个空间,空间中有有属性,定义类只是得到一个初始的,但并不是实际的对象
class Student:
# 类属性
name = 'xiaoming'
age = 3
# 使用类来构建一个对象,先定义类,再使用类
# 对象属性找的时候,先去这个对象空间里边找,找不到,就去类属性里边找
# 对象属性可以修改,但不会改动类的属性
xiaoming = Student()
# 赋值操作,在xiaoming的空间里新动态创建一个属性,这个属性只属于xiaoming这个空间,不属于类空间
# 属于这个对象自己的属性,称为 对象属性
xiaoming.age = 18
print(xiaoming.age)
>>>
18
xiaohua = Student()
print(xiaohua.name)
# 只要有赋值操作,就会在 xiaohua 的空间里边增加一个属性,原本是空的
xiaohua.name = 'xiaohua'
xiaohua.age = 1
print(xiaohua.name)
print(xiaohua.age)
>>>
xiaoming
xiaohua
1
怎么访问类属性:一定要用类名来访问
Student.name = 'Jack'
print(Student.name)
>>>
Jack
方法:动作部分
方法的分类:
def 方法名(self[,参数])
方法体...
class Phone:
brand = 'xiaomi'
price = 4999
type = 'mate 80'
# 普通方法
def call(self):
print('正在打电话...')
# 当构造的对象叫 phone1 时,self指向 phone1 这个对象
print('self: ',self)
phone1 = Phone()
print('phone1:',phone1) # 输出内存地址
phone1.call()
print('*********************************')
phone2 = Phone()
print('phone2:',phone2) # 输出内存地址
phone2.call()
>>>
phone1: <__main__.Phone object at 0x00000197A0D5C978>
正在打电话...
self: <__main__.Phone object at 0x00000197A0D5C978>
*********************************
phone2: <__main__.Phone object at 0x00000197A0D63518>
正在打电话...
self: <__main__.Phone object at 0x00000197A0D63518>
哪个对象调用 call,就会把这个对象作为参数传给 self 。就叫做自身。我自己调用 call,就把自己扔进去了。
class Phone:
brand = 'xiaomi'
price = 4999
type = 'mate 80'
# 普通方法
def call(self):
# 当构造的对象叫 phone1 时,self指向 phone1 这个对象
print('note: ',self.note)
phone1 = Phone()
phone1.note = '我是 phone1 的 note'
phone1.call() # 往括号里边传的就是 phone1
print('*********************************')
phone2 = Phone()
phone2.note = '我是 phone2 的 note'
phone2.call()
>>>
note: 我是 phone1 的 note
*********************************
note: 我是 phone2 的 note
self 的好处:谁调用,self 就是谁
这样操作可能出现的问题:不是每个对象的属性都是相同的,或者说有的对象没有某些属性。
下面这个例子,就是说不能保证每个被传进来的 self 都有 address_book.
class Phone:
brand = 'xiaomi'
price = 4999
type = 'mate 80'
# 普通方法
def call(self):
# 当构造的对象叫 phone1 时,self指向 phone1 这个对象
print('正在访问通讯录...')
for person in self.address_book:
print(person.items())
phone1 = Phone()
phone1.address_book = [{'15900889976':'xiaoming'},{'13457889999':'xiaohua'}]
phone1.call() # 往括号里边传的就是 phone1
print('\n*********************************\n')
phone2 = Phone()
phone2.call()
>>>
正在访问通讯录...
dict_items([('15900889976', 'xiaoming')])
dict_items([('13457889999', 'xiaohua')])
*********************************
正在访问通讯录...
...
AttributeError: 'Phone' object has no attribute 'address_book'
解决上述问题:
魔术方法:只要用了类的名,系统默认就会执行
先定义一个类,会创建一个类,用类创建一个对象。
p = Phone()
# 1、先找有没有 Phone 这个空间
# 2、申请和 Phone 一样的空间,地址不同
# 3、回到类里边看,如果类里边提供了魔术方法__init__
# 如果没有,不用管,则执行将得到的内存空间给到 p
# 如果有,则进入 __init__,执行里边的动作,此时 init 里边的 self 是当这个对象 p 的地址,会把init里边的属性放到对象空间里边。之后就不能改类里边的属性了,可以改对象里边的属性。
# 4、执行完 init 之后,才给对象 p 赋值
init 作用:做一个标准化,保证每个通过这个类得到的对象,都有这些属性
class Phone:
# 魔术方法之一(魔术方法:前后有 __ 的)
def __init__(self): # 初始化
# self 是创建的对象
# self. ... 就表示动态的给 self 空间中添加了两个属性
self.brand = 'huawei'
self.price = '4999'
def call(self):
# 当构造的对象叫 phone1 时,self指向 phone1 这个对象
print('正在访问通讯录...')
for person in self.address_book:
print(person.items())
p = Phone()
在 init 中直接传参:
class Phone:
# 魔术方法之一(魔术方法:前后有 __ 的)
def __init__(self, name, age):
self.name = name
self.age = age
def call(self):
print('{}今年{}岁了!'.format(self.name, self.age))
p = Phone('xiaoming',22)
p.call()
>>>
xiaoming今年22岁了!
创建对象的时候,只要传值了,默认就会把值送到 init 里边。
class Cat:
type = 'cat'
# 通过__init__ 初始化特征
def __init__(self, nickname, age, color):
self.nickname = nickname
self.age = age
self.color = color
# 动作:方法
def eat(self, food):
print('{}喜欢吃{}'.format(self.nickname,food))
def catch_mouse(self, color, weight):
print('{}抓了一只{}kg的老鼠,{}色的!'.format(self.nickname, weight, color))
def sleep(self,hour):
if hour<5:
print('继续睡吧!')
else:
print('快起来抓老鼠!')
def show(self):
print('猫的详情:')
print(self.nickname, self.color, self.age)
# 创建对象:利用 cat 这个类,构建一个真实的猫
cat1 = Cat('xiaoguai', 2, 'white')
# 调用这个类的方法
cat1.catch_mouse('黑','2')
cat1.eat('小金鱼')
cat1.sleep(5)
cat1.show()
>>>
xiaoguai抓了一只2kg的老鼠,黑色的!
xiaoguai喜欢吃小金鱼
快起来抓老鼠!
猫的详情:
xiaoguai white 2
普通方法的相互调用,要加 self
class Dog:
def __init__(self,nickname):
self.nickname = nickname
def run(self):
print('{}在院子里跑来跑去'.format(self.nickname))
def eat(self):
print('{}吃了很多'.format(self.nickname))
self.run()
d = Dog('大黄')
d.eat()
>>>
大黄吃了很多
大黄在院子里跑来跑去
普通方法的 self 就是对象,要依靠对象来调用。
类方法直接用类就可以调用。
类方法,调用的时候往这里穿的不是对象,而是类。
特点:
作用:
class Dog:
color = 'White'
def __init__(self,nickname):
self.nickname = nickname
def run(self):
print('{}在院子里跑来跑去'.format(self.nickname))
@classmethod
def test(cls):
print(cls) #
# 类方法的调用
Dog.test()
>>>
<class '__main__.Dog'>
类方法不能调用有self的方法,因为有self的方法的调用都要依赖于self。
类方法的作用例子:
# 非私有属性,可以在外边直接访问到
class Person:
age = 18
def show(self):
print('---------->',Person.age)
print('---------->',self.age)
@classmethod
def test(cls):
print('---------->类方法')
Person.test()
Person.age
>>>
---------->类方法
18
私有类:只能在类里边改这个属性,在外边不能访问以及修改
怎么操作呢?只能依赖于类方法对其进行修改
class Person:
__age = 18
def show(self):
print('---------->',Person.age)
@classmethod
def test(cls):
print('---------->类方法')
cls.__age = 20
print('修改后的年龄是:', cls.__age)
# 不创建对象,就想要改属性的需求
Person.test()
>>>
---------->类方法
修改后的年龄是: 20
静态方法:类似于类方法
class Person:
__age = 18
def __init__(self, name):
self.name = name
def show(self):
print('---------->',Person.age)
@staticmethod
def test():
print('---------->静态方法')
print(Person.__age)
Person.test()
>>>
---------->静态方法
18
类方法和静态方法的不同:
相同之处:
普通方法和上述两者的不同:
魔术方法就是一个类/对象中的方法,和普通方法唯一的不同是,普通方法需要调用,而魔术方法是在特定时刻自动触发。只要你写了这个魔术方法,不用调也能自动触发。
1、_ init _:初始化魔术方法
触发时机:初始化对象时触发,不是实例化触发,但和实例化在一个操作中
2、_ new _:实例化的魔术方法
触发时机:在实例化时,进行触发
3、_ call _:将对象当成函数调用的魔术方法
触发时机:将对象当做函数调用时触发
4、_ del :delete的缩写,析构魔术方法
触发时机:当对象没引用的时候被触发,也就是没有任何变量引用的时候。
5、_ str_ :打印对象名
触发时机:打印对象名的时候,自动触发,调用__str_ 里边的内容。
一定要在这个方法中加return,return 后面的内容就是打印对象看到的内容
单纯打印对象的名称,对开发者没有太大的意义,但使用__str__ 就可以直接打印变量名。
class Person:
def __init__(self, name):
self.name = name
p = Person('nana')
print(p)
>>>
<__main__.Person object at 0x00000197A0D96EF0>
class Person:
def __init__(self, name):
self.name = name
def __str__(self):
return '姓名是:'+self.name
p = Person('nana')
print(p)
>>>
姓名是:nana
class Student:
def __init__(self, name, age):
self.__score = 59
self.name = name
self.age = age
def __str__(self):
return '姓名:{}, 年龄:{}, 分数:{}'.format(self.name, self.age, self.__score)
student = Student('nana',18)
print(student)
>>>
姓名:nana, 年龄:18, 分数:59
能改吗?下面没有改成功
student.age = 21
student.__score = 95
print(student)
>>>
姓名:nana, 年龄:21, 分数:59
面向对象有一种封装操作:
为什么要私有化:
因为外界改不了,所以如果要改的话,要向外界暴露一个公有的东西,set 和 get。
class Student:
def __init__():
...
# setAge() 给私有属性赋新值
def setAge(self,age):
self.__age = age
# getAge() 可以在外边直接调用 p.getAge() 来访问
def getAge(self):
return self.__age
nana = Student()
nana.SetAge(21)
nana.getAge()
class Student:
def __init__(self, name, age):
self.__score = 59
self.__name = name
self.__age = age
def setName(self,name):
if len(name)>6:
self.__name = name
else:
print('姓名长度必须大于6位!')
def setAge(self,age):
if age>0 and age<100:
self.__age = age
else:
print('年龄不在规定范围内!')
def getAge(self):
return self.__age
def getName(self):
return self.__name
def setScore(self,score):
if score<100 and score>0:
self.__score = score
else:
print('成绩不符合规范,请重新输入')
def getScore(self):
return self.__score
def __str__(self):
return '姓名:{}, 年龄:{}, 分数:{}'.format(self.__name, self.__age, self.__score)
nana = Student('nana',18)
print(nana)
nana.setAge(21)
print(nana)
print('\n---------------------------\n')
nana = Student('nana',25)
print(nana)
nana.setScore(95)
print(nana)
print('\n---------------------------\n')
print(nana.getName())
print(nana.getAge())
print(nana.getScore())
>>>
姓名:nana, 年龄:18, 分数:59
姓名:nana, 年龄:21, 分数:59
---------------------------
姓名:nana, 年龄:25, 分数:59
姓名:nana, 年龄:25, 分数:95
---------------------------
nana
25
95
只要加了__name,底层就会给你改名成 _类名__name。
在开发中的私有化处理,装饰器
给setAge和getAge加一层装饰器,让外界用起来和没有私有化是一样的,但功能还能和私有化一样,加一些限制。
class Student:
def __init__(self, name, age):
self.__score = 59
self.__name = name
self.__age = age
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
if age>0 and age<100:
self.__age = age
else:
print('年龄不在规定范围内!')
def __str__(self):
return '姓名:{}, 年龄:{}, 分数:{}'.format(self.__name, self.__age, self.__score)
nana = Student('nana',18)
nana.age = 130
print(nana.age)
print(nana)
>>>
年龄不在规定范围内!
18
姓名:nana, 年龄:18, 分数:59
公路(Road):
属性:公路名称,公路长度
车(Car):
属性:车名,时速
方法:1、求车名在哪条公路上以多少的时速行驶了多长时间
2、初始化车辆属性信息
3、打印对象显示车的属性信息
import random
class Road:
def __init__(self, name, len):
self.name = name
self.len = len
class Car:
def __init__(self,brand, speed):
self.brand = brand
self.speed = speed
def get_time(self, road):
ran_time = random.randint(1,10)
msg = '{}品牌的车在{}上以{}速度行驶{}个小时!'.format(self.brand,road.name,self.speed,ran_time)
print(msg)
def __str__(self):
return '{}品牌的车,速度:{}'.format(self.brand,self.speed)
#创建实例化对象
r = Road('京藏高速',12000)
print(r.name)
audi = Car('Audi',120)
print(audi)
audi.get_time(r)
>>>
京藏高速
Audi品牌的车,速度:120
Audi品牌的车在京藏高速上以120速度行驶2个小时!
1)has a 关系:
has a:一个类里边有另一个类,不完全是继承关系,但是是一种包含关系。
# 创建三个类,则系统开辟三个空间,分别存这三个类的信息
# 然后调用的时候,就是创建三个对象
# student对象,需要name,computer
# 这里的computer也是一种类型,不过是自定义类型
# list、int 等都是系统提供的类型
#
class Computer:
pass
class Book:
pass
class Student:
pass
class Computer:
def __init__(self, brand, type, color):
self.brand = brand
self.type = type
self.color = color
def online(self):
print('正在使用电脑上网...')
def __str__(self):
return self.brand + '---' + self.type + '---' + self.color
class Book:
def __init__(self, bname, author, number):
self.bname = bname
self.author = author
self.number = number
def __str__(self):
return self.name + '---' + self.author + '---' + str(self.number)
class Student: # has a
def __init__(self,name,computer,book):
self.name = name
self.computer = computer
self.books=[]
self.books.append(book)
def borrow_book(self, book):
for book1 in self.books:
if book1.bname == book.bname:
print('已经借过了')
break
else:
# 将这本书加到列表中
self.books.append(book)
print('添加成功!')
def show_book(self):
for book in self.books:
print(book.bname)
def __str__(self):
return self.name + '---' + str(self.computer) + '---' + str(self.books)
# 创建对象
computer = Computer('mac','mac pro 2018','深灰色')
book = Book('盗墓笔记','南派三叔',10)
student = Student('nana',computer,book)
print(student)
book1 = Book('鬼吹灯','天下霸唱',8)
student.show_book()
student.borrow_book(book1)
print('--------------')
student.show_book()
>>>
nana---mac---mac pro 2018---深灰色---[<__main__.Book object at 0x000001F0F2343668>]
盗墓笔记
添加成功!
--------------
盗墓笔记
鬼吹灯
知识点:
2)is a 的关系:
如果 A 是 B,那么 B 就是 A 的基类,基类就是父类。
为什么要层层继承:
很多类中的方法是重复的,所以把每个类中间都具备的共同特征或共同属性,放到一个大类里边,其他的类直接继承来用就好啦。
# 基类:父类 base class
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(self.name + '正在吃饭!')
def run(self):
print(self.name + '正在跑步!')
class Employee:
def __init__(self, name, age):
self.name = name
self.age = age
class Doctor:
pass
使用继承的方法:把父类里边的东西都继承过来了,调用的时候是跑到父类里边去调用的。
class 子类(父类):
...
什么时候需要继承:
如何继承:
class Student(Person): ...
特点:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(self.name + '正在吃饭!')
def run(self):
print(self.name + '正在跑步!')
class Students(Person):
pass
class Employee(Person):
pass
class Dctor(Person):
pass
s = Students('nana',14) # 执行步骤,先调 __new__,产生新空间传给 __init__,student什么都没有,就会到其父类里边找
s.run()
>>>
nana正在跑步!
子类定义 init:都要把父类的 init 调用一下才可以
所有的类传参数都是传到 init 去了,所以,super 传参也就传到 init去了。
super其实是一个类,既然是个类,那么就要传参数,往init传参数。
调用的目的:保证把共同的特征拿过来。
# super() 表示父类对象
super().__init__()
无参数情况下定义 init:
class Person:
def __init__(self):
self.name = 'nana'
self.age = 14
def eat(self):
print(self.name + '正在吃饭!')
def run(self):
print(self.name + '正在跑步!')
class Students(Person):
def __init__(self):
print('-----> student 的 init')
super().__init__()
s = Students() # 执行步骤,先调 __new__,产生新空间传给 __init__,student什么都没有,就会到其父类里边找
s.run()
>>>
-----> student 的 init
nana正在跑步!
有参数情况下定义 init:
为什么要在每个子类定义 init:因为每个子类都会有他的特有属性和方法。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(self.name + '正在吃饭!')
def run(self):
print(self.name + '正在跑步!')
class Students(Person):
def __init__(self, name, age):
print('-----> student 的init')
super().__init__(name, age)
class Employee(Person):
pass
class Dctor(Person):
pass
s = Students('Jack',18) # 执行步骤,先调 __new__,产生新空间传给 __init__,student什么都没有,就会到其父类里边找
s.run()
e = Employee('lily',13)
e.run()
>>>
-----> student 的init
Jack正在跑步!
lily正在跑步!
并非所有类的属性都是共有的,类都会有自己特有的东西,所以,需要定义个体的不同之处:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(self.name + '正在吃饭!')
def run(self):
print(self.name + '正在跑步!')
class Students(Person):
def __init__(self, name, age, classes):
super().__init__(name, age) # 利用 super 把父类有的属性拿过来
self.classes = classes # 自己定义的属性
def study(self, course):
print('{}正在学{}'.format(self.name, course))
def eat(self, food):
# super().eat()
print('{}正在吃饭,喜欢吃{}'.format(self.name, food))
class Employee(Person):
def __init__(self, name, age, salary, manager):
super().__init__(name, age)
self.salary = salary
self.manager = manager
class Doctor(Person):
def __init__(self, name, age, patients):
super().__init__(name, age)
# super(Doctor, self).__init__(name, age) # 和上面等价,不过底层会做一个 isinstance 的判断,判断传进来的是不是 Doctor
self.patients = patients
s = Students('Jack',18, '1611') # 执行步骤,先调 __new__,产生新空间传给 __init__,student什么都没有,就会到其父类里边找
s.run()
s.study('python基础')
s.eat('红烧肉')
e = Employee('lily',23, 10000, 'king')
e.run()
list1 = ['tom','jack','json','lili']
d = Doctor('lucy', 30, list1)
d.run()
>>>
Jack正在跑步!
Jack正在学python基础
Jack正在吃饭,喜欢吃红烧肉
lily正在跑步!
lucy正在跑步!
练习:工资管理程序
编写一个工资管理程序,管理以下四类人: worker, salesman, manager, salemanager。
所有员工都具有工号,姓名,工资等属性,有设置姓名,获取姓名,获取员工号,计算工资等方法。
1)worker:具有工作小时数和时薪的属性,工资 = 小时*时薪
2)salesman:具有销售额和提成比例的属性,工资 = 销售额*提成
3)manager:固定月薪
4)salasmanager:工资 = 销售额*提成比例*月薪
请完成以下功能:
1)添加所有类型的人员
2)计算月薪
3)显示所有人工资
class Person:
def __init__(self, no, name, salary):
self.no = no
self.name = name
self.salary = salary
def __str__(self):
msg = '工号:{}, 姓名:{}, 本月工资:{}'.format(self.no, self.name, self.salary)
return msg
def getSalary(self):
return self.salary
class Worker(Person):
def __init__(self, no, name, salary, hours, per_hour_money):
super().__init__(no, name, salary)
self.hours = hours
self.per_hour_money = per_hour_money
def getSalary(self):
money = self.hours*self.per_hour_money
self.salary += money
return self.salary
class Salesman(Person):
def __init__(self, no, name, salary, salemoney, percent):
super().__init__(no, name, salary)
self.salemoney = salemoney
self.percent = percent
def getSalary(self):
money = self.salemoney*self.percent
self.salary += money
return self.salary
# 创建对象
worker = Worker('001','king',2000,160,50)
S = worker.getSalary()
print('月薪是:',S)
print(worker)
saler = Salesman('002','lucy',5000,5000000,0.003)
s = saler.getSalary()
print('月薪是:',s)
print(saler)
>>>
月薪是: 10000
工号:001, 姓名:king, 本月工资:10000
月薪是: 20000.0
工号:002, 姓名:lucy, 本月工资:20000.0
有重名的方法,后面的会把前面的覆盖掉:
class Person:
def __init__(self, name):
self.name = name
def eat(self):
print('--------eat1')
def eat(self,food):
print('--------eat',food)
p = Person()
p.eat()
>>>
TypeError: eat() missing 1 required positional argument: 'food'
p = Person('jack')
p.eat('红烧肉')
>>>
--------eat 红烧肉
python 允许多继承:
class A:
def test(self):
print('AAAAAAAAA')
class B:
def test1(self):
print('BBBBBBBBB')
class C(A,B):
def test2(self):
print('CCCCCCCCC')
c = C()
c.test1()
c.test()
>>>
BBBBBBBBB
AAAAAAAAA
多继承的搜索顺序:
class Base:
def test(self):
print('-------Base---------')
class A(Base):
def test(self):
print('AAAAAAAAAAAAAAAAAAAA')
class B(Base):
def test(self):
print('BBBBBBBBBBBBBBBBBBBB')
class C(Base):
def test(self):
print('CCCCCCCCCCCCCCCCCCCC')
class D(A, B, C):
pass
d = D()
d.test()
import inspect
print(inspect.getmro(D))
print(D.__mro__) # 获取搜索顺序方法二
>>>
AAAAAAAAAAAAAAAAAAAA
(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>)
python 允许多继承:
def 子类(父类1,父类2):
pass
父类中有相同的方法时,搜索顺序:从左至右,深度优先
python 类似于多态,但是是依赖于 isinstance 来判断的。
isinstance(obj, 类): 判断obj是不是该类的对象或该类子类的对象
class Person:
def __init__(self,name):
self.name = name
def feed_pet(self, pet):
if isinstance(pet, Pet):
print('{}喜欢养宠物:{},昵称是:{}'.format(self.name,pet.role, pet.nickname))
else:
print('不是宠物,不能养!')
class Pet:
role = 'Pet'
def __init__(self, nickname, age):
self.nickname = nickname
self.age = age
def show(self):
print('昵称:{},年龄:{}'.format(self.nickname, self.age))
class Cat(Pet):
role = 'Cat'
def catch_mouse(self):
print('抓老鼠...')
class Dog(Pet):
role = 'Dog'
def whatch_house(self):
print('看家高手...')
class Tiger:
def eat(self):
print('太可怕了...')
# 创建对象
cat = Cat('huahua', 2)
dog = Dog('dahuang', 4)
tiger = Tiger()
person = Person('nana')
person.feed_pet(cat)
person.feed_pet(tiger)
>>>
nana喜欢养宠物:Cat,昵称是:huahua
不是宠物,不能养!
开发模式:单例模式
单个对象就叫单例模式
class Student:
pass
s = Student()
s1 = Student()
s2 = Student()
上面这种创建对象的模式,会导致每次调用这个类,系统都会给这个对象分配一个空间,多个地址。
单例模式,开发过程中,一个实例就搞定的,不需要每次实例化的时候都开辟一个空间。也就是每次调用这个类的时候,都指向同一个地址,不会占用很多空间。
调用的时候底层的操作:
class Singleton:
# __instance 就是保存变量空间的私有变量
# 私有化
# 保证单例的地址都存在在这里,别人也没法改
__instance = None
# __new__ 是开辟空间的方法,所以要单例化,就要重写这个方法
# 重写父类,把__new__修改了
def __new__(cls):
print('----->instance:', cls.__instance)
if cls.__instance is None:
print('------->1')
cls.__instance = object.__new__(cls)
return cls.__instance
else:
print('------->2')
return cls.__instance
# 调实例化对象,先判断__instance是否为 None,如果为 None,则调用父类的 new 给分配空间,且修改了__instance
s = Singleton()
# 再次实例化对象,__instance 已经不是 None了,所有会走 else 分支
s1 = Singleton()
print(s)
print(s1)
>>>
----->instance: None
------->1
----->instance: <__main__.Singleton object at 0x000001F0F2746390>
------->2
<__main__.Singleton object at 0x000001F0F2746390>
<__main__.Singleton object at 0x000001F0F2746390>