Python入门自学进阶——5--类与对象
Posted kaoa000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python入门自学进阶——5--类与对象相关的知识,希望对你有一定的参考价值。
面向对象编程是函数式编程的一种变化。python既可以函数式编程,也可以面向对象编程。
函数式编程可以做所有事,只是看适不适合,如果使用面向对象更简洁,就使用面向对象。
对比:
函数式编程,定义一个函数:
def foo(name,age,sex,content):
print(name,age,sex,content)
面向对象,定义一个类:
class Bar:
def foo(,self,name,age,sex,content):
print(name,age,sex,content)
使用或是说执行:
函数:直接 foo('小明',20,'男','吟诗一首')
对象:obj = Bar()
obj.foo('小明',20,'男','吟诗一首')
区别:
定义:
函数:def + 函数名(参数)
面向对象:class + 类名 ==>名字叫Bar类
def + 方法名(参数) ===>名字叫foo的方法
参数第一个一般是固定的self
执行:
函数:
函数名(参数)
面向对象:
obj = Bar #创建obj变量(相当于一个中间人),叫做对象或实例
obj.foo() #第一个self参数不必输入,python自动填充
即对象.方法(参数)
函数和对象的方法都有返回值,默认都是None。
类、对象(实例)在内存中的加载及参数self
对于对象(实例),可以在生成后再添加私有属性。对象就像一个中间人,通过它来使用类中的方法,这样方法就在内存中存在一份就行了。
像上面的添加的属性,相当于将一些公共的属性装到了对象中,这就是面向对象的封装概念。
面向对象的构造方法:
特殊作用:在
obj = 类名() 过程中,做了两件事
#创建对象obj
#通过对象执行类中的一个特殊方法。
这个特殊方法是:__init__(self,...),叫做构造方法。
构造方法的作用:就是对对象进行数据封装,将数据封装到对象中,相当于对对象中的变量进行初始化。
如上图,构造函数的作用就类似上图中Bar的实例obj增加name和age属性一样,构造函数更简洁、方便。生成哪个对象,构造函数中的self就是哪个对象,相应的就对该对象中的属性进行了赋值,即初始化了。
这里,构造方法与foo()方法的区别就是调用者不同,foo()方法是对象主动调用的,需要使用obj.foo('999')显式主动调用,而构造方法是Python调用的。
obj = Bar('aaa',30,'999')是先执行Bar(),生成obj对象,然后python调用obj的构造方法,而 Bar('aaa',30,'999')括号中的参数,就是传给构造方法的参数。
上面的就是数据的封装,封装到了对象中。对象的封装特性。(面向对象三大特性之一)
如果所有的对象都有一个公共的属性,如都一个颜色为yellow,则可以如下实现:
这样,每创建一个对象,都会有一个color属性,值为yellow。
如果多个函数中有一些相同参数时,最好转换为面向对象,可以封装共同的数据。
继承(面向对象三大特性之一)
在定义类的时候,类名后加上括号,括号中写上父类名。上例Son是子类(或叫派生类),Father是父类(或叫基类)
如果对父类中的fun2()方法不满意,想要有自己的实现,可以在Son中重写这个方法
对于Son中的fun2,如果即想执行本类中的方法,又想执行父类中fun2方法,需要使用super()方法:
继承的使用场景: 别人的应用程序,或是Web框架,提供了一个类提供了一些功能,想对其中一些功能进行扩展,可以使用继承,然后重写相关方法。
Python的继承支持继承多个父类。继承多个父类有一个问题,如果多个父类中都有一个相同的方法,那么子类调用这个父类的方法时,是调用哪一个父类的方法呢?这里就需要有一个查找的排序问题。
查找适用MRO原则:
只有新式类:C3算法
C3算法详解:
公式:
L(object) = [ object ]
L(子类(父类1,父类2)) = [ 子类 ] + merge(L(父类1) + L(父类2) + [父类1,父类2])
注意:+ 代表合并列表
mergel算法:
1、第一个列表中的第一个元素如果是后面列表中的首个元素或者在后面列表中不存在,则将这个元素合并到merge函数前面的最终列表中,并删除这个元素
2、如果第一个列表第一个元素不成立,则查看第二个列表首个元素,执行第1步操作
3、如果最终无法把所有元素都归到最终的解析列表中,则报错,说明是错误的继承关系
当定义好类后,也就形成了这个查找顺序,就是__mro__
注意运行结果是F2.fun
关键是第4步,到低是执行了F1中的fun还是Minx中的fun,这里一定要看self是谁。
多态(面向对象三大特性之一)
类似Java这类语言,其对类型的限制是严格的,多态就是说子类也是父类,一个方法接收的参数类型为类A,则A的子类也可以接收。
而 python语言原生多态,不需要考虑了。
类及其成员:
class Foo:
country = ‘中国’ #字段 (静态字段)
def __init__(self,name) #__init__是构造方法
self.name = name #self.name叫做字段(普通字段)
def show(self): #show是方法 (普通方法)
print(self.name)
#python加载到这里时,类被加载到内存,静态字段就生成,也就存在了。
print(Foo.country) #可以执行了,静态字段可以通过类访问
obj = Foo('aaa') #这一步执行时,普通字段才会生成。
obj.name #普通字段只能通过对象访问
obj.show()
obj.country #这一步也能执行,静态字段可以通过对象访问
那么,类的成员包括:
#字段
- 普通字段,保存在对象中,那么内存中有多少个对象,就会有多少份普通字段
- 静态字段,保存在类中,内存中只存在一份。
普通字段属于对象,静态字段属于类。普通字段只能通过对象访问,静态字段可以通过类和对象访问。
#方法
- 普通方法,保存在类中,必须先创建对象,然后通过对象调用,或是通过类调用但是要传入一个对象参数
- 静态方法,保存在类中,在方法上加上装饰器@staticmethod,下面定义的方法就是静态方法,静态方法的参数是可选的,即可以没有self参数,可以通过类直接调用。
- 类方法,保存在类中,使用@classmethod装饰器,具有参数,默认写成cls,传送的是类本身。由类直接调用。
- 应用场景:
如果对象中需要保存一些值,执行某功能时,需要使用对象中值,则使用普通方法。
如果不需要任何对象中的值,可以使用静态方法。
类方法完全可以使用静态方法构建出来。
类属性:
对于类的字段,无论是普通字段还是静态字段,定义时就是写一个字段名,然后是等于号在跟上值,即字段名 = 值,调用时,使用对象.字段名或类名.字段名;对于类的方法,定义时使用def 方法名(),调用时,使用对象.方法名()或类名.方法名()。
而看下面的例子:
对于per,它的定义与方法相同,但是它的调用与字段相同,就是使用对象.方法名,后面没有括号,这种使用@property装饰器修饰的方法,这叫做属性。
因为字段是可以赋值的,那么属性类似字段,是否可以赋值?测试:
可以看到直接赋值不行,修改如下
这时就可以对属性进行赋值了。
可以看出,@property修饰的方法,相当于取值,即执行obj.per时调用,@方法.setter修饰同样的方法名,相当于赋值。即执行obj.per = 时调用。
这种写法主要是使属性与字段表现相同,还有一个@方法名.delete,模拟字段的删除
属性还有一种等价的写法
以上是关于Python入门自学进阶——5--类与对象的主要内容,如果未能解决你的问题,请参考以下文章
Python入门自学进阶——6--类与对象-成员修饰符特殊成员及元类
Python入门自学进阶-Web框架——4HttpRequest和HttpResponse及模板