Python中万物皆对象,方法是对象,类是对象,甚至对于一些基本数据类型也是对象,在Python中离不开对象.
什么是面向对象编程
面向对象(Object oriented Programming,OOP)编程的思想主要是针对大型软件设计而来的.面向对象编程使程序的拓展性更强,可读性更好,使得编程可以向搭积木一样简单.
面向对象编程将数据和操作数据相关的方法封装到对象中,组织代码和数据的方式更加贴近人的思维,从而大大提高了编程的效率.
Python完全采用了面向对象的思想,是真正面向对象的编程语言,完全支持面向对象的基本功能,例如:继承封装多态等.
Python中,一切都是对象,之前学习的数据结构,函数等都是对象
注:Python支持面向过程,面向对象,函数式编程等多种编程规范.
面向对象和面向过程区别
面向过程(Procedure Oriented)思维
面向过程编程更加关注的是"程序的逻辑流程",是一种执行者"思维,适合编写小规模的程序.
面向过程思想思考问题时,我们首先思考的是"怎么按步骤是先?"并将步骤对应成方法,一步一步,最终完成.这个适合简单任务,不需要过多协作的情况下.比如,开车的步骤;
1.发动车 2.挂挡 3.踩油门 4.车动了
面向过程适合简单,不需要协作的是我.但是当我们思考比较复杂的问题,比如"如何造车?",就会发现列出这样的步骤,是不可能的.那是因为,造车太过于复杂,需要很多协作才能完成,此时面向对象的思维就应运而生了.
面向对象(Object Oriented)思维
面向对象更加关注的是"软件中对象之间的关系",是一种"设计者"思维"适合编写大规模的程序.
面向对象(Object)思想更契合人的思维模式.我们首先思考的是"怎么设计这个失误?"比如思考造车,我们就会思考"车怎么设计?",而不是直接想"怎么按照步骤造车的问题".这就是思维方式的转变.
面向对象方式思考造车,发现车有以下对象组成:
1.轮胎 2.发动机 3.车壳 4.座椅 5.挡风玻璃.....
因此,面向对象可以帮助我们从宏观上把我,从整体上分析整个系统.但是具体到实现部分的微观操作,仍然需要面向过程去处理.
面向过程和面向对象是相辅相成的,面向对象离不开面向过程.
面向对象方式思考
遇到复杂问题,先从问题中找(面向过程更多是找动词),然后确立这些名词哪些可以作为类,再根据问题需求确定的类的属性和方法,确定类之间的关系
面向对象和面向过程的总结
都是解决问题的思维方式,都是代码组织的方式.
解决问题简单的时候使用面向过程
解决问题复杂的时候:宏观上使用面向对象把我,微观处理上仍然是面向过程
对象的进化
随着编程面临的问题越来越发咋,编程语言本身也在进化,从主要处理简单数据开始,随着数据变化进化"数组";数据类型变复杂,进化成"结构图";处理数据的方式和逻辑复杂,进化出"对象"
类的定义:
我们通过类定义数据类型的属性(数据)和方法(行文),也就是说,类将想问和状态打包在一起"
对象是类的具体实体,一般成文"类的实例",类看做"饼干模具"的话,对象就是根据这个"模具"创建的饼干
从一个类创建对象是,每个对象都会共享这个类的行文(类中定义的方法),但会有自己的属性值(不共享状态).更具体一点:"方法代码是共享的,属性数据不共享"
Python中,"一切皆对象",类也称为"类对象",类的实例也称为"实例对象".
定义类的语法格式如下
class 类名:
类体
要点如下:
1.类名必须符合"标识符:的规则;一般规定,首字母大写,多个单词使用"驼峰原则".
2.类体重我们可以定义属性和方法.
3.属性用来描述数据,方法(即函数)用来描述这些数据相关的操作.
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def say_sore(self):
print("{0}的分数是{1}".format(self.name, self.score))
s1 = Student("tangmou", 18)
s1.say_sore()
构造函数 __init__()
类是抽象的,也称之为"对象的模板".我们需要通过类的这个模板,创建类的实例对象,然后才能使用类定义的功能.
前面说的Python对象包含三个部分:id(identity识别码) type(对象类型),value(对象的值)
现在可以更进一步的说,一个Python对象包含如下部分
1.id
2.type
3.value(对象的值)
1)属性(attribute)
2)方法(method)
创建对象,我们需要定义构造函数__init__()方法.构造方法偶那个鱼执行"实例对象的初始化工作",即对象创建后,初始化当前对象的相关属性,无返回值.
实例属性
实例属性是从属于实例对象的属性,也成为了"实例变量".他的使用有如下几个要点:
1.实例属性一般在__init()__方法中通过如下代码定义:
self.实例属性名 = 初始值
2.在本类的其他实例方法中,也是通过self进行访问:
self.实例属性名
3.创建实例对象后,通过实例对象访问:
obj01 = 类名() #创建对象,调用__init__()初始化属性值
obj01.实例属性名 = 值 #可以给已有属性赋值,也可以加新属性
实例方法
实例方法是从属于实例对象的方法.实例方法的定义格式如下:
def 方法名(self[,形参列表]):
函数体
方法的调用 格式如下:
对象.方法名([实参列表])
实例方法是属于实例对象的方法.实例方法的定义格式如下:
对象.方法名([实参列表])
函数体
方法的调用格式如下:
对象.方法名([实参列表])
要点:
1.定义实例方法是,第一个参数必须为self.和前面一样,self指当前的实例对象.
2.调用实例方法时,不需要也不能给self传参.self由解释器自动传参.
函数和方法的区别
1.都是用来完成一个功能的语句块,本质一样.
2.方法调用时,通过对象来调用.方法从属于特定实例对象,普通函数没有这个特点.
3.直观上看,方法定义时需要传递self,函数不需要
实例对象的方法调用本质
其他操作:
dir(obj)可以获得对象的所有属性,方法
obj.__dict__ 对象的属性字典
pass 空语句
isinstance(对象,类型) 判断"对象"是不是"指定类型"
类对象
前面的类定义格式中,"class 类名:".实际上解释器执行class语句时,就会创建一个类对象
类属性
类属性是从属于"类对象"的属性,也称为"类变量".由于,类属性从属于类对象,可以被所有实例对象共享.
类属性的定义方式:
class 类名:
类变量名 = 初始值
在类中或者类的外面,我们可以通过:"类名.类变量名"来读写.
类方法
类方法是从属于"类对象"的方法.类方法通过装饰器@classmethod来定义,格式如下:
@classmethod
def 类方法名(cls [形参列表]):
函数体
要点如下:
1.classmethod必须位于方法上面一行
2.第一个cls 必须有:cls指的就是"类对象"本身;
3.调用类方法格式:"类名.类方法名(参数列表)".参数列表中,不需要也不支持给cls传值
4.类方法中访问实例属性和实例方法会导致错误
5.子类继承父类方法时,传入cls是子类对象,而非父类对象
静态方法
python中允许定义与"类对象"无关的方法,称为"静态方法".
"静态方法"和模块中定义的普通函数没有区别,只不过"静态方法"放到了"类的名字空间里面",需要通过"类调用".
静态方法通过装饰器@staticmethod来定义,格式如下:
@staticmethod
def 静态方法名([形参列表])
函数体
要点如下:
1.@staticmethod必须位于方法上面一行
2.调用静态方法格式:"类名.静态方法名(参数列表)";
3.静态方法中访问实例属性和实例方法会导致错误
demo
尝试了一下类方法和静态方法的区别:
静态方法如果有cls参数则在使用的时候必须将对象作为参数放在里面
而类方法,cls这个参数是不需要再外部传值的
class Student:
isChinese = True
@classmethod
def showFlag(cls):
print("这是一个{0}的学生".format("中国" if cls.isChinese== True else "外国"))
@staticmethod
def showOther():
print("这是一个静态的方法")
def __init__(self,name,age):
self.name = name
self.age = age
def showStudent(self):
print("{0}今年{1}岁了".format(self.name, self.age))
s = Student("张三",17)
s.showStudent()
Student.showFlag()
s.showOther()
Student.showOther()
__del__方法(析构函数)和垃圾回收机制
__del__方法称为 析构方法,用于实现对象销毁时所需要的操作.比如:释放对象占用的资源,例如:打开文件资源,网络连接等.
Python实现自动的垃圾回收,当对象没有被引用时(应用技术为0),由垃圾回收期调用__del__方法
我们也可以通过del语句删除对象,从而保证调用__del__方法
系统会自动提供__del__方法,一般不需要自定义析构方法
__call__方法和可调用对象
定义了__call__方法的对象,称为 "可调用对象",即该对象可以像函数一样被调用
在Python中方法没有重载
在其他语言中,可以定义多个重名的方法,只要保证方法签名唯一即可.方法签名包含3个部分:方法名,参数数量,参数类型.
Python中,方法的参数没有具体
类型(调用时确定参数的类型),参数的数量也可以由可变参数控制.因此,Python中是没有方法的重载的.定义一个方法即可有多重调用方式,相当于实现了其他语言中的方法的重载.
如果我们在类体中定义了多个重名的方法,只有最后一个方法有效.
建议:不要使用重名的方法!Python中方法没有重载
方法的动态性
Python是动态语言,我们可以动态的为类添加新的方法,或者动态的修改类的已有的方法.
私有属性和私有方法(实现封装)
Python对于类的成员没有严格的访问控制限制,这与其他面向对象语言有区别.关于私有属性和私有方法,有如下要点:
1.通常我们预定,两个下划线开头的属性是私有的(private).其他的为公共的(public)
2.类内部可以访问私有属性(方法)
3.类外部不可直接访问私有属性(方法)
4.类外部可以通过"_类名__私有属性(方法)名"访问私有属性(方法)
注意:
方法本质上也是属性!只不过是可以通过()执行而已.所以,此处讲的私有属性和公有属性,也同时讲解了私有方法和公有方法的用法.如下测试中,同时也包含了私有方法和公有方法的例子
私有方法
class Employee:
__hobby = "玩手机"
def __init__(self,name,age):
self.name = name
self.__age = age
def __work(self):
print("{1}的{0}正在工作".format(self.name,self.__age))
e = Employee("tang",18)
print(e.name)
print(e._Employee__age)
e._Employee__work()
print(Employee._Employee__hobby)
@property 可以将一个方法的调用方式变成"属性调用",下面是一个例子
class Employee:
def __init__(self,name,age,salary):
self.__name = name
self.__age = age
self.__salary = salary
def show(self):
print("{0},{1},{2}".format(self.__name,self.__age,self.__salary))
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
self.__name = name
@property
def age(self):
return self.__age
@age.setter
def age(self,age):
if(age<0 or age>99):
return
else:
self.__age = age
@property
def salary(self):
return self.__salary
@salary.setter
def salary(self,salary):
if salary<0:
return
else:
self.__salary = salary
emp = Employee("张三",28,10000)
emp.show()
emp.age = 30
emp.show()
emp.age = -10
emp.show()