一 对象的概念
程序 = 数据 + 功能
面向过程:
核心是'过程'二字
过程的终极奥义就是将程序流程化
过程是'流水线',用来分步骤解决问题的
面向对象:
核心是'对象'二字
对象的终极奥义就是将程序"整合"
对象是'容器',用来盛放数据与功能的
示例:
学生容器 = 学生的数据 + 学生的功能
课程r容器 = 课程的数据 + 课程的功能
二 类与对象
1 类的概念
类也是"容器",该容器用来存放同类对象共有的数据与功能
产生对象的类与对象之间存在关联,这种关联指的是:对象可以访问到类中共有的数据与功能,所以类中的内容仍然是属于对象的,类只不过是一种节省空间、减少代码冗余的机制,面向对象编程最终的核心仍然是是去使用对象。
类体代码,在类的定义阶段就运行了,产生类的名称空间(可以通过类.__ dict __ 查看)
写程序:先想哪些数据整合到一起。
在程序,必须事先定义好类,然后再调用类产生对象(调用类拿到的返回值就是对象)
注:类体代码是在类定义阶段就会立即执行,会产生类的名称空间
定义类
class Student: #类的命名应该使用'驼峰体'
#1、变量的定义
stu_school= 'oldboy'
# 空对象,'egon', 18, 'male'
def __init__(self, x, z):
self.stu_name = x #空对象.stu_name = 'egon'
self.stu_age = y #空对象.stu_age= 18
self.stu_gender = z #空对象.stu_gender = 'male'
#2、功能的定义
def tell_stu_info(self):
print('学生信息:名字:%s 年龄:%s 性别:%s' %(
self.stu_name,
self.stu_age,
self.stu_gender
))
def set_info(self,x,y,z):
self.stu_name=x
self.stu_age=y
self.stu_gender=z
def choose(self,x):
print('正在选课')
self.course=x
类是对象相似数据与功能的集合体,所以类体中最常见的是变量与函数的定义,但是类体其实可以包含任意其他代码的
可以通过 类. __ dict__ 来查看类这个容器内盛放的东西
如:
print(Student.__dict__)
#{..., 'stu_school': 'oldboy', 'choose': <function Student.choose at 0x128b6850>, ...}
2 对象
1、类实例化(调用类产生对象)
stu1_obj= Student('egon', 18, 'male') #自动调用 __init__ 方法,Student.__init__(空对象,'egon',18,'male')
stu2_obj=Student('lili',19,'female')
stu3_obj=Student('jack',20,'male')
通过调用类产生的对象的名称空间(可以通过对象. __ dict __ 查看),调用类会自动触发类下面的__ init __ 方法
2、调用类的过程又称之为实例化,发生了三件事
1、先产生一个空对象(python 底层做了,是看不到的)
2、python 会自动调用类的__ init __ 方法,然后将空对象和已经调用类时括号内传入的参数一起传给 __ init __方法
3、返回初始完的对象
3、总结 __ init __ 方法
1、会在调用类时自动触发执行, 用来为对象初始化自己独有的数据
2、 __ init __ 内应该存放是为对象初始化属性的功能,但是是可以存放任意其他代码,想要在类调用时就立刻执行的代码都可以放到该方法内
3、__ init __方法必须返回 None(默认就是返回 None)
3、属性访问
1、类属性访问
在类中定义的名字,都是类的属性,类有两种属性:数据属性和函数属性,可以通过 __ dict __ 访问属性的值,比如 Student.__ dict __ ['stu _ school'], 但 python 提供了专门的属性访问语法
1、访问数据属性
print(Student.stu_school) #oldboy
2、访问函数属性
print(Student.tell_stu_info) #<function Student.tell_stu_info at 0x10fd4c1e0>
print(Student.set_info) #<function Student.set_info at 0x10fd4c378>
1)当通过类.方法来修改类的属性时,调用类的对象属性都会随之改变
Student.stu_school='OLDBOY'
print(stu1_obj.stu_school) #OLDBOY
print(stu2_obj.stu_school) #OLDBOY
2)当对象的属改变时,类的属性和其他调用该类的属性不会被改变
stu1_obj.stu_school='OLDBOY'
print(stu1_obj.stu_school) #OLDBOY
print(Student.stu_school) #oldboy
print(stu2_obj.stu_school) # #oldboy
print(stu3_obj.stu_school) # #oldboy
原因就是类中定义的函数主要是给对象使用的,而且是绑定给对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同。
3)类调用自己的函数属性必须严格按照函数的用法来(有几个参数就必须传几个)
#类实例化产生对象
stu1_obj= Student('egon', 18, 'male') #自动调用 __init__ 方法,Student.__init__(空对象,'egon',18,'male')
stu2_obj=Student('lili',19,'female')
stu3_obj=Student('jack',20,'male')
#通过类调用方法
Student.tell_stu_info(stu1_obj) #学生信息:名字:egon 年龄:18 性别:male
Student.tell_stu_info(stu2_obj) #学生信息:名字:lili 年龄:19 性别:female
Student.tell_stu_info(stu3_obj) #学生信息:名字:jack 年龄:20 性别:male
2、对象属性访问
类通过实例化产生对象,这时对象就有了对象的绑定方法,绑定方法的特殊之处在于:谁(对象)来调用绑定方法就会将谁当做第一个参数传入
#类实例化产生对象
stu1_obj= Student('egon', 18, 'male') #自动调用 __init__ 方法,Student.__init__(空对象,'egon',18,'male')
stu2_obj=Student('lili',19,'female')
stu3_obj=Student('jack',20,'male')
stu1_obj.tell_stu_info() #tell_stu_info(stu1_obj) #学生信息:名字:egon 年龄:18 性别:male
stu2_obj.tell_stu_info() #tell_stu_info(stu2_obj)
stu3_obj.tell_stu_info() #tell_stu_info(stu3_obj)
3、操作对象的属性
print(stu1_obj.__dict__) #{'stu_name': 'egon', 'stu_age': 18, 'stu_gender': 'male'}
#查看
stu1_obj.stu_name #egon 等同于 stu1_obj.__dict__['stu_name']
#新增
stu1_obj.stu_hobby = 'play basketball'
print(stu1_obj.__dict__) #{'stu_name': 'egon', 'stu_age': 18, 'stu_gender': 'male'}
#修改
stu1_obj.stu_gender = 'female'
print(stu1_obj.__dict__) #{'stu_name': 'egon', 'stu_age': 18, 'stu_gender': 'female', 'stu_hobby': 'play basketball'}
#删除
del stu1_obj.stu_hobby
print(stu1_obj.__dict__) #{'stu_name': 'egon', 'stu_age': 18, 'stu_gender': 'female'}
4、属性查找顺序与绑定方法
对象的名称空间里只存放着对象独有的属性,而对象相似的属性是存放于类中的。对象在访问属性时,会优先从对象本身的__ dict __ 中查找,未找到,则取类中的__ dict __ 中查找
类的属性是共享给所有对象用,所以大家访问的地址都是一样的
print(id(stu1_obj.stu_school)) # #4494520136
print(id(stu2_obj.stu_school)) # #4494520136
print(id(stu3_obj.stu_school)) # #4494520136
绑定到对象的方法特殊之处在于,绑定给谁就应该由谁来调用,谁来调用,就会将’谁’本身当做第一个参数自动传入(方法__ init __也是一样的道理),在使用对象的绑定方法时,python 会默认将对象本身当做第一个参数自动传入,因此无需我们再传入。
绑定到不同对象的 choose 技能,虽然都是选课,但是学生 1 选的课不会选给学生 2,这正是'绑定'二字的精髓所在
stu1_obj.choose('python全栈开发')
print(stu1_obj.course)
stu2_obj.choose('linux运维')
print(stu2_obj.course)
stu3_obj.choose('高级架构师')
print(stu3_obj.course)
注:绑定到对象方法的这种自动传值特征,决定了在类中定义的函数都要默认写一个参数 self,self 可以是任意的名字,但是命名为 self 是约定俗成的
python 中一切皆为对象,且 python3中类与类型是一个概念
#类型list就是类
>>> list
<class 'list'>
#实例化得到 3个对象l1,l2,l3
>>> l1=list([1,2,3])
>>> l2=list(['a','b','c'])
>>> l3=list(['x','y'])
#三个对象都有绑定方法append,是相同的功能,但内存地址不同
>>> l1.append
<built-in method append of list object at 0x10b482b48>
>>> l2.append
<built-in method append of list object at 0x10b482b88>
>>> l3.append
<built-in method append of list object at 0x10b482bc8>
#操作绑定方法l1.append(4),就是在往l1添加4,绝对不会将4添加到l2或l3
>>> l1.append(4) #等同于list.append(l1,4)
>>> l1
[1,2,3,4]
>>> l2
['a','b','c']
>>> l3
['x','y']