17.python面向对象
Posted 大道至简
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了17.python面向对象相关的知识,希望对你有一定的参考价值。
面向对象的编程(object oriented programming),简称OOP:是一种编程的思想。OOP把对象当成一个程序的基本单元,一个对象包含了数据和操作数据的函数。面向对象的出现极大的提高了编程的效率,使其编程的重用性增高。
模拟场景理解面向对象和面向过程:
1 ‘‘‘ 2 使用面向过程的思想解决吃饭的问题? 3 步骤: 4 1).思考今天吃什么? 5 2).去买菜(货比三家) 6 3).摘菜 7 4).洗菜 8 5).切菜 9 6).炒菜 10 7).焖饭 11 8).吃饭 12 9).洗刷 13 使用面向对象的思想解决吃饭的问题? 14 步骤: 15 1).思考今天吃什么? 16 2).去饭店 17 ①.调用服务员的点菜功能 18 ②.将菜品告知后台大厨 19 ③.大厨调用服务员的上菜功能 20 3).开始吃饭 21 4).结账走人(多种支付方式) 22 ‘‘‘
Python是解释性语言,但是它是面向对象的,能够进行对象编程。面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用;类 是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中);对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数。大白话理解类和对象的区别:i类:具有一些列相同特征、行为的"事物",它的表现是不具体的、不清晰的、模糊的概念;对象:从类中实例化得到,一个实实在在的个体,在内存中有体现;它的表现是具体的、清晰的、看得见摸的着的。
遇到面向对象的问题,通常可以考虑如下三个环节:
1). 设计类,定义属性、函数、...(可能需要花费大量的时间) ;
2). 创建(实例化)对象(简单,一行代码搞定,但是内存比较复杂);
3). 对象调用属性或者函数完成需求。
1 # 1.设计类 2 class Car(object): 3 4 # 属性 5 color = "红色" 6 brand = "BMW" 7 number = "沪A88888" 8 9 # 函数/方法 10 def run(self): 11 print(‘%s的%s,车牌为%s,正在飞速的行驶...‘ %(self.color,self.brand,self.number)) 12 13 def stop(self): 14 print(‘车停了...‘) 15 16 # 2.创建对象/实例化对象 17 c1 = Car() 18 print(c1,type(c1)) # 得到<__main__.Car object at 0x000000000220D710> <class ‘__main__.Car‘> 19 20 # 3.对象调用属性 21 print(c1.color,c1.brand,c1.number) # 红色 BMW 沪A88888 22 23 # 4.对象调用函数 24 c1.run() # 红色的BMW,车牌为沪A88888,正在飞速的行驶... 25 c1.stop() # 车停了... 26 27 # 创建第二个对象 28 c2 = Car() 29 print(c2,type(c2)) # 得到<__main__.Car object at 0x000000000272D7B8> <class ‘__main__.Car‘> 30 31 print(c1 == c2) # 得到False ,比较的是地址,c1和c2的地址不一样 32 33 c2.color = "白色" 34 c2.brand = "BYD" 35 c2.number = "京A66666" 36 print(c2.color,c2.brand,c2.number) # 白色 BYD 京A66666 37 print(c1.color,c1.brand,c1.number) # 红色 BMW 沪A88888 38 ‘‘‘在一个模块中可以创建多个对象,它们彼此之间是相互独立存在(堆空间有体现),切互不干扰...‘‘‘ 39 40 c3 = c1 # c1和c3的地址是一样的,共用,c1不调用了,但c3还指在堆上,c1记录的地址又给到c3一份 41 c1 = None 42 ‘‘‘此时堆中有1个空间,不存在垃圾空间;因为c1虽然被赋值为None了,但是c3仍然记录了堆中对象空间的地址(维护这层关系)‘‘‘
类的成员:
1). 字段:普通字段、静态字段
普通字段需要通过对象来访问,而静态字段通过类访问,在使用上可以看出普通字段和静态字段的归属是不同的;他们的本质的区别是内存中保存的位置不同,普通字段属于对象,而静态字段属于类;静态字段在内存中只保存一份,普通字段在每个对象中都要保存一份;通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段。
1 class Province: 2 3 # 静态字段/类属性 4 country = ‘中国‘ 5 6 def __init__(self, name): 7 # 普通字段/对象属性 8 self.name = name 9 10 # 实例对象obj1 11 obj1 = Province(‘河北省‘) 12 print(obj.name) # 直接访问普通字段 13 14 # 实例对象obj2 15 obj2 = Province(‘河南省‘) 16 print(obj.name) # 直接访问普通字段 17 18 # 直接访问静态字段 19 Province.country
2). 方法:普通方法、类方法、静态方法、属性方法
前三种方法在内存中都归属于类,区别在于调用方式不同。普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;类方法:由类调用;至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;静态方法:由类调用;无默认参数。
相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份;不同点:方法调用者不同、调用方法时自动传入的参数不同。
静态方法意思是把 @staticmethod 下面的函数和所属的类截断了,这个函数就不属于这个类了,没有类的属性了,只不是还是要通过类名的方式调用 ,把静态方法当作一个独立的函数给他传参就行了。
类方法只能访问类变量,不能访问实例变量。
属性方法把一个方法变成一个静态属性,属性就不用加小括号那样的去调用了
1 class Foo: 2 3 def __init__(self, name): 4 self.name = name 5 6 def ord_func(self): 7 """ 定义普通方法,至少有一个self参数 """ 8 print(‘普通方法‘) 9 10 @classmethod 11 def class_func(cls): 12 """ 定义类方法,至少有一个cls参数 """ 13 print(‘类方法‘) 14 15 @staticmethod 16 def static_func(): 17 """ 定义静态方法 ,无默认参数""" 18 print(‘静态方法‘) 19 20 # 调用普通方法 21 f = Foo() 22 f.ord_func() 23 24 # 调用类方法 25 Foo.class_func() 26 27 # 调用静态方法 28 Foo.static_func()
属性方法:其实是方法里面普通方法的变种。属性方法的定义和调用要注意:定义时,在普通方法的基础上添加 @property 装饰器;定义时,属性仅有一个self参数调用时,无需括号。补充:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象,属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回。
1 class Foo: 2 3 # 定义普通方法 4 def func(self): 5 pass 6 7 # 定义属性 8 @property 9 def prop(self): 10 pass 11 12 # 实例化对象 13 foo_obj = Foo() 14 15 foo_obj.func() # 调用普通方法 16 foo_obj.prop # 调用属性方法
属性方法的两种定义方式:装饰器 即:在方法上应用装饰器;静态字段 即:在类中定义值为property对象的静态字段。
1 # 装饰器方式:在类的普通方法上应用@property装饰器 2 class Goods: 3 4 @property 5 def price(self): 6 return "wupeiqi" 7 8 obj = Goods() 9 10 obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值 11 12 13 # 静态字段方式,创建值为property对象的静态字段 14 class Foo: 15 16 def get_bar(self): 17 return ‘wupeiqi‘ 18 19 BAR = property(get_bar) 20 21 obj = Foo() 22 23 obj.BAR # 自动调用get_bar方法,并获取方法的返回值
类特殊成员:
魔术函数:__开头并且__结尾的函数,我们称为魔术函数;特点:调用执行都不需要程序员关注,系统自行决定;例如:__init__、__del__、__str__ 、...... 构造函数,析构函数, 重写函数,...... 。
构造函数(constructor):又称构造方法/构造器,在生成对象时调用,一个对象只会被执行一次,可以用来进行一些初始化操作,不需要显示去调用,系统会默认去执行。
格式:__init__(self):
执行时机:在创建对象时被执行
1 class Person(object):
2
3 def __init__(self,name,age):
4 self.name = name
5 self.age = age
6 self.address = ‘中国‘
6
7 def details(self):
8 print(‘姓名为:%s,年龄为:%d,籍贯是:%s‘ %(self.name,self.age,self.address))
9
10 # 创建对象
11 p1 = Person("多多",18) # 构造方法,通过类创建对象时,自动触发执行
12 # 创建第二个对象,与p1互不干扰,共同存在与堆中
13 p2 = Person("老王",28)
14 p2.details()
析构函数:当对象在内存中被释放时,自动触发执行,此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。这个方法默认是不需要写的,不写的时候,默认是不做任何操作的。因为不知道对象是在什么时候被垃圾回收掉,所以,除非确实要在这里面做某些操作,不然不要自定义这个方法。
格式:__del__(self):
执行时机:在程序结束前,将对象回收,清出内存
1 class Dog: 2 3 def __init__(self,name,age,color): 4 print(‘我是构造函数...‘) 5 self.name = name 6 self.age = age 7 self.color = color 8 9 def __del__(self): 10 print(‘我是析构函数...‘) 11 12 def func(self): 13 print(‘我是func函数...‘)
__str__(self)函数:如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值
对象实例化之后将数据给到对象名,此时如果打印对象名,在控制台上我们看到的是整个对象的类型以及在内存中的地址(十六进制),但是我们在开发过程中,对于类型和地址并不关注;我们更希望看到的是对象的各个属性内容,此时我们可以自己重新定义__str__(self)函数的函数体(就是函数重写),此函数有返回值,return后面的内容必须是str类型
执行时机:在打印对象名/引用名时被触发
1 # 没有定义__str__方法时,打印创建的对象 2 class Person(object): 3 4 def __init__(self,name,age,address): 5 self.name = name 6 self.age = age 7 self.address = address 8 9 p = Person(‘韩梅梅‘,20,‘上海‘) 10 print(p) # <__main__.Person object at 0x0000000004C3D978> 11 12 13 # 有定义__str__方法时,打印创建的对象 14 class Person(object): 15 16 def __init__(self,name,age,address): 17 self.name = name 18 self.age = age 19 self.address = address 20 21 def __str__(self): 22 return ‘姓名为:%s,年龄为:%d,籍贯是:%s人‘ %(self.name,self.age,self.address) # return后面必须是字符串数据 23 24 p = Person(‘韩梅梅‘,20,‘上海‘) 25 print(p) # 姓名为:韩梅梅,年龄为:20,籍贯是:上海人
以上是关于17.python面向对象的主要内容,如果未能解决你的问题,请参考以下文章