面向对象第一天
我们现在学习到当前的这个阶段,我们能够实现很多功能了,回想一下我们其实学习了两种编程方式,今天咱们在学习一种编程方式,在开发中只有个这三种开发方式
编程方式:
- 过程式编程
- 函数式编程
- 面向对象式编程
过程式编程 vs 函数式编程
有个s1='aabbbccddeeeffffssss'使用程序统计s1字符串的长度,禁止使用len函数
count = 0
for i in s1:
count += 1
print(count)
这样我们就成功的实现了,现在又出现了一个列表 l1 = [1,2,3,4,5,6,7,8,9,0,01,2132,321,41234],还是同样的需求不能使用len函数来统计长度
count = 0
for i in l1:
count += 1
print(count)
这样也完美的实现了这个需求,但是将两个需求一对比发现只有可迭代对象是不同的,其他的代码都是一样的,就出现了重复代码的情况。看到这个我们瞬间就想到函数式编程,函数式编程就完美的将重复代码的现象解决掉,我们现在用函数式编程来实现一下
def my_count(obj):
count = 0
for i in obj:
count += 1
print(count)
my_count(s1)
my_count(l1)
这样就很好的解决了,过程式编程和函数式编程没有问题后咱们来看看函数式编程和面向对象式编程
函数式编程 vs 面向对象式编程
函数式编程我们一直在用,ATM机是不是就全都是用函数写的,写了一堆函数,还需要人为的进行分类,加注释 才能稍微的清晰一些,如下:
# 这是账户相关的逻辑
def login():
print('这是登录函数')
def register():
print('这是注册函数')
def check_user():
print('这是验证用户名')
def check_password():
print('这是验证密码')
# 这是金钱相关的逻辑
def save():
print('这是存钱的逻辑')
def send_money():
print('这是转账的逻辑')
def show_money():
print('这是查看余额的逻辑')
# 这是购物相关的逻辑
def shopping():
print('这是购物逻辑')
def show_love_goods():
print('这是查看喜欢的商品')
def show_buy_goods():
print('这是查看购买的商品')
这个九个函数我们还是写了注释,不仔细看也不知道都是什么功能,给人直观的感觉就是比较乱,我们先查看一下面向对象式编程,在给大家讲面向对象
class UserInfo:
def login(self):
pass
def register(self):
pass
def show_user(self):
pass
def show_password(self):
pass
class Shopping:
def show_buy_goods(self):
pass
def show_love_goods(self):
pass
class Money:
def save(self):
pass
def send_money(self):
pass
def show_money(self):
pass
面向对象式编程就从代码级别上看比较清晰,容易读. 还将一类相似的功能和属性汇总到一起,帮助咱们做到分类的功能
这其实就是面向对象的优点一:
- 代码可读性强
- 将相似的功能和属性汇总到一起,帮助咱们进行分类
面向对象不止这一个优点,我们先来学习面向对象,优点慢慢进行体会,首先要学习面向对象就要学习什么是类什么是对象
类
什么是类?
汽车就是一个类,汽车是不是可以加油,可以前进,可以后退,可以拐弯,可以坐人,四个*,具有这些就是一个汽车,我说我买了个汽车你们知道买了个什么车吗?,不知道 因为汽车就是一个统称
我说xxx你帮我把手机袋里的手机拿过来,你知道拿那个手机吗?不知道,因为手机就是一个统称
我说我想养只猫,你们知道我想养什么猫吗?不知道 因为猫也是一个统称
到饭点了,你去饭店吃饭,老板问你吃啥,你和老板说饭,你看看老板干不干你,饭是不是也是一个统称啊
以上的汽车,手机,猫,饭都是一种统称.包含范围比较广,不知道具体是什么.
类就是对一些相似的实物的统称,我们认识了什么是类,在来研究一下什么是对象
对象
刚刚我说了我买了个汽车,你们不知道我买的啥汽车,我现在告诉你我买了一个宝马320,这样你们是不是就知道明确知道我买的车是什么了
我刚让xxx从手机袋里把手机拿过来,他是不是也不知道我要那个手机,我现在告诉他,你帮我把那个苹果8后壳是一个狗的,贴着钢化膜的那个手机拿过来,他是不是就知道去拿那个了
我还说我想养只猫,你们也不知道我想养什么猫,我说我想养一只布偶,你们是不是就知道我想养什么猫了
经过上次吃饭让老板给揍了的经验,这次去饭店直接和老板说我要吃土豆丝炒饼,老板就给你去做了
通过我这四个描述,你们能够准确的知道是什么,并且我的说的宝马320,苹果8,布偶,土豆丝炒饼都是具体存在的东西,可以看的见,摸得到的就是对象.
对象就是在类的基础上在进行细化,能够准确定位到个体.实实在在存在的.
我们现在明确的知道了什么是类什么是对象,我们就先来定义一个类
类的定义
定义类其实和定义函数很类似,看如下对比:
def func():
print('这是一个函数')
class Dog():
print('这是一个类')
两个对比之后发现,关键字不同,定义类是class 函数的名字和类的名字有点区别,是的没错 类名需要使用大驼峰,两个或多个单词以上不建议使用下划线相连
类是由两部分组成:
- 类变量(静态属性,静态字段)
- 类方法(动态属性,方法)
上边说到了类变量和类方法,我们来定义一个完整的类
class Pepole:
main = '有思想' #类变量 静态属性 静态字段
def work(self): #类方法 动态属性 函数
print('正在工作')
def eat(self):
print(在吃东西')
我们来观察我们写的这个类,这个类就是一个人类,我写的类变量就是所有人都具有的,我写的类方法就是人类都具有的功能,也就是说人会做的事情.好了 你告诉我你是什么,你说你是人 ok你怎么证明? 你只要有思想会工作你就是人,我们可以根据自己的特点去总结类.你们刚开始接触面向对象不会定义类很正常,我现在先教你一个方法
简单定义类
我:小黄你叫什么啊?
小黄:王富贵
我:小黄你多大了?
小黄:20
我:小黄你是男的还是女的?
小黄:男
我:小黄你能干啥?
小黄:我能吃饭,睡觉,说话,工作
我:小白你叫什么啊?
小白:王老二
我:小白你多大了?
小白:25
我:小白你是男的还是女的?
小白:男的
我:小白你能干啥?
小白:我能吃饭,睡觉,说话,工作
通过于小黄,小白得到的信息,我们将这些信息用代码描述出来
# 小黄
name = '王富贵'
age = 20
sex = '男'
def eat():
print('这是吃饭')
def sleep():
print('这是睡觉')
def talk():
print('这是说话')
def work():
print('这是工作')
# 小白
name = '王老二'
age = 25
sex = '男'
def eat():
print('这是吃饭')
def sleep():
print('这是睡觉')
def talk():
print('这是说话')
def work():
print('这是工作')
发现小黄和小白只有名字和年龄不一样其他好像都是一样的,我们将一样的东西用类包一下
class People:
def eat(self):
pass
def sleep(self):
pass
def talk(self):
pass
def work(self):
pass
我们将他们两共同的功能放到一个类中,名字和年龄是小黄和小白的特征也是区分的地方咱们稍后在说,先说他们都有的功能,现在把他们共同的功能写到一个类中,我们先来分析一下 代码运行都干了什么
定义类发生的事情
通过上图可以看出,在定义类的时候在内存中会开辟一个类空间,类空间中存放多个功能的空间
我们已经推测他会开辟空间,那我们就来查看一下我们推测的到底对不对
print(People.__dict__) #类名.__dict__就是查看类空间的内容
结果:
{'__module__': '__main__', 'eat': <function People.eat at 0x0000025B3F158840>, 'sleep': <function People.sleep at 0x0000025B3F1588C8>, 'talk': <function People.talk at 0x0000025B3F158950>, 'work': <function People.work at 0x0000025B3F1589D8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
通过结果的长相,估计是一个字典,我们来试一试字典访问行不行,搞起
print('这是吃=====>',People.__dict__['eat'])
结果:
这是吃=====> <function People.eat at 0x0000023548A38840>
果然,咱们的猜测是准确的,既然可以查看 不妨试一试修改
People.__dict__['eat'] = '东坡肘子'
结果:
Traceback (most recent call last):
File "D:/Python_project/class_obj/test.py", line 264, in <module>
People.__dict__['eat'] = '东坡肘子'
TypeError: 'mappingproxy' object does not support item assignment
哎呀,报错了,看来是不支持这样的操作啊,怎么搞.莫慌有我在 在面向对象对象中有个万能的点(.)
万能的点
看看这个点(.)能干啥
# 查
print(People.__dict__)
print(People.eat)
结果:
{'__module__': '__main__', 'eat': <function People.eat at 0x0000017343628840>, 'sleep': <function People.sleep at 0x00000173436288C8>, 'talk': <function People.talk at 0x0000017343628950>, 'work': <function People.work at 0x00000173436289D8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
<function People.eat at 0x0000017343628840>
字典里的eat后边的内容和咱们用点eat的到结果是一毛一样的,说明可以进行查询
#改
People.eat = '东坡肘子'
print(People.__dict__)
结果:
{'__module__': '__main__', 'eat': '东坡肘子', 'sleep': <function People.sleep at 0x000002097F3988C8>, 'talk': <function People.talk at 0x000002097F398950>, 'work': <function People.work at 0x000002097F3989D8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
字典里eat后边的内容已经改成了东坡肘子了,改也没有问题
#删
del People.eat
print(People.__dict__)
结果:
{'__module__': '__main__', 'sleep': <function People.sleep at 0x00000243447F88C8>, 'talk': <function People.talk at 0x00000243447F8950>, 'work': <function People.work at 0x00000243447F89D8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
eat不在这个字典中了,说明删除成功了
#增
People.a = 'alex'
print(People.__dict__)
结果:
{'__module__': '__main__', 'eat': <function People.eat at 0x000001F808B88840>, 'sleep': <function People.sleep at 0x000001F808B888C8>, 'talk': <function People.talk at 0x000001F808B88950>, 'work': <function People.work at 0x000001F808B889D8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None, 'a': 'alex'}
字典中多了一个a:alex,说明增加成功了,这里和大家说一下咱们这些增加,修改,删除,是在类空间有变化,不要觉得代码会有变动,代码是不会有变动.只是在类的空间中有变化.还有其实点的操作我们一点都不陌生,我们在第三天的时候就一直在用,想想字符串的那些方法是不是都是.upper什么的啊.列表中.append什么的.
我们说了万能的点(.)我们试试通过点去调用一下eat函数
class People:
def eat(self):
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
print(People.eat)
结果:
<function People.eat at 0x0000011A5B478840> #这是一个函数的内存地址,函数内存地址加括号就是调用
People.eat() #你们猜运行结果是什么??
结果:
Traceback (most recent call last):
File "D:/Python_project/class_obj/test.py", line 276, in <module>
print(People.eat())
TypeError: eat() missing 1 required positional argument: 'self'
报错了,不知和你想的是否一样,肯定有人在想为什么会报错呢?回想一想在类中咱们写的eat函数括号里有个self,别管他叫啥
想一想在函数的定义时括号里有个参数是不是就是形参,一直在等待咱们给他传一个东西啊,我们给他传一个参数试一试
class People:
def eat(self):
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
People.eat(111)
结果:
这是吃饭
这样调用的方式比较麻烦,并且不建议使用类名去调用,(类方法,静态方法)除外,那不让用类名去调用那怎么去调用呢?
我们对比函数来执行一下,函数加括号就是在调用,类名加括号是干啥
class People:
def eat(self):
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People()
print(p1)
结果:
<__main__.People object at 0x000001EE11099E48> #发现是一个People 的object 也就是People的对象
获取的是一个内存地址,我们来一下People加括号在内存级别发生了什么
第六步的时候就在内存中创建一个新的空间,这个空间是对象,并且将对象的空间赋值给p1,也叫做实例化
p1这对象就是People的类创建出来的,我们尝试着用p1访问以下类中eat函数
class People:
def eat(self):
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People()
p1.eat() #运行结果是什么??
结果:
这是吃饭
为什么没有报错??刚刚类名调用eat函数就报错了.还记得我说不推荐使用类名执行吧,是因为Python中函数正常写的函数都是默认给对象使用的,咱们明明没有给eat函数传参怎么就调用成功了呢? 是因为python自动帮我传递过去了.我们来查看一下self是个啥东西
class People:
def eat(self):
print('is self ====>',self)
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People()
p1.eat()
结果:
is self ====> <__main__.People object at 0x0000017F92449E80>
这是吃饭
这个看着好眼熟啊,想起来了这不就是类名加括号得到的东西吗?来验证一下是不是一样
class People:
def eat(self):
print('is self ====>',self)
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People()
print(p1)
p1.eat()
结果:
<__main__.People object at 0x0000015302439E80>
is self ====> <__main__.People object at 0x0000015302439E80>
这是吃饭
没跑了,就是它.通过这个测试咱们是不是就知道在使用p1对象调用类中的eat方法默认就会将p1传递给self.这地方我问大家一个问题,也是面试题,self能更改吗?
class People:
def eat(x):
print('is self ====>',x)
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People()
print(p1)
p1.eat()
结果:
<__main__.People object at 0x000001606C1A9E80>
is self ====> <__main__.People object at 0x000001606C1A9E80>
这是吃饭
没有报错,能够正常运行就证明是可以更换的,听好了什么args,kwargs,self都是可以更换的但是不建议更换,写这种的显得专业.
咱们现在把人类共同的都写好了,人和人之间还有不同的地方吧,比如alex浑身屌丝气息,太白反光的光头,宝元的帅气等等这些东西怎么搞?这些是不是就是每个人的特征啊,看到光头就想到了太白,看到了帅哥就想起了宝元.这些特征是不是应该让每个自己携带着,ok那回到程序中p1是不是就是一个人,我们要把这个人的特征写到它的空间里,我们试一试点操作
class People:
def eat(x):
print('is self ====>',x)
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People()
p1.name = 'alex'
print(p1.name)
设置成功了,咱们把设置放到类中
class People:
def info(self):
self.name = 'alex'
def eat(x):
print('is self ====>',x)
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People()
p1.info()
这样就给p1对象设置一个了名字叫做alex,但是不管谁来都是alex了,要是能够自动换人就好了.机智的铁子们说用参数啊,是啊,盘它
class People:
def info(self,name):
self.name = name
print(self.name)
def eat(x):
print('is self ====>',x)
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People()
p1.info('alex') #这样alex来了就是alex wusir来了就是wusir
这样就搞定了,你们学Python的时候是不是告诉你们Python简单,咱们来看看Pyhton的简单之处
class People:
def __init__(self):
print(123)
def eat(x):
print('is self ====>',x)
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People()
结果:
123
咱们也没有调用__init__这个函数啊,怎么里边的123就打印了呢,这个是Python帮咱做的,在类名加括号的时候就触发了__init__ 这个函数,我们以后就在这个函数给对象设置它特殊的属性,__init__这个方法叫做初始化方法,就是给对象设置属性的.怎么设置呢,继续向下看
class People:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def eat(x):
print('is self ====>',x)
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People('alex',78,'不明') # 因为在执行类名()的时候触发__init__方法,我们只需要把__init__需要的参数放到括号里就可以了
print(p1.__dict__) #查看对象的空间也可以使用__dict__
结果:
{'name': 'alex', 'age': 78, 'sex': '不明'}
现在能够p1设置特殊的属性,我们试一试在创建一个p2(实例化一个p2)
class People:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def eat(x):
print('is self ====>',x)
print('这是吃饭')
def sleep(self):
print('这是睡觉')
def talk(self):
print('这是说话')
def work(self):
print('这是工作')
p1 = People('alex',78,'不明') # 因为在执行类名()的时候触发__init__方法,我们只需要把__init__需要的参数放到括号里就可以了
p2 = People('wusir',69,'男')
print(p1.__dict__) #查看对象的空间也可以使用__dict__
print(p2.__dict__)
结果:
{'name': 'alex', 'age': 78, 'sex': '不明'}
{'name': 'wusir', 'age': 69, 'sex': '男'}
我们通过结果发现,实例化一个对象就开辟一个空间,这个空间就单独存放着这个人的特征.
总结:
- 类就是一些相似事物的统称,范围比较广
- 对象就是具体的实物,范围比较小.能够准确定位到某些东西
- 定义类 使用
class
关键字 类名使用大驼峰 - 类名+() 是在实例化对象
- 查看类空间和对象空间使用.__dict__
- 类和对象通过.可以进行增删改查
- 除去(类方法,静态方法) 建议使用对象调用类中的方法,因为Python帮我们自动把对象当最第一个参数传递给self
- self 是可以进行更改,但是不建议更改(面试可能会问)
- 一个类可以有多个对象,但是对象的空间是独立的