python中的面向对象详解
1. 面向过程和面向对象
1.1 面向过程
面向过程就是先分析出解决问题的步骤,再把步骤拆成一个个方法,是没有对象去调用的,通过一个个方法的执行解决问题。
1.2 面向对象
面向对象就是将编程当成是一个事物(对象),对外界来说,事物是直接使用的,不用去管内部的情况,而编程就是设置事物能做什么事
情。
2. 类和对象
2.1 类
对一系列具有相同属性和行为的事物的统称,是一个抽象的概念,不是真实存在的事物。
# 基本格式:
class 类名:
代码块
注意:类名要符合标识符规定,同时遵循大驼峰命名法,见名知意。
类的三要素
- 类名
- 属性:对象的特征描述,用来说明是什么样子的。
- 方法:对象具有的功能(行为),用来说明能够做什么。
2.2 对象
类的具体表现,是面向对象编程的核心。
# 实例化(创建)对象的格式:
对象名=类名()
注意:
- 先有类,再有对象。
- 类只有一个,对象可以有很多个。
3. 类属性和实例属性
3.1 类属性
类属性就相当与全局变量,实例对象共有的属性,实例对象的属性为实例对象自己私有。
类属性就是类对象(Tool)所拥有的属性,它被所有类对象的实例对象(实例方法)所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象和实例对象访问。
类属性是定义在类级别上的属性,它是类的所有实例共享的。当在类定义中定义一个变量时,它就成为了类属性。
class People(object):
name = 'Tom' #公有的类属性
__age = 12 #私有的类属性
p = People()
print(p.name) #正确
print(People.name) #正确
print(p.__age) #错误,不能在类外通过实例对象访问私有的类属性
print(People.__age) #错误,不能在类外通过类对象访问私有的类属性
3.2 实例属性
与类属性不同,实例属性是每个类实例特有的属性,每个实例都有自己的属性。当您创建一个类的实例时,它会拥有自己的属性和值,这些属性和值称为实例属性。
class People(object):
address = '山东' #类属性
def __init__(self):
self.name = 'xiaowang' #实例属性
self.age = 20 #实例属性
p = People()
p.age =12 #实例属性
print(p.address) #正确
print(p.name) #正确
print(p.age) #正确
print(People.address) #正确
print(People.name) #错误
print(People.age) #错误
3.3 通过实例(对象)去修改类属性
class People(object):
country = 'china' #类属性
print(People.country)
p = People()
print(p.country)
p.country = 'japan'
print(p.country) #实例属性会屏蔽掉同名的类属性
print(People.country)
del p.country #删除实例属性
print(p.country)
3.4 区别和使用
使用
-
使用类属性来定义类级别的属性和默认值。
-
使用实例属性来定义实例特定的属性和值。
区别
- 实例属性只能由对象名访问,不能由类名访问。实例属性是属于对象的,是私有的。
- 访问类属性,类可以访问到,实例对象也可以访问到。类属性是属于类,是公共的。
4. 实例方法
由对象调用,至少有一个self
参数,执行实例方法的时候,自动将调用该方法的对象赋值给self
。
self参数是类中的实例方法必须具备的。
5. 构造函数
构造函数:__init__()
。
构造函数也被称为构造器,当创建类对象的时候第一个被自动调用的函数
作用
- 通常是在做属性初始化或者赋值操作。
注意
- 在类实例化对象的时候,会被自动调用。
示例
#1. 构造函数何时被调用
# 我们来下面这段代码:
class People:
# tag = "创建类对象" 如果写在这里,下面用到的时候就要加 self. 和下一个注释是一对的
def __init__(self, age):
self.age = age
tag = "创建类对象"
# print(self.tag)
print(tag)
def print_what(self):
print("what")
# 看看他们分别打印了什么(语句后面是打印的结果)
obj = People(18) # 创建对象
print(obj.age) # 18
obj.print_what() # what
print(obj) # <__main__.People object at 0x000001E698FB94F0>
由上面的代码可以看出,当刚创建类对象的时候,并没有调用任何方法,但是自动执行了print(tag),这就是构造函数的作用,在创建对象的同时,__init__里面的方法就自动执行了。当然self.age = age也执行了,只不过没有调用而已,想要调用的话就通过 类对象.属性名就可以了。
#2.构造函数传不定长参数
class Check1():
def __init__(self,*args): #设置不定长参数
print("自动执行构造函数")
# 在创建对象的时候,注意参数的匹配问题
c1 = Check1(10,20) # 自动执行构造函数
c1 = Check1() # 自动执行构造函数
5. 析构函数
析构函数:__del__()
。
删除对象的时候,解析器会默认调用__del__()
方法。
5.1 定义
析构函数是Python面向对象编程中的一个重要概念,它是在对象生命周期结束时自动调用的特殊方法。就像我们每个人都有出生和死亡一样,Python对象也有创建和销毁的时刻。而析构函数就是负责在对象销毁之前执行一些清理工作的函数。
5.2 为什么使用
这是因为有时候我们在创建对象时会占用一些资源,比如打开文件、分配内存等。当对象不再需要时,我们希望释放这些资源,以便系统可以重新利用它们。而析构函数就是用来完成这个任务的。
5.3 如何使用
class Fish():
# 构造函数
def __init__(self, color, name):
self.color = color
self.name = name
# 游泳的方法
def swim(self):
print("我是一条鱼,游来游去...")
# 析构函数
def __del__(self):
print("析构函数的触发时机是:当对象被销毁的时候,自动触发...")
# 创建对象 fish
fish = Fish("红色", "锦鲤")
fish.swim()
print(fish.color)
print(fish.name)
del fish # 执行的时候,内存会立即被回收,会调用本身的__del__()方法
执行结果:
我是一条鱼,游来游去...
红色
锦鲤
析构函数的触发时机是:当对象被销毁的时候,自动触发...
6. 封装
- 封装:类——麻袋,本身就是一种封装
- 封装的方法:将属性和方法装到一个抽象的类中,外界使用类创造对象,让对象调用方法
- 封装的作用:将复杂的信息、流程给包起来,内部处理,让使用者只需要通过简单的操作步骤就能实现。
7. 私有权限、私有属性和私有方法
7.1 隐藏属性(私有权限)
私有权限:在属性名和方法名前加两个下划线__。
类中定义私有,只有类的内部能使用,外部无法访问。
访问不了私有属性:age,会报错 。私有属性,外部不能访问。
如何访问?
方法一:
隐藏权限实际上就是将名字修改为:_类名__属性名
_Person__age
。使用p._Person__age 可以访问到。
方法二:
定义一个实例方法,返回类的私有权限。
7.2 私有属性
_xx:单下划线揩油,私有属性或方法,类对象和子类可以访问。
__xx:双下划线开头,私有权限,无法再外部直接访问。
如何访问私有属性?
在实例方法内,通过:类名.__私有属性名(在类的内部访问)
7.3 隐藏方法
在实例方法中调用私有方法。
7.4 私有方法
7.5 总结
- xxx:普通属性/方法,如果是类中定义的,则类可以在任意地方使用
- _xxx:单下划线开头,声明私有属性/方法,如果定义在类中,外部可以使用,子类也可以继承。但是在另一个
py
文件中通过from xxx import *
导入时,无法导入。一般是为了避免与Python关键字冲突而采用的命名方法。 - __xxx:双下划线开头,隐藏属性,如果定义在类中,无法在外部直接访问,子类不会继承,要访问只能通过间接的方式,另一个
py
文件中通过from xxx import *
导入的时候,也无法导入。这种命令一般是python中的魔术方法或属性,都是有特殊含义或者功能的,自己不要轻易定义。