一、面向过程VS面向对象
面向过程
- 优点:极大的降低了写代码的复杂度,只需要顺着执行的步骤,堆叠代码即可。
- 缺点:一套流水线或者流程下来是用来解决一个问题,代码牵一发而动全身。
面向对象
- 优点:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
- 缺点:可控性差。
二、初识类和对象
1、类
- 类的声明
'''
class 类名:
'类的说明文档'
类体
'''
# 创建一个类
class Student: # 类名一般开头大写
class_num = 'robot3'
def stu_speak(self):
print('student is speaking!')
- 类的两种作用:属性引用和实例化
- 属性引用(类名.属性)
class Student:
class_num = 'robot3'
def stu_speak(self):
print('student is speaking!')
print(Student.class_num) # 查看学生的班级属性
print(Student.stu_speak) # 引用学生的说话方法
# output
robot3
<function Student.stu_speak at 0x000002934C4E87B8>
- 实例化(类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特性)
class Student:
class_num = 'robot3'
def __init__(self, name): # 每个学生都有自己的姓名
self.name = name
def stu_speak(self):
print('student is speaking!')
# 实例化一个对象,这个对象的名字属性是‘jacky’
# 类名()就等于在执行Student.__init__(), 这个对象类似一个字典,存着属于这个学生本身的一些属性和方法。
jacky = Student('jacky')
#查看属性和调用方法
print(jacky.name) # 对象名.属性
print(jacky.stu_speak) # 对象名.方法名()
- 类属性的补充
一:我们定义的类的属性到底存到哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值
二:特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)
2、对象
对象是关于类而实际存在的一个例子,即实例
对象/实例 只有一种功能:属性引用(方法也是属性,只不过是类似函数的属性,我们也管它叫动态属性,调用时后面加上括号)
固定模式
class 类名:
def __init__(self, 参数1, 参数2):
self.对象的属性1 = 参数1
self.对象的属性2 = 参数2
def 方法名1(self):
pass
def 方法名2(self):
pass
对象名 = 类名(1, 2) # 实例化,参数不需要传self
# 属性引用
对象名.对象的属性1
对象名.方法名()
三、类命名空间与对象、实例的命名空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
类有两种属性:静态属性和动态属性
- 静态属性是直接在类中定义的变量
- 动态属性是定义在类中的方法
类的数据属性共享给所有对象
print(id(jacky.class_num)) # 3025487647384
print(id(Student.class_num)) # 3025487647384
类的动态属性是绑定到所有对象的
print(jacky.stu_speak)
print(Student.stu_speak)
# output
<bound method Student.stu_speak of <__main__.Student object at 0x000001FE7FEC0898>>
<function Student.stu_speak at 0x000001FE00EC87B8>
对于不可变数据类型,类变量最好用类操作
class Course:
language = 'Chinese'
def __init__(self, teacher, course_name):
self.teacher = teacher
self.name = course_name
python = Course('weige', 'python')
# 对象对类静态属性的修改只有在本对象才有效
python.language = 'English'
print(python.language) # English
print(Course.language) # Chinese
对于可变数据类型,变量的修改是共享的,重新赋值是独立的
class Course:
language = ['Chinese']
def __init__(self, teacher, course_name):
self.teacher = teacher
self.name = course_name
python = Course('weige', 'python')
# 对象对类静态属性的修改同步到了类上
python.language[0] = 'English'
print(python.language) # ['English']
print(Course.language) # ['English']
# 对象对类静态属性的重新赋值只对自身起效果
python.language = 'a language you don\'t know'
print(python.language) # a language you don't know
print(Course.language) # ['English']
怎么理解?类的数据属性共享给所有对象,但是当数据属性是可变数据类型时,比如列表,列表的地址是共享的,列表内部的修改并不会改变列表的地址,所以变量的修改是共享的,对象对类静态属性的修改将同步到类。
print(id(python.language)) # 2644085527496
print(id(Course.language)) # 2644085527496
# 列表的地址没有改变
python.language[0] = 'English'
print(id(python.language)) # 2644085527496
print(id(Course.language)) # 2644085527496
对象对数据属性重新赋值时,将产生一个新的地址,这种赋值效果只对自身有效。
print(id(python.language)) # 2642364355528
print(id(Course.language)) # 2642364355528
python.language = 'English'
print(id(python.language)) # 2642347558984 变成一个新的地址
print(id(Course.language)) # 2642364355528
四、组合
组合:在一个类中以另外一个类的对象作为数据属性,称为类的组合
class Birthday:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
class Course:
language = 'Chinese'
def __init__(self, course_name):
self.name = course_name
class Teacher:
def __init__(self, name, age, sex, birthday):
self.name = name
self.age = age
self.sex = sex
self.birthday = birthday
# 此处传入一个Course对象作为Teacher类的一个属性
self.course = Course('python')
b = Birthday(2019, 9, 22)
# 此处传入一个Birthday对象赋值给Teacher类 用以实例化一个Teacher对象
hh_teacher = Teacher('jack', 0, 'boy', b)
print(hh_teacher.birthday.year)
print(hh_teacher.course.name)
# output
2019
python
来源:https://blog.csdn.net/qq_41823444/article/details/101151243