Python之面向对象(一)
基本概念
什么是对象
在Python中万物皆对象。
对象是具体的物体。该物体拥有属性、行为,对象就是把很多零散的东西封装成一个整体。
e.g.
Javier_Ji 拥有姓名、年龄、身高、体重…(这些既是属性);
Javier_Ji能走路、吃饭、睡觉…(这些既是行为)。
Javier_Ji就是一个对象,一个实例。
面向过程&面向对象
面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就像流水线,能做到什么在时候做什么事情。在解决问题的时候关注的是解决问题的每一个过程(步骤)。
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
面向对象在解决问题的时候,关注的是解决问题所需要的对象。
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
举个栗子:
如何从面向过程编程的思想,过渡到面向对象编程?
- 一样的,列举出一个任务的具体实现步骤
- 试图分离这些实现步骤中的功能代码块
- 将这些功能代码块,划分到某一个对象中
- 根据这个对象以及对应的行为,抽象出对应的类
类
由对象抽象出对应的类,如由Javier_Ji抽象出人类,人类拥有年龄、性别、身高等属性,吃饭、睡觉等行为。
类的作用
根据抽象出的类,生产具体的对象。
我们可以通过人类这个类生成张三、李四、王五等等不同的对象,这些对象的模板就是人类。
类的组成
名称、属性、方法
其中的属性和方法都是抽象的概念。只有在产生对象之后,对象才拥有具体的属性值和方法实现
列举生活中的类:
- 类:钱
对象:具体的1毛、1元、5元…… - 类:动物
对象:猫、狗、老虎 - 类:汽车
对象:凯迪拉克、宝马、奥迪
对象和类的关系
面向对象在python中的实现
如何定义一个类
class 类名:
pass
怎样通过类创建(或者说实例化)一个对象
对象名 = 类名()
通过类创建对象时底层执行机制
话不多说,上码
class Person:
pass
p = Person()
Person是一个变量名,引用了Person这个类,即该变量指向了Person这个类的地址。Person()
使程序在内存中开辟了一块新的空间用来存放对象,即上图中的椭圆形。p也是一个变量,指向了根据Person这个类产生的对象的地址。
在产生的对象中有一个属性值__class__
关联着Person类。
>>> p.__class__
<class '__main__.Person'>
属性相关
属性和变量的区别及判定依据
- 区别:
概念:变量是“可以改变的量值”。属性是“属于某个对象的特性”。
访问权限:变量是根据不同的位置,存在不同的访问权限(全局变量、局部变量……)。属性只能通过对象来进行访问,所以必须先找到对象才能调用其属性,并且对象也是通过变量名来引用,而既然是变量,也有其相对应的访问权限。
2.判定依据:是否存在宿主。
如果是变量,则直接写给变量即可。如果是属性,则需要写对象.属性
。
根据宿主的不同可以划分为:对象属性和类属性
对象属性
增
- 直接通过对象,动态添加
语法:对象.属性 = 值
class Person:
pass
p = Person()
p.age = 18
print(p.age)
打印的结果为:18
我们可以使用内置方法:__dict__
来查看是否真的将age
属性存到了p
对象中。
对象.__dict__
表示的是当前该对象中的所有属性
print(p.__dict__)
打印的结果为:{'age': 18}
该属性是如何存储的呢?
在内存中开辟一块空间存储18
,age
中存放的是18
的唯一标识,即age
指向18
。
当我们输入p.age
时,是通过p
变量找到对应的对象
,通过对象
找到age属性
,age
的值指向18
。
- 通过类的初始化方法(构造方法)
__init__
方法
删
使用del
命令,即可删除属性。
class Person:
pass
p = Person()
p.age = 18
print(p.age, id(p.age))
del p.age
print(p.__dict__)
打印的结果为:
18 140718833325632
{}
改
class Person:
pass
p = Person()
p.age = 18
print(p.age, id(p.age))
p.age = 25
print(p.age, id(p.age))
print(p.__dict__)
打印的结果为:
18 140718833325632
25 140718833325856
{'age': 25}
由打印出的结果我们可以发现,两个属性的值的地址不一样。说明在修改属性age
指向的值18
时,会开辟一块新的空间来存储新的值25
,并将属性age
指向新的值25
。
查
对象.属性
(p.age
)即可查看(或叫访问)该属性的值。
注意:不同的对象之间不可以互相访问对方的属性!!!
类属性
增
类名.类属性 = 值
class Person:
pass
Person.age = 20
print(Person.age)
print(Person.__dict__)
打印的结果为:
20
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'age': 20}
我们可以看到,age
属性确实被添加进去了。
- 在类定义是添加类属性
class Person:
age = 20
height = 180
weight = 70
print(Person.age)
print(Person.height)
print(Person.weight)
print(Person.__dict__)
打印的结果为:
20
180
70
{'__module__': '__main__', 'age': 20, 'height': 180, 'weight': 70, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
可以看到属性age
、height
和weight
都被添加进去了
查
-
通过类访问:
类名.属性
-
通过对象访问:
对象.类属性
class Person:
age = 20
height = 180
weight = 70
p = Person()
print(p.age)
print(p.height)
print(p.weight)
print(Person.__dict__)
print(p.__dict__)
打印的结果为:
20
180
70
{'__module__': '__main__', 'age': 20, 'height': 180, 'weight': 70, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
{}
注意
Q:为什么可以通过对象访问到类属性?
A:和Python对象的属性查找机制有关
优先在对象自身查找属性,若找到则结束,否则根据__class__
找到对象对应的类,在类中查找
改
- 通过类名修改
class Person:
age = 20
height = 180
weight = 70
Person.age = 666
print(Person.age)
print(Person.__dict__)
打印的结果为:
666
{'__module__': '__main__', 'age': 666, 'height': 180, 'weight': 70, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
- 能否通过对象进行修改?
不能
class Person:
age = 20
height = 180
weight = 70
Person.age = 666
print(Person.age)
p = Person()
p.age = 777
print(Person.age)
print(Person.__dict__)
print(p.__dict__)
打印的结果为:
666
666
{'__module__': '__main__', 'age': 666, 'height': 180, 'weight': 70, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
{'age': 777}
我们可以看到age
类属性还是666,经过p.age = 777
后,对象p
中增加了age
对象属性。
为什么呢?
因为p.age = 777
是赋值操作,而不是查询操作!!!
删
- 通过类名删除:
del 类名.属性
- 能否通过对象删除?
不能,因为del
语句只能删除直系属性!
限制对象属性的添加
使用__slots__
方法。
class Person:
__slots__ = ('age', 'height')
pass
p = Person()
p.age = 777
print(p.age)
p.height = 180
print(p.height)
p.weight = 777
print(p.weight)
打印的结果为:
777
180
Traceback (most recent call last):
File "G:/python_work/面向对象/类.py", line 11, in <module>
p.weight = 777
AttributeError: 'Person' object has no attribute 'weight'
由于weight
没有被放到__slots__
中,所以不能绑定weight
属性,试图绑定weight
将得到AttributeError
的错误。