面向对象编程【Python】

一、编程语言的发展:

机器语言 —> 汇编语言 —> 高级语言(面向过程的 C ) —> 面向对象(c++、Java、Python) 越高级,程序员就可以越偷懒

要把大象塞冰箱总共分几步?

二、面向过程:

1.先把冰箱打开;2.把大象塞进去;3.把冰箱关上
定义一个函数来实现功能:def {1.先把冰箱打开;2.把大象塞进去;3.把冰箱关上 }
往后遇到要实现把大象装冰箱这个操作时,直接调用函数就行

三、面向对象:

  • 群体:“妈妈” —— 抽象 —— 类
  • 个体:“李妈妈” —— 具体 —— 对象

对象: 所有你能看到的东西都是对象。对象是具有 属性 和 方法 的实物,(桌子、水杯、电灯、墙…都是对象),

  • 属性:
    是静态的名词性的描述一个东西,比如说:电扇这个对象的属性有 高度、重量、颜色、风力大小、额定电压 等。

  • 方法:
    是指对象的功能和行为,风扇的功能能就是吹风。

四、类:具有相同 “属性” 和 “方法” 的抽象

一个抽象的名词,没有特征,没有特指,模糊的东西,就叫 ,比如说:桌子,你不知道哪一个桌子,不知道什么样的桌子

类是对一系列事物的统称,同类事物必定具有相同的特征

特征分类:

  • 状态(静态化) —— 变量 / 属性(成员变量)
  • 行为(动态化) —— 方法(成员方法)
    统称:类的成员

类的定义:

 # 定义格式一:
class 类名:pass# 定义格式二:
class 类名:成员变量 >>> 静态化的状态 年纪 国籍 身高 体重成员方法 >>> 动态化的行为 函数

1、成员变量:

	# 定义格式一:
class 类名:“”“成员变量 >>> 静态化的状态 ”“”def __init__(self): # 定义成员的变量 固定的语法格式self.变量名1 =1  # 成员变量self.变量名2 = None  # 并不确定该属性具体的值>>> 成员方法 —— 动态化的行为 函数# 调用格式:
取值:对象名.变量名
赋值:对象名.变量名 =# 创建对象
变量名 = 类名() # 对象名
print(变量名.方法)
	# 定义格式二:
对象名.变量名 =# 创建对象出来之后,属于该对象独有的属性/变量# 调用格式
取值:对象名.变量名
赋值:对象名.变量名 =

2、成员方法:

	# 定义格式一:
class 类名:def 方法名(self):方法体# 调用格式
对象名.方法名()

self 仅在声明时占位,无需传递具体参数

	# 定义格式二:
class 类名:def 方法名(self,形参1,形参2,......):方法体# 调用格式一:对象名.方法名(实参1,实参2,......)

怎么表示类呢

class person():  # 类def __init__(self, name, age, sex, heigh):  # 属性写括号里self.name = name  # self 的含义代表即将要出现的面向对象self.age = ageself.sex = sexself.heigh = heighdef say(self):print(self.name, self.age, self.sex, self.heigh, "hello")p = person("name", 18, "男",180)  # 运行 __init__ 方法
p.say()

(1)属性(这个类的一些名词属性):

在这里插入图片描述

上面定义了属性(name、age、sex、height),又定义了方法say(),这样就构成了一个类,但是类是一个抽象的概念,你想让“人说话”,就得把抽象的类实例化具体哪个人说话,那么下面的p就是一个对象,p = person(),但是就这样一个模糊的人,你不知道它具体长啥样,于是需要在括号里填属性:p = person(“name”,18, “男”, 180),这样创建一个人就能具体实实在在知道他是谁,然后就可以运行功能p.say(),我想让他做自我介绍,然后就是在say() 方法里面设置属性:

def say()
print(self.name, self.age, self.sex, self.height, "hello")

所以,创建对象之前,得要有一个类,一个概念性的东西,抽象的类就是一个造汽车的图纸,只有根据图纸造出具体的对象汽车了,才可以使用汽车的一些方法

在这里插入图片描述

__init__    叫:构造函数,构造啥用的呢?构造 对象p 用的。

只要你写一个类名加一个括号,这个构造函数__init__是自动调用的,只要创建了对象,那么类里面的构造方法就会被自动调用,我们也把__init__叫做 魔法方法

然后构造函数下面出现一系列的 self属性,self 的含义代表即将要出现的那个对象p,self 指向的就是p,临时指向新创建的对象(等具体的新对象p来接手)

如下:如果你临时创建的对象没有东西指向它的话,系统会认为它是一个垃圾,所以需要self临时指向一下这一串内存地址,有了一个名字,这时候它就不是垃圾了在这里插入图片描述
但最后还得回到具体的新对象p去指向,因为当你再创建其它新对象了,self就又得去指向新的对象了

整体捋一遍:
在这里插入图片描述
在这里插入图片描述

问:构造函数里有没有return?

init 方法 可以有return,但return必须是 return None,其实返回None, 最终接收的还是 self 对象;
(理论上说应该返回self,这样才能把self的值赋值给P,这样说理论是对的,但是实际上一般在init方法里不写return)
或者说 没有 return,但是构造函数init方法会给返回一个值,返回一个 临时对象self 赋给 新创建的对象p

在这里插入图片描述

(2)方法 —— 这 个 类 所 具 有 的 功 能 :

静态方法:

在这里插入图片描述
如上图,
静态方法是不依赖对象的,通过类,就可以使用这个方法;

say()方法静态方法run() 的存储空间是不一样的,前者say()基于 对象,后者run()基于
所以 run( ) 通过 类 来调用, say( ) 通过 对象 来调用,静态方法 run( ) 也可以通过对象来调,但是得 传对象,

看一下两种方法的内存模型是怎么样的:
在这里插入图片描述
当然,静态方法也可以用对象来调用的:p.run()

如下:
下图 为 对象直接调用静态方法,调用时少了四个参数,
在这里插入图片描述
下图 为 传完对象后 的调用成功:
在这里插入图片描述
所以,
类方法 只能 类 来调用,
静态方法 是 类 和 对象 都可以调用

对象对象 通过类名 后加一个 括号 的形式 来创建,创建后 里面的一个内存模型,怎么赋值的要知道

str 魔术方法的介绍

class man:def __init__(self):self.gender = '男性'self.age = None# 成员方法 定义部分def sing(self,num1):print('唱了%s首歌' % num1)def dance(self,num2):print('跳了%s只舞' % num2)# def __str__(self):# return一个返回值# return '这个类是创建人类的末班'man1 = man()
print(man1)

在这里插入图片描述

class man:def __init__(self):self.gender = '男性'self.age = None# 成员方法 定义部分def sing(self,num1):print('唱了%s首歌' % num1)def dance(self,num2):print('跳了%s只舞' % num2)def __str__(self):# return一个返回值return '这个类是创建人类的末班'man1 = man()
print(man1)

在这里插入图片描述
str魔术方法,特定的时机去进行调用,在使用print函数打印对象的时候,会自动执行代码,也属于魔术方法

	# 定义格式:def __str__(self):return '显示的信息'

五、面向对象的三大特性:

  • 继承
  • 封装
  • 多态

1、继承(涉及到好几个类的关系处理)

优点减少代码量,把一些重复的、共用的代码提出去,但并不是这个共同部分就归谁所有,只是调用共同代码的使用权,

缺点耦合程度太高(比如,下述继承案例中:cat 如果不和 animal 建立联系的话,那么 cat类 就什么用都没有,就是一个废类,那咱们写代码的时候,要尽可能的减低代码类与类之间的耦合程度------> 高内聚、低耦合

  • 构造函数:没有显示和声明时,系统会自动给

  • 子类使用父类属性时,必须手动调用父类构造函数

  • 重写和覆盖:当父类方法不能满足子类的需要时,则在每个子类中都要覆盖,

比如:
猫也要吃,狗也要吃,但猫吃猫粮,狗吃狗粮,它不一样;
如果吃的方法一样,可以继承父类,吃的方法不一样,那就只能覆盖了

# 这是源代码:class cat():def __init__(self,name,weight,age):self.name = nameself.age = ageself.weight = weightdef eat(self):print("吃饭")def run(self):print("跑步")def sleep(self):print("睡觉")class dog():def __init__(self,name,weight,age):self.name = nameself.age = ageself.weight = weightdef eat(self):print("吃饭")def run(self):print("跑步")def sleep(self):print("睡觉")---------------------------------------------------# 这是采用继承后的代码:class animal():def __init__(self, name, weight, age):self.name = nameself.age = ageself.weight = weightdef eat(self):    #下面的吃饭、跑步、睡觉,这三个方法是父类的方法,这些父类的方法想要调用得通过 animal父类 的对象来调用print("吃饭")def run(self):print("跑步")def sleep(self):print("睡觉")class cat(animal):     # cat是子类,animal是父类    
# 构 造 函 数 在 没 有 写 上 显 示 声 明 时 ,系 统 会 默 认 提 供 ----> def __init__ (self):    pass
class dog(animal):passc = cat()
d = dog()
c.sleep()   # 子类对象进行调用父类方法
d.eat()

在这里插入图片描述

小实验:

验证 父类对象到底创没创建 ,如果创建了,那么 print(“这是父类构造函数”) 一定会走

只需要看看父类构造函数能不能运行出来,如果运行出来了,那说明它底层给咱们构造了一个函数,只是咱们没看见

结果,没有走父类

下图所示,父类构造函数没有运行出来,那是怎么调用父类的呢
在这里插入图片描述

怎么创建父类对象呢?

下面把属性打开:
在这里插入图片描述
子类使用父类属性时,必须手动调用父类构造函数
这种 手动调用的方法是绝对没有问题的,括号里写三个参数,属性
在这里插入图片描述
调用父类属性的时候,使用的是父类本身的属性,而不是父类属性的复印版(如下图 id 验证问题:调用的属性是父类本身)
在这里插入图片描述

重写和覆盖:

当父类方法不能满足子类的需要时,则在每个子类中都要覆盖,比如:猫也要吃,狗也要吃,但猫吃猫粮,狗吃狗粮,它不一样;如果吃的方法一样,可以继承父类,吃的方法不一样,那就只能覆盖了

class animal():def __init__(self, name, weight, age):self.name = nameself.age = ageself.weight = weightprint(id(self.name))def eat(self):print("吃饭")def run(self):print("跑步")def sleep(self):print("睡觉")class cat(animal):def __init__(self):super().__init__("小花",2,2) # super() 手动调用父类init方法print("这是子类构造函数")def eat(self):print("猫粮")passc = cat()
c.eat()

在这里插入图片描述

多继承的继承顺序是:

先找本身(子类)—> 再找继承的父类1(亲父类) —> 再找继承的父类2 —> 再找继承的父类3 (若父类没了!---->就找爷爷(父类的父类))===>要是找一圈都没有这个方法,就会报错了!

【二叉树:从左到右,一层一层找,这个叫:广度优先

class father0():def __init__(self):print("这是亲爹")def fun0(self):print("功能1:当大官")class father1():def __init__(self):print("这是干爹1号")def fun1(self):print("功能2:变有钱")class father2():def __init__(self):print("这是干爹2号")def fun2(self):print("功能3:找媳妇")class son(father0,father1,father2):passs =son()
s.fun0()
s.fun1()
s.fun2()

在这里插入图片描述

六、字符串练习

1.字符串解析,现有一字符串,“卡巴斯基#杀毒软件#免费版#俄罗斯#”,解析出每个元素

str = "卡巴斯基#杀毒软件#免费版#俄罗斯#"
str = str[:-1]  # -1表示最后一个元素的下标 || 也可以用:str = str[:len(str)-1]
print(str.split("#")) #考察的方法是 split()

在这里插入图片描述
2.“那车水马龙的人世间,那样地来 那样地去,太匆忙”最后一次出现“那”的位置。

str = "那车水马龙的人世间,那样地来 那样地去,太匆忙"index = str.rfind("那")print(index)

在这里插入图片描述
3.判断输入的字符串是否是.py结束

str = input("请输入一个字符串:")
if str[-3:]==".py":print(True)
else:print(False)

在这里插入图片描述
在这里插入图片描述
4.有一个身份证号码,判断此为男还是女,基于此方法,写一个算法,判断一个身份证号为男还是女。(身份证号分15位和18位)

def is_man(idcard):   if len(idcard)==18:return True if int(idcard[-2])%2 !=0 else False  #身份证号倒数第二位奇数是男性,偶数位女性    if len(idcard)==15:return True if int(idcard[-1])%2 !=0 else False  #身份证号倒数第一位奇数是男性,偶数位女性b = is_man("420984199802048416")
print(b)

在这里插入图片描述
18位身份证,看倒数第二位,为奇是男性
15位身份证,看倒数第一位,为奇是男性

5.有如下格式的字符串name-age-sex-address,解析出姓名,年龄等信息

str = "name-age-sex-address"
print(str.split("-"))

在这里插入图片描述
6.求出字符串中有多少种字符,以及每个字符的个数
static void printCharInfo(String str)
例如有字符串 str=“apple is a apple.”:
结果应该是:

(考察的点在排序,先转列表再排序)
字符串转列表:list = [str[i] for i in s]

s = "apple is a apple."
list = [str(i) for i in s]
list.sort()  # 排完序
print(list)count = 0
a = list[0]for item in list:if item==a:count+=1else:print(a,":",count)count = 1a = item
print(a,":",count)

在这里插入图片描述


七、总结:

1,面向过程 和 面向对象

class  类名():类的体(属性和方法)

2,创建对象

引用(变量) = 类名()
__init__(self)  构造函数

3,方法:类方法 对象方法
4,面向对象的三大特性:继承 封装 多态

class 子类/派生类(父类/超类/基类):
class A(object):def a():passpassclass B():def b():passpassclass C(B)    # C把B继承过来了,C也可以同时有自己的方法class D(A,B,C):   # 多继承,D 把 A、B 、C都继承过来了def b():

从左到右,整体深度优先 局部广度优先(有菱形结构)
覆盖/重写


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部