Python学习(七)---- 面向对象学习(类)

原文地址: https://blog.csdn.net/fgf00/article/details/52449707 编辑:智能算法,欢迎关注!

今天我们继续学习python中类。

1.1 编程范式

编程范式:(一组指令的集合,实现方式) 编程是程序员用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程。一个程序是程序员为了得到一个任务结果而编写的一组指令的集合,正所谓条条大路通罗马,实现一个任务的方式有很多种不同的方式,对这些不同的编程方式的特点进行归纳总结得出来的编程方式类别,即为编程范式。

1.2面向过程编程(Procedural Programming)

面向过程,使用一系列的指令告诉计算机一步一步的做什么。就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题。基本设计思路就是程序一开始是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。

1.3面向对象编程

  • 面向对象介绍

世界万物, 皆可分类。世界万物,皆为对象,只要是对象,就肯定属于某种品类,只要是对象,就肯定有属性。现实生活中就是这个样子的,面向对象就是按照现实生活的这个规则。 面向对象是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。

  • 面向对象特性

Class类: (属性)# 例如:鸟的属性, 类即是对一类相同属性的对象的抽象、蓝图、原形。 Object对象:(实例)# 例如:一个具体的鸟, 一个对象即是一个类实例化后的实例。

三大特性: 封装: 再类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法。比如人的消化系统、心脏、等封装

继承:一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承

多态:是面向对象的重要特性,简单点说:“一个接口,多种实现”,提供统一接口

面向过程编程与面向的主要区别就是面向对象可以使程序更加容易扩展和易更改。

2. 创建类和对象

2.1 创建类和对象

定义类:(object 所有类的父类)

 1class Dog(object):  # 定义一个类, class是定义类的语法,Role是类名,(object)是新式类的写法
 2    n = 123  # 类变量
 3
 4    def __init__(self,name):  # 构造函数--传参数用
 5    # 作用:在实例化时做一些累的初始化的工作。
 6    self.name = name  # 实例变量(静态属性),赋给实例
 7    # 实例变量作用域就是实例本身
 8
 9    def bulk(self)  # 类的方法(动态属性),功能
10        print("%s wang wang!" % self.name)

创建实例(对象):

1# 通过一个类创建一个具体对象的过程叫 实例化
2dog1 = Dog("wangcai")  # 创建实例,并赋值给变量
3# dog1 是对象,又叫Dog这个类的实例
4
5dog1.bulk()  # 调用内部方法

2.2 参数self

初始化一个实例,就需要调用这个类一次:

1dog1 = Dog("wangcai")  # 生成一个实例,会自动把参数传给Dog下面的__init__(...)方法

上面创建dog1对象的时候,并没有给self传值,程序也没未报错,是因为,类在调用它自己的init构造函数时已经帮你给self参数赋值了

1dog1 = Dog("wangcai")  # 此时self 相当于 dog1 ,  dog1 = Dog(dog1, "wangcai")

当执行dog1 = Dog(“wangcai”)时,python的解释器其实干了两件事:

  • 在内存中开辟一块空间指向dog1这个变量名
  • 调用Dog这个类并执行其中的init__(…)方法,相当于Dog.__init(dog1, “wangcai”), 这么做是为什么呢?是为了把”wangcai”这个值跟刚开辟的dog1关联起来,因为关联起来后,你就可以直接dog1.name这样来调用啦。

  所以,为实现这种关联,在调用init__方法时,就必须把dog1这个变量自己也传进去,否则_init_不知道要把那参数跟谁关联呀。 所以这个_init_(…)方法里的,self.name = name等等的意思就是要把这几个值 存到dog1的内存空间里。 把变量dog1也传进去了,再赋值给dog1,这就是self的作用   __init(…)懂了,但后面的那几个函数,噢 不对,后面那几个方法 为什么也还需要self参数么? 不是在初始化实例的时候,就已经把属性跟dog1绑定好了么? 先来看一下上面类中的一个bulk的方法:

1def bulk(self)
2    print("%s wang wang!" % self.name)

上面这个方法通过类调用的话要写成如下:

1dog1 = Dog("wangcai")
2dog1.bulk()  #  #python 会自动帮你转成 dog1.bulk(dog1)

依然没给self传值 ,但Python还是会自动的帮你把dog1 赋值给self这个参数, 为什么呢? 因为,你在bulk(..)方法中可能要访问dog1的一些其它属性呀, 比如这里就访问了dog1的名字,怎么访问呢?你得告诉这个方法呀,于是就把dog1传给了这个self参数,然后在bulk里调用 self.name 就相当于调用dog1.name

总结一下

  • 上面的这个dog1 = Dog(“wangcai”)动作,叫做类的“实例化”, 就是把一个虚拟的抽象的类,通过这个动作,变成了一个具体的对象了, 这个对象就叫做实例
  • 刚才定义的这个类体现了面向对象的第一个基本特性,封装,其实就是使用构造方法将内容封装到某个具体对象中,然后通过对象直接或者self间接获取被封装的内容

2.3 在谁的内存里?(实例化过程)

上面定义了类Dog,并创建了一个实例dog1,那么类变量和实例变量是什么区别和联系? 类变量没实例化就能打印,存在类的内存里。先找实例本身,实例本身没有就去类里找.实例化只拷贝构造函数,不拷贝类变量和其他方法,那些还只在类的内存中。 所以类变量可以存放所有实例一些共同的属性,以节省空间。比如存放用户信息,用户姓名等属性可以放在实例变量里,国籍都是中国,可以放在类变量里。 但是,类变量和类方法方法不在实例中,调用怎么调用呢?

1dog1.bulk()  # 实际是 :Dog.bulk(dog1)
2
3>>> dog1 = Dog('wangcai')
4>>> dog1.bulk()
5wangcai wang wang
6>>> Dog.bulk(dog1)
7wangcai wang wang

所以类里每个函数都必须至少有个self方法

2.4 实例属性的增删改

1dog1.age = 3   # 增加属性
2del dog1.name  # 删除属性
3
4dog1.n = "111"
5# 改类变量,实际不是改类变量,而是在实例里添加一个属性
6
7Dog.n ="ccc"  #改变类变量

2.5 析构函数、私有属性和私有方法

析构函数:跟构造函数相反。在实例释放、销毁的时候执行的,通常用于做一些收尾工作,如关闭一些数据库连接、打开的临时文件。如在上面的Dog类中添加一个析构函数

1def __del__(self):
2    print("%s 挂了" %self.name)

类的私有属性和私有方法: 现在类的私有属性和私有方法,外边可以直接调用,比如Dog.n。如果不想被调用,在前面加两个下划线,就变成了私有属性或私有方法

3. 面向对象的特性

3.1 封装

前面提到:封装,就是使用构造方法将内容封装到某个具体对象中,然后通过对象直接或者self间接获取被封装的内容封装是面向对象的特征之一,是对象和类概念的主要特性。 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

3.2 继承

作用:省代码 面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。 继承的过程,就是从一般到特殊的过程。 要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。 示例:

 1# class SchoolMember: 经典类写法
 2class SchoolMember(object):  # 新式类
 3    def __init__(self,name,age,sex):
 4        self.name = name
 5        self.age = age
 6        self.sex = sex
 7    def tell(self):
 8        pass
 9    def __del__(self):
10        '''析构方法'''
11        print("\033[31;1mmember [%s] left the school\033[0m" %self.name)
12
13class Teacher(SchoolMember):  # 继承父类SchoolMember
14    def __init__(self,name,age,sex,salary,course):
15        # 如何继承父类的构造函数?直接定义则重构了父类的构造函数
16        # 继承父类的构造函数,如下两种写法:
17        # SchoolMember.__init__(self,name,age,sex)  # 经典类写法
18        super(Teacher,self).__init__(name,age,sex)  # 新式类写法
19        self.salary = salary
20        self.course = course
21
22    def tell(self):
23        print('''
24        ---- info of Teacher:%s ----
25        Name:%s
26        Age:%s
27        Sex:%s
28        Salary:%s
29        Course:%s
30        '''%(self.name,self.name,self.age,self.sex,self.salary,self.course))
31
32    def teach(self):
33        print("%s is teaching course [%s]" %(self.name,self.course))
34
35class Student(SchoolMember):
36    def __init__(self,name,age,sex,stu_id,grade):
37        super(Student,self).__init__(name,age,sex)
38        self.stu_id = stu_id
39        self.grade = grade
40
41    def tell(self):
42        print('''
43        ---- info of Student:%s ----
44        Name:%s
45        Age:%s
46        Sex:%s
47        Stu_id:%s
48        Grade:%s
49        ''' % (self.name, self.name, self.age, self.sex, self.stu_id, self.grade))
50
51    def pay_tuition(self,amount):
52        print("%s has paid tution for $%s"% (self.name,amount) )
  • 多继承

上面提到了经典类和新式类: 经典类写法:

1class 类名:  # 定义类
2父类名.__init__(self,*args)  # 继承父类构造函数

新式类写法:

1class 类名(object):  #  定义类
2super(类名,self).__init__(name,*args)  # 继承父类

经典类和新式类区别主要体现在多继承上顺序问题,现在规范写法用新式类

  • 继承顺序

在python2和3版本中测试以下代码,分别注释不同类中的构造函数,查看D的实例继承谁的构造函数

 1class A:
 2    def __init__(self):
 3        print("A")
 4class B(A):
 5    # pass
 6    def __init__(self):
 7        print("B")
 8class C(A):
 9    # pass
10    def __init__(self):
11        print("C")
12class D(B,C):
13    # pass
14    def __init__(self):
15        print("D")
16
17obj = D()
1     A          # 父类
2   /   \
3  /     \
4B         C     # B类和C类继承A
5  \     /
6   \   /
7     D          # D多继承B、C

继承查找策略:   广度优先:D->B->C->A(横向先都查完)   继承顺序从左到右,找到构造函数就停下来,注意方法只是定义在内存中   深度优先:D->B->A, D->C->A python 3: 都是统一广度优先 python 2: 经典类是按深度优先继承,新式类是按广度优先继承的 深度没有广度效率高 多继承示例:

 1class People(object):  # 新式类
 2    def __init__(self,name,age):
 3        self.name = name
 4        self.age = age
 5        self.friends = []
 6    def eat(self):
 7        print("%s is eating..." % self.name)
 8    def talk(self):
 9        print("%s is talking..." % self.name)
10    def sleep(self):
11        print("%s is sleeping..." % self.name)
12
13class Relation(object):
14    # def __init__(self,n1,n2):
15    #     print("init in relation")
16    def make_friends(self,obj): #w1
17        print("%s is making friends with %s" % (self.name,obj.name))
18        self.friends.append(obj.name)
19class Man(Relation,People):
20    def __init__(self,name,age,money=10):
21        # People.__init__(self,name,age)
22        super(Man,self).__init__(name,age)  # 新式类写法
23        self.money  = money
24        print("%s 一出生就有%s $" %(self.name,self.money))
25    def sleep(self):
26        People.sleep(self)
27        print("man is sleeping ")
28class Woman(People,Relation):
29    def get_birth(self):
30        print("%s is born a baby...." % self.name)
31
32m1 = Man("XiaoMing",22)
33w1 = Woman("XiaoHong",20)
34
35m1.make_friends(w1)
  • 组合

另外一种继承方式,严格意义上说不叫继承

1class Teacher(SchoolMember):
2    def __init__(self,name,age,sex,sourse, school_obj):
3        super(Teacher,self).__init__(name,age,sex)
4        # SchoolMember.__init__(self,name,age,sex)
5        self.school = school_obj  # 组合方式,“继承”
6        self.course = course

3.3 多态

一种接口,多种形态。比如打印每类动物的叫声,每次都调用不同的类名,不仅麻烦,而且要记住不同的类名,因此:

 1class Animal:
 2    def __init__(self, name):  # Constructor of the class
 3        self.name = name
 4
 5    def talk(self):  # Abstract method, defined by convention only
 6        pass #raise NotImplementedError("Subclass must implement abstract method")
 7
 8    @staticmethod
 9    def animal_talk(obj):
10        obj.talk()
11
12class Cat(Animal):
13    def talk(self):
14        print('%s Meow!'%self.name)
15
16
17class Dog(Animal):
18    def talk(self):
19        print('%s Woof! Woof!'%self.name)
20
21
22d = Dog("GreyHound")
23#d.talk()
24
25c = Cat("Ocelot")
26#c.talk()
27
28# def animal_talk(obj):
29#     obj.talk()
30
31Animal.animal_talk(c)
32Animal.animal_talk(d)

声明:本文系网络转载,版权归原作者所有。如涉及版权,请联系删除!

本文分享自微信公众号 - 智能算法(AI_Algorithm)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-08-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏儿童编程

一张图理清《梅花易数》梗概

学《易经》的目的不一定是为了卜卦,但是了解卜卦绝对能够让你更好地了解易学。今天用一张思维导图对《梅花易数》的主要内容进行概括,希望能够给学友们提供帮助。

31640
来自专栏web前端教室

你可以从面试中学到什么?

讲一下我对面试的一些。。。“偏见”,哈哈,熟悉我的同学们一定要批判的读接下来的内容哈。

12100
来自专栏FSociety

SQL中GROUP BY用法示例

GROUP BY我们可以先从字面上来理解,GROUP表示分组,BY后面写字段名,就表示根据哪个字段进行分组,如果有用Excel比较多的话,GROUP BY比较类...

5.1K20
来自专栏腾讯NEXT学位

今天我就说三句话

11520
来自专栏华章科技

穿越十年后看互联网+:家电行业的金矿在哪里?

现在市场上炒得火热的智能家居未来出路在何方?做智能家居的创业者应该注意哪些机会?传统家电厂商又到底如何借助互联网进行转型?本文以智能空调为例,用故事的形式,提前...

8310
来自专栏haifeiWu与他朋友们的专栏

复杂业务下向Mysql导入30万条数据代码优化的踩坑记录

从毕业到现在第一次接触到超过30万条数据导入MySQL的场景(有点low),就是在顺丰公司接入我司EMM产品时需要将AD中的员工数据导入MySQL中,因此楼主负...

28340
来自专栏非著名程序员

这是对付产品经理的一副毒药,程序员慎入

程序员和产品经理的日常就像是一对天生的冤家,为了需求的实现,几乎天天在争吵。这不,就在昨天各大技术和产品群里一个程序员暴打产品经理的视频火了,被广泛传播。

12320
来自专栏Ken的杂谈

【系统设置】CentOS 修改机器名

17830
来自专栏儿童编程

我不是算命先生,却对占卜有了疑惑——如何论证“占卜前提”的正确与否

事出有因,我对《周易》感兴趣了很多年。只是觉得特别有趣,断断续续学习了一些皮毛。这几天又偶然接触到了《梅花易数》,觉得很是精彩,将五行八卦天干地支都串联了起来。...

14810
来自专栏非著名程序员

「我真的没有改需求」

11910

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励