python语言基础(十一)面向对象编程(类、对象、self参数、init方法、str方法、私有属性、私有方法)

面向对象编程(一)

从上至下的编程方式、函数等都成为面向过程的编程方式。
面向对象编程: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 是什么?
实际上,我们需要明确 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__()方法。
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属性封装到该对象中,才可以访问。

1__str__()方法

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--
'''可以通过 对象._类名__私有方法名 去访问私有方法,但是不建议使用'''

你可能感兴趣的:(python基础,python,开发语言)