热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

小白学习之路,初识面向对象

一,编程范式所谓编程范式(programmingparadigm),指的是计算机编程的基本风格或典范模式。怎么说呢,每个人都有自己不同的习惯,当然编程也是一样的,每个程序组员根据自

一,编程范式

所谓编程范式(programming paradigm),指的是计算机编程的基本风格或典范模式。怎么说呢,每个人都有自己不同的习惯,当然编程也是一样的,每个程序组员根据自己不同的习惯会写出不同的代码。当然这样肯定是不行的啦,这样的可读性不强,而且太乱了,所以慢慢慢慢的大家就统一编程的风格。编程范式里面呢又包括下面几种(我知道的):面向对象,面向过程,函数式编程。感觉写到这里,需要用一波我自己的土话来跟大家解释一下这三种的大概不同了。

面向对象:在python里面一切皆对象,当然不是你女(男)朋友那个对象。emmm,打个比方吧,假如你高考完了,准备选学校,选专业了,你在想到底是去北大呢,还是去清华呢。你就想可以写个函数,如果选清华有哪些专业,选北大有哪些专业。当然还可以这样写,你可以把清华看成一个对象,北大看成一个对象,然后里面的对象有不同的属性跟方法。你选择了清华,就是实例化了一个清华对象,下一个人选择北大,就实例化一个北大对象。这样看似没得多大区别,但是他能够在里面的属性跟方法添加其他的,可扩展性更强了,而且容易修改,这种思想其实就是面向对象。

面向过程:面向过程就太好理解了。因为我们这种小白,最熟悉的就是面向过程。面向过程呢,就是一步一步实现,然后到最后完成。面向过程就是重要的是过程,但是在使用面向过程时,你想改其中一个地方,你会发现很多地方都要改,一个地方错了,其他地方也错了,所以很麻烦。

函数式编程:其实,我觉得跟面向过程差不多,然后是用函数实现的一种编程方式。

二,面向对象简介

1,认识面向对象

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 实例变量:定义在方法中的变量,只作用于当前实例的类。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

2,面向对象特性

面向对象有三大特性:封装,继承,多态

封装:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

继承:继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。在这里值得提一下的就是,python支持多继承,之后多继承后面也会提到。通俗来讲,继承就是你继承其他的类,他的属性方法,你都有,而且还可以继续增加或者修改一些属性或者方法。

多态:多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。

三,面向对象基础语法

听了这么多的类啊,对象啊,现在就来新建一个类吧。在新建之前,类还分经典类和新式类。

经典类:

技术分享图片技术分享图片
 1 import time
 2 class people:#(class后面的是类名)
 3     #构造函数,在实例化一个对象的时候生成的一些属性写在这里
 4     def __init__(self,name):
 5         self.name=name
 6     def eat(self):
 7         print(%s is eating...%self.name)
 8     def sleep(self,times):
 9         print(%s Is sleeping%self.name)
10         time.sleep(times)
11         print(%s sleep up %self.name)
12 a=people(zzq) #实例化一个对象
13 a.eat() #调用里面的方法
14 a.sleep(1)#调用需要传参的方法
View Code

新式类:(继承了object)

技术分享图片技术分享图片
 1 import time
 2 class people(object):#(class后面的是类名)
 3     #构造函数,在实例化一个对象的时候生成的一些属性写在这里
 4     def __init__(self,name):
 5         self.name=name
 6     def eat(self):
 7         print(%s is eating...%self.name)
 8     def sleep(self,times):
 9         print(%s Is sleeping%self.name)
10         time.sleep(times)
11         print(%s sleep up %self.name)
12 a=people(zzq) #实例化一个对象
13 a.eat() #调用里面的方法
14 a.sleep(1)#调用需要传参的方法
View Code

他们之间的区别在讲了后面的继承跟多继承会讲到,其实在python3中没得区别,一般常用新式类的写法哦。

四,类的继承

面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。

通过继承创建的新类称为子类派生类,被继承的类称为基类父类超类

在python中继承中的一些特点:

  • 1、如果在子类中需要父类的构造方法就需要显示的调用父类的构造方法,或者不重写父类的构造方法。详细说明可查看:python 子类继承父类构造函数说明。
  • 2、在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数
  • 3、Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

1,下面简单介绍一下,继承的一些基本语句

技术分享图片技术分享图片
 1 class Father(object):
 2     def __init__(self,name):
 3         self.name=name
 4     def get_name(self):
 5         print(Father’s name is %s %self.name)
 6     def say(self):
 7         print(Father is say)
 8 class Son(Father):#继承Father类
 9     def __init__(self,name,age):
10         Father.__init__(self,name)#继承父类的构造方法
11         self.age=age
12     def get_name(self):
13         Father.get_name(self)#继承父类的方法
14         print(Son’s name is %s age is %s%(self.name,self.age))
15     def say(self):
16         print(Son is say)#重写say方法
17 a=Son(xxx,18)
18 a.get_name()
19 a.say()
View Code

执行结果:

技术分享图片

在上面的构造方法的继承其实还有一种比较常用的,也是推荐使用的方法,代码如下

1     def __init__(self,name,age):
2         # Father.__init__(self,name)#继承父类的构造方法
3         super(Son, self).__init__(name)#继承父类的构造方法,并且不用知道父类的名字
4         self.age=age

总结一下吧。如果不重构的情况下,默认,子类有父类所有的方法并且跟父类相同。子类还可以继承父类的构造方法或者其他方法,并且在上面添加扩展。如果父类跟子类的方法或者属性重名,那么使用的还是子类的属性或方法。

2,多继承的用法跟分析

在讲到多继承这里大家就要知道在继承的时候需要考虑继承的顺序问题。讲这么多不好理解,我们先看代码,然后在分析吧。

技术分享图片技术分享图片
 1 class F1(object):
 2     def say1(self):
 3         print(this is F1 say1)
 4     def say2(self):
 5         print(this is F1 say2)
 6 class F2(object):
 7     def say1(self):
 8         print(this is F2 say1)
 9     def say2(self):
10         print(this is F2 say2)
11     def say3(self):
12         print(this is F2 say3)
13 class Son(F1,F2):#继承F1,F2两个类
14     pass
15 a=Son()
16 a.say1()
17 a.say2()
18 a.say3()
View Code

执行结果:

1 this is F1 say1
2 this is F1 say2
3 this is F2 say3

通过结果我们可以看到,如果同时继承了两个类,会首先去前面一个类里面找有木有方法或者属性,如果有,就用前面那个类的属性或方法,如果前面没有就用后面的那个类的属性或方法。

讲到这里跟大家讲一下经典类跟新式类的区别吧。但是在讲区别之前,需要带大家了解一下什么叫广度优先跟深度优先。

广度优先:从初始点出发,把所有可能的路径都走一遍,如果里面没有目标位置,则尝试把所有两步能够到的位置都走一遍,看有没有目标位置;如果还不行,则尝试所有三步可以到的位置。这种方法,一定可以找到一条最短路径,但需要记忆的内容实在很多,要量力而行。

深度优先:从初始点出发,不断向前走,如果碰到死路了,就往回走一步,尝试另一条路,直到发现了目标位置。这种不撞南墙不回头的方法,即使成功也不一定找到一条好路,但好处是需要记住的位置比较少。

python2经典类是按照深度优先来继承类的,新式类是按照广度优先来继承类的。

python3经典类和新式类都是统一按照广度优先来继承类的。

当然,有的人还是不能完全理解继承流程,下面是我画的流程图,当然,丑不能怪我!!!

技术分享图片

这个顺序是在继承的时候查找属性和方法的向上查找顺序。

五,类属性,方法扩展

想了一下,属性好像有实例变量,类变量,私有变量等。方法有构造方法,析构函数,私有方法,静态方法,类方法,属性方法等。

1,私有变量,私有方法

私有属性跟私有方法,其实就是只能在类里面能够使用的属性跟方法,外部不能调用使用。

1 class tset(object):
2     def __init__(self,name):
3         self.__name=name   #变为私有属性,只有内部能够调用
4     def __say(self):   #变为私有方法,只有内部能够调用
5         print(self.__name)  #调用私有属性
6     def say(self):
7         self.__say()  #调用私有方法

2,静态方法

普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法。

1 class Test(object):
2     def __init__(self, name):
3         self.name = name
4     @staticmethod  # 把say方法变为静态方法
5     def say():#不能传入其他参数
6         print("hello")
7 d = Test("xxx")
8 d.say()

3,类方法

类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量

1 class Test(object):
2     name=zzq #类变量
3     def __init__(self, age):
4         self.age = age
5     @classmethod  # 把say方法变为类方法
6     def say(self):
7         print("hello %s" %self.name)#只能调用类变量
8 d = Test("xxx")
9 d.say()

4,属性方法

属性方法的作用就是通过@property把一个方法变成一个静态属性

1 class Test(object):
2     def __init__(self, name):
3         self.name = name
4     @property  # 把say方法变为属性方法
5     def say(self):
6         print("hello %s" %self.name)
7 d = Test("xxx")
8 d.say  #相当于say是一个属性,调用的时候相当于调用一个属性,不用加括号

六,类里面的一些特殊方法

1,__str__

1 def __str__(self):#输出对象时,输出的是return的返回值
2     return hahaha

2,__call__

1 def __call__(self, *args, **kwargs):#在调用后面加一个()执行这个方法
2     print(this is call,args,kwargs)
3 Test("xxx")() #在调用的时候后面再加一个括号

3,__doc__,__module__

1 print(Test.__doc__)#打印类的描述
2 print(Test.__module__)#输出类所在哪个模块

4,__class__

print(Test.__class__)#表示当前操作的对象的类是什么

5,__dict__

1 print(Test.__dict__)#打印类中的所有属性,不包括实例化属性
2 a=Test("xxxx")
3 print(a.__dict__)#打印类中所有实例化属性,不包括类属性

6,__del__

1     def __del__(self):#析构函数,在实例化以后自动调用,比如一些关闭数据库连接等操作
2         print(end)

7,__new__

类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__,所以在实例化__init__之前其实先调用了__new__方法的。

 七,反射

相信在写程序的时候都会遇到一个问题就是你想要把字符串转换成需要执行的属性或者类。需要执行对象里的某个方法,或需要调用对象中的某个变量,但是由于种种原因我们无法确定这个方法或变量是否存在,这是我们需要用一个特殊的方法或机制要访问和操作这个未知的方法或变量,这中机制就称之为反射。

简单来讲,反射就是把字符串转化为可以执行的属性或者方法。

技术分享图片技术分享图片
 1 class Dog(object):
 2     def __init__(self,name):
 3         self.name=name
 4     def eat(self):
 5         print(The dog %s is eating... %self.name)
 6 d=Dog("xxx")
 7 chose=input(">>>>")
 8 print(hasattr(d,chose)) #判断输入的chose在d对象中,是否存在属性或者方法
 9 
10 func=getattr(d,chose) #把字符串转化为可以直接使用的属性或者方法
11 func() #如果是方法,调用方法(执行结果:The dog xxx is eating...)
12 print(func) #如果是属性(执行结果:xxx)
13 
14 setattr(d,age,20)#为d增加属性,第二个为属性名,第三个为属性值
15 print(d.age) #执行结果:20
16 def say(self):
17     print(hello,world)
18 setattr(d,talk,say)#把函数say添加到d中,并且函数名为talk
19 d.talk(d) #调用talk方法,因为这是额外添加的方法,需手动传入对象(执行结果:hello,world)
20 
21 delattr(d,name)#删除d中的name属性,delattr不能删除类中的方法
View Code

当然,一般hasattr跟getattr是一起使用的,先用hasattr判断类或对象中是否存在,然后再用getattr获取。getattr不仅仅可以获取对象的方法和属性和方法,还可以获取类的方法和属性。你还可以这样理解,比如d.name在使用getattr的时候可以理解为getattr(obj,str)obj相当于.前面的,str相当于.后面的。

小白学习之路,初识面向对象


推荐阅读
  • 本文探讨了在使用Selenium进行自动化测试时,由于webdriver对象实例化位置不同而导致浏览器闪退的问题,并提供了详细的代码示例和解决方案。 ... [详细]
  • 本文详细介绍了 org.apache.commons.io.IOCase 类中的 checkCompareTo() 方法,通过多个代码示例展示其在不同场景下的使用方法。 ... [详细]
  • 本文探讨了使用C#在SQL Server和Access数据库中批量插入多条数据的性能差异。通过具体代码示例,详细分析了两种数据库的执行效率,并提供了优化建议。 ... [详细]
  • 反向投影技术主要用于在大型输入图像中定位特定的小型模板图像。通过直方图对比,它能够识别出最匹配的区域或点,从而确定模板图像在输入图像中的位置。 ... [详细]
  • 深入理解Lucene搜索机制
    本文旨在帮助读者全面掌握Lucene搜索的编写步骤、核心API及其应用。通过详细解析Lucene的基本查询和查询解析器的使用方法,结合架构图和代码示例,带领读者深入了解Lucene搜索的工作流程。 ... [详细]
  • 本文详细探讨了JavaScript中的作用域链和闭包机制,解释了它们的工作原理及其在实际编程中的应用。通过具体的代码示例,帮助读者更好地理解和掌握这些概念。 ... [详细]
  • 算法题解析:最短无序连续子数组
    本题探讨如何通过单调栈的方法,找到一个数组中最短的需要排序的连续子数组。通过正向和反向遍历,分别使用单调递增栈和单调递减栈来确定边界索引,从而定位出最小的无序子数组。 ... [详细]
  • 本文介绍如何在 C++ 中使用链表结构存储和管理数据。通过具体示例,展示了静态链表的基本操作,包括节点的创建、链接及遍历。 ... [详细]
  • 本问题探讨了在特定条件下排列儿童队伍的方法数量。题目要求计算满足条件的队伍排列总数,并使用递推算法和大数处理技术来解决这一问题。 ... [详细]
  • 查找最小值的操作是很简单的,只需要从根节点递归的遍历到左子树节点即可。当遍历到节点的左孩子为NULL时,则这个节点就是树的最小值。上面的树中,从根节点20开始,递归遍历左子 ... [详细]
  • 本文介绍如何使用 Android 的 Canvas 和 View 组件创建一个简单的绘图板应用程序,支持触摸绘画和保存图片功能。 ... [详细]
  • 在项目部署后,Node.js 进程可能会遇到不可预见的错误并崩溃。为了及时通知开发人员进行问题排查,我们可以利用 nodemailer 插件来发送邮件提醒。本文将详细介绍如何配置和使用 nodemailer 实现这一功能。 ... [详细]
  • Python 内存管理机制详解
    本文深入探讨了Python的内存管理机制,涵盖了垃圾回收、引用计数和内存池机制。通过具体示例和专业解释,帮助读者理解Python如何高效地管理和释放内存资源。 ... [详细]
  • Appium + Java 自动化测试中处理页面空白区域点击问题
    在进行移动应用自动化测试时,有时会遇到某些页面没有返回按钮,只能通过点击空白区域返回的情况。本文将探讨如何在Appium + Java环境中有效解决此类问题,并提供详细的解决方案。 ... [详细]
  • 利用Selenium与ChromeDriver实现豆瓣网页全屏截图
    本文介绍了一种使用Selenium和ChromeDriver结合Python代码,轻松实现对豆瓣网站进行完整页面截图的方法。该方法不仅简单易行,而且解决了新版Selenium不再支持PhantomJS的问题。 ... [详细]
author-avatar
四海承风2502893247
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有