从上至下的编程方式、函数等都成为面向过程的编程方式。
面向对象编程:Object Oriented Programming,简称OOP,是一种程序的设计思想,能把对象归类的时候就用面向对象编程,python是面向对象编程语言。
需要注意的是能够使用面向对象编程思想实现的程序,也都能通过面向过程完成,要看哪种思想更适合当前开发需求。
面向过程与面向对象区别:
面向过程:根据业务逻辑从上到下写代码,注重每一步的过程。
面向对象:将数据与函数绑定到一起,进行封装。减少重复代码的重写过程
在下五子棋的整个过程中可以有两种不同的思路来实现:
面向过程
按步骤来看:
(1)开始游戏,(2)黑子先走,(3)绘制画面,(4)判断输赢,(5)轮到白子,(6)绘制画面,(7)判断输赢,(8)返回步骤(2),(9)输出最后结果
面向对象
按组成模块来看:
(1)黑白双方模块,(2)棋盘模块,(3)规则模块
前者侧重于游戏步骤的设计,对应于编程中的面向过程思想;后者着重于分层,有模块化设计理念,对应于编程中的面向对象思想。可以很明显地看出:面向对象是以功能来划分问题,而不是步骤。
类是抽象的概念,仅仅是模板。用来描述具有相同属性和方法的对象的集合。比如:"人"是一个类,不同的姓名的人组成。
某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的。 比如:每个人就是一个对象。
班级里的每一位同学,都会有姓名、年龄的属性,在教室的行为都是在学习。可以把所有学生归为学生类,每一位学生都是类里实实在在的对象。这就是对象归类的过程。
比如汽车、水果是类,奔驰大G550、红富士是对象。
类由3个部分构成
*1. 类的名称:类名
*2 类的属性:一组数据(年龄、性别等属性)
*3 类的方法(行为):学习python的动作也被称为行为,允许对类进行操作的方法
Python 使用 class 关键字来定义类,其基本结构如下:
class MyClass:
pass
注意:类名通常采用驼峰式命名方式,尽量让字面意思体现出类的作用。
python 中,可以根据已经定义的类去创建出一个个对象
obj_name = MyClass()
在上面代码中,MyClass()就是实例化的过程,将实例化后创建出来的对象赋值给obj_name,obj_name就是对象。
小练习
*1 创建类:学生类
*2 创建对象:张三
*3 在类中定义方法输出:张三学习Python
class LogStudents: # 定义类,类名为驼峰命名法
def study_python(self): # 定义类中的方法
print('张三学python')
zs = LogStudents() # 创建对象赋值给zs,也可理解为创建zs这个对象(实例),是实例化的过程。
zs.study_python() # 通过 对象.方法名() 调用类中的方法
当在类中定义方法时,会发现系统帮我们自动创建了self 参数,并且在调用对象的该方法时,也无需传入 self 参数。那这个 self 是什么?
实际上,我们需要明确 self 的两个概念
*1 self 本身是 形参
*2 self 就是 对象本身
class LogicStudent():
def test_one(self):
print(self)
N_stu = LogicStudent()
print(N_stu) # <__main__.LogicStudent object at 0x0000026A16B89828>
N_stu.test_one() # <__main__.LogicStudent object at 0x0000026A16B89828>
'''体现了self 与 N_stu 是同一个对象'''
# 再创建一个对象,self 与 M_stu 也是同一个对象
M_stu = LogicStudent()
print(M_stu) # <__main__.LogicStudent object at 0x000002D27D657588>
M_stu.test_one() # <__main__.LogicStudent object at 0x000002D27D657588>
'''可以得到self就是对象本身,创建的对象是谁,self就是谁'''
如果创建一个对象,就用对象的名称去访问的话,会很麻烦。可以用 self. 直接调用,代表的是通过谁来调用,就用谁来传。根据对象的不同来引用不同对象的属性。
class LogicStudent():
def stu_info(self):
# print(N_stu.name, N_stu.age)
print(M_stu.name, M_stu.age)
# N_stu = LogicStudent()
# N_stu.name = 'N_stu'
# N_stu.age = 18
# N_stu.stu_info() # N_stu 18
M_stu = LogicStudent()
M_stu.name = 'M_stu'
M_stu.age = 19
M_stu.stu_info() # N_stu 18
'''在类中可以访问到对象的属性,但是N_stu和M_stu要分开运行,
若同时运行,调用stu_info()的时候,会出现另外一个对象未定义的情况'''
# 可以用self.一起调用
class LogicStudent():
def stu_info(self):
print(self.name, self.age)
N_stu = LogicStudent()
N_stu.name = 'N_stu'
N_stu.age = 18
N_stu.stu_info()
M_stu = LogicStudent()
M_stu.name = 'M_stu'
M_stu.age = 19
M_stu.stu_info() # N_stu 18 M_stu 19
0无任何意义,因为下划线显示不正确
在上面的例子中,在类的外部给它的对象添加属性,用起来没问题,但是值都要通过对象去传递,而且写在外部很容易暴漏数据,是不安全的,可以用__init__()方法。
0__init__() 方法称为 初始化方法,也可称为构造方法。在创建对象时,会自动执行该方法,为对象的属性设置初始值。
class Student():
def __init__(self):
print('--1--')
s = Student() # init为初始化方法,在创建对象后会自动执行的方法
print('--2--') # 先打印--1-- 再打印--2--
该方法可以初始化类中的属性,可以把刚才的代码进行优化。
class LogicStudent():
def __init__(self):
# 初始化对象的属性,self代表对象本身(N_stu)
self.name = 'N_stu'
self.age = 18
def stu_info(self):
print(self.name, self.age)
N_stu = LogicStudent()
N_stu.stu_info() # N_stu 18
一般在写到类的时候,初始化对象的属性都是在init下进行的,下面讲解一下在初始化对象属性时传参的问题。
class LogicStudent():
def __init__(self, stu_name, age): # __init__方法形参传递入口
self.name = stu_name
self.age = age
def stu_info(self):
print(self.name, self.age)
N_stu = LogicStudent('N_stu', 18) # __init__方法实参传递入口
N_stu.stu_info()
N_stu = LogicStudent('M_stu', 28) # __init__方法实参传递入口
N_stu.stu_info() # N_stu 18 M_stu 28
实现了相对动态的方式进行不同对象参数的传递。
class LogicStudent():
def __init__(self, stu_name, age):
self.name = stu_name
self.age = age
# 1.__init__()方法可以有返回值,但是必须为None
# return '111' # __init__() should return None, not 'str'
def stu_info(self):
print(self.name, self.age)
N_stu = LogicStudent('N_stu', 18)
# 2. 在__init__()中初始化的属性,可以在类的外部通过对象访问,在初始化方法中,self就代表N_stu
print(N_stu.name) # N_stu
print(N_stu.age) # 18
N_stu.stu_info() # N_stu 18
1.0__init__()方法可以有返回值,但是必须为None
2.在__init__()中初始化的属性,可以在类的外部通过对象访问
class LogicStudent():
def __init__(self, stu_name, age):
self.name = stu_name
self.age = age
def stu_info(self):
self.gender = 'male'
self.address = 'China'
N_stu = LogicStudent('N_stu', 18)
'''在这个地方不可以访问到gender和address,因为程序从上至下执行
打印的时候,N_stu.stu_info()还没有执行,所有必须在执行N_stu.stu_info()之后访问'''
# print(N_stu.gender)
# print(N_stu.address) # 'LogicStudent' object has no attribute 'gender'
N_stu.stu_info()
'''必须在执行N_stu.stu_info()后,调用了stu_info()才能访问到里面的属性'''
print(N_stu.gender) # male
print(N_stu.address) # China
在自定义的方法当中定义对象的属性,需要先调用执行该方法,才会将gender和address属性封装到该对象中,才可以访问。
class Student():
def __init__(self):
pass
s = Student()
print(s) # <__main__.Student object at 0x000002368F5F9828>
在上述例子中,打印的是对象(实例)所在的内存地址,如果在开发中,希望打印输出对象变量时,能够打印自定义的内容。就可以使用__str__() 方法,将自定义内容通过 return 关键字返回。
跟init一样,也为内置的具有特殊功能的魔法方法。
class Student():
def __init__(self):
self.name = 'N_stu'
self.age = 18
def __str__(self):
return self.name # N_stu
s = Student()
print(s) # N_stu
当类中有str的魔法方法的时候,会将返回的对象(return self.name),直接返回给实例(s),此时的实例不在是内存地址,而是魔法方法的返回值。
class Student():
def __init__(self):
self.name = 'N_stu'
self.age = 18
def __str__(self):
# return self.name # N_stu
# return self.age # 会报错,__str__()方法返回的必须是字符串
# return self.name, str(self.age) # 报错,return返回多个值,会打包成元组
return f'{self.name}, {self.age}' # N_stu, 18
s = Student()
print(s) # N_stu
注意:return返回值必须是字符串
在实际开发中,对象的某些属性或者方法,只希望在对象的内部使用,这时,我们就可以使用私有属性和私有方法。
私有属性:就是对象不希望公开的属性
定义方式:在属性名前面增加两个下划线(例如:__name)
*1. 定义类为:"人"类
*2. 创建对象:rose
*3. 初始化对象属性:name 与 age
*4. 要求:age 不能在类的外部访问
class People:
def __init__(self,name,age):
self.name = name
# self.age = age
self.__age = age
rose = People('zs',18)
print(rose.name) # zs
print(rose.age) # 在类的外面访问私有属性,就会报错
类的私有属性在类的外部不能访问,但是在类的内部其他方法中可以访问;可以借助类的内部方法,将私有属性返回到类的外部,在类的外部对私有属性进行访问;借助内部方法对私有属性进行修改。
class People:
def __init__(self,name,age):
self.name = name
# self.age = age
self.__age = age
def print_info(self):
print(self.__age) # 私有属性在类的内部其他方法中可以访问
def get_age(self):
return self.__age
def set_age(self, new_age):
self.__age = new_age
print(f'new_age:{new_age}')
rose = People('zs',18)
print(rose.name) # zs
# rose.print_info() # 18 1.私有属性在类的内部其他方法中可以访问
print(rose.get_age()) # 18 2.在类的内部将私有属性返回出来,进行访问
rose.set_age(30) # new_age:50 3.借助内部方法,在类的外部对私有属性进行修改
通过上述代码可以得知:
1.可以通过类的内部的方法访问私有属性
2.通过类的内部方法将私有属性返回出去
3.在类的外部调用内部方法可以对私有变量进行修改
私有方法:就是对象不希望公开的方法
定义方式:在方法名前面增加两个下划线(例如:__test )
class Test_Demo:
def test1(self):
print('--1--')
def __test2(self):
print('--2--')
def test3(self):
return self.__test2() # 或者直接调用 self.__test2(),也可以访问
d = Test_Demo()
d.test1() # --1--
# d.__test2() # 报错,无法访问
d.test3() # --2-- 通过类内部的方法进行调用
注意:
在 python 中,并没有真正意义上的私有,只有伪私有。当我们在访问时,以 对象._类名__私有属性 即可访问,私有方法同理。但是不建议使用。
class Test_Demo:
def test1(self):
print('--1--')
def __test2(self):
print('--2--')
d = Test_Demo()
d.test1() # --1--
d._Test_Demo__test2() # --2--
'''可以通过 对象._类名__私有方法名 去访问私有方法,但是不建议使用'''