17. 面向对象与封装
面向对象(object oriented)
面向对象基础
面向过程的编程思想:将程序流程化
- 优点:将程序流程化,进而使程序设计简单化
- 缺点:可扩展性差
面向对象的编程思想:对象就是容器,用来封装一些数据和功能,将程序进行整合,数据对应的就是属性,功能对应的是函数
- 优点:提升程序的解耦合程度,进而增强程序的可扩展性
- 缺点:设计复杂
面向对象编程相比较面向过程编程,能有效减少代码的重用性,增强代码的可读性
python中如何实现面向对象:类和对象
类(class)和对象(objcct)
在程序设计的时候,一定是先定义类,然后再调用类创建对象
# 1. 定义类 : 类是对象相同或者相似度功能的集合体,所以类中最常见的是变量与函数的定义,但是实际上类中可以使用任何代码
# 注意:在类的定义阶段就会执行代码,也就是说,类定义的时候就会产生类的名称空间,使用print(Student.__dict__)返回一个字典,可以查看类的名称空间中存放的东西
class Student: # 驼峰体命名,首字母一般大写
def __init__(self,name,age,gender)
self.stu_name=name # 根据3. 的解释就是将对象传给self,self.stu_name=name实际上就是对象.stu_name=name
self.stu_age=age
self.stu_gender=gender
def tell_stu_info(self):
print(self.stu_name)
# 属性查看的方法:Student.stu_school、Student.tell_stu_info
# 查看全部的属性使用Student.__dict__
# 2. 类的调用会产生对象
stu1=Student()
# 类的名称空间和对象的名称空间的关系:类在定义的时候就会产生类的名称空间,存放类中的属性和函数,在进行实例化(就是调用类产生对象的过程)的时候,会产生一个对象名称的命名空间,里面存放一个指针,指向原来的类的命名空间,对象中如果使用原来的类的属性或者方法的时候,会通过指针直接在类的命名空间中寻找,但是对于对象自己的属性(对象可以自定义属性或者函数,马上讲),存放在属性的名称空间中,这和前面的容器类的数据类型的存储方式有点像,所以说实际上类也是一个容器
# 3. __init__方法(initial初始化的意思)
# 调用类的过程称为实例化,调用类的过程中一共发生了三件事:首先是产生一个对象的名称空间,然后会自动调用类中的init方法,将空对象和调用类时使用的参数一起传给init,最后,返回一个初始化之后得到的对象(init里面经过初始化的属性都有了)
# init的方法是定义类之后自动调用的,所以不要添加一些乱七八糟的代码
# init部分默认返回none,也必须返回none,所以不用return任何值
# 4. 属性的查找循序
# 属性的查找是从对象中开始的,对象中没有的属性会到类中去查找
# 类中的属性是实例化的对象所共享的,id都是一样的,这里涉及一个修改值的问题,如果直接修改类的属性,name所有对象所使用的属性都改变了,当只改变对象的属性时,会在对象的名称空间中创建一个属性的名,然后将修改的值赋值给它
# 类里面的函数是绑定给对象的,也就是说对象是将类的函数复制一份到自己的名称空间中,使用的时候直接调用自己名称空间中的函数,内存地址也各不相同,类里面的函数叫做函数,复制过来的对象里面的函数叫做绑定函数(bound method),实际上在定义类的时候,将函数里面放一个参数(self或者是obj都可以)的目的就是在对象使用函数的时候,将对象当做参数传给类中的函数中的参数self(因为函数中可能会使用到对象的属性),进而调用函数
# 在python中一切皆对象
面向对象的三大特性之封装
封装的实现主要是隐藏属性和开放接口实现的
# 1. 将封装的属性进行隐藏
class Person:
def __init__(self,name,age):
self.name=name
self.__age=age
def __pick(self):
pass
# 经过隐藏的属性和方法在外部是无法访问的(Person.age外面直接访问会报错),但是不是不能访问,Person._Person__age就可以访问隐藏属性(两个person都是类名)
# 这种隐藏实际上就是一种变形,你在定义的时候保存的不是self.__age=age,而是self._Person__age=age,同理方法也是经过了变形,但是这种变形对于用户来说是保密的,相对比较安全,这种隐藏在外部是不能直接访问的,但是在类的内部能够直接访问(方法可以直接使用self.__age)
# 隐藏属性的用途:隐藏数据属性使用户无法会直接查看和修改属性,程序员可以根据需求,用函数开放接口让用户查看属性,(def pick(self):print(self.__name)),程序设计者可以根据需求任意在函数中添加想要的逻辑,对于隐藏函数,可以保护一些关键的功能不被用户使用和发现(比如银行卡的一些操作)
'''
隐藏属性和隐藏函数介绍:
隐藏属性实际上是在函数定义时完成的变形
函数定义时会将定义时前面带有双下划线的属性和函数包装成“_类名__属性”的形式
这种做法在一定程度上隐藏了属性和函数,在外部无法直接访问,但是一旦掌握原理,通过“_类名__属性”还是能够访问到的
实际上在应用时这是一种约定俗成,放你看到下划线定义隐藏属性和函数的时候,记得不要将其进行更改
'''
property装饰器
# 1. property的用法1
class Perple:
def __init__(self,name,weight,height):
self.name=name
self.weight=weight
self.height=height
# bmi是一个体质指数,实际上应该是一个属性,但是需要进行计算
def bmi(self):
return self.weight/(self.height**2)
person1=Perple('dabai',80,170)
print(person1.bmi())
# 下面就将bmi伪装成一个属性,property能够将一个函数伪装成一个属性
@property
def bmi(self):
return self.weight/(self.height**2)
# 这样直接访问person1.bmi能够直接将函数的返回值打印出来,像一个属性一样进行查看
# 2. property的用法2
class People:
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
def set_name(self, val):
if type(val) is not str:
print('必须传入str类型')
return
self.__name = val
def del_name(self):
print('不让删除')
# del self.__name
name=property(get_name,set_name,del_name)
obj1=People('dabai')
print(obj1.name) # 进行查看的功能
obj1.name=18 # 进行修改的功能
del obj1.name # 进行删除的功能
# 3. property的用法3
class People:
def __init__(self, name):
self.__name = name
@property
def name(self): # obj1.name
return self.__name
@name.setter
def name(self, val): # obj1.name='EGON'
if type(val) is not str:
print('必须传入str类型')
return
self.__name = val
@name.deleter
def name(self):
print('不让删除')
obj1=People('dabai')
print(obj1.name) # 进行查看的功能
obj1.name=18 # 进行修改的功能
del obj1.name # 进行删除的功能
静态方法@stasticmethod
- 静态方法是一种非绑定方法,该方法不与类或对象绑定,类与对象都可以来调用它,但它就是一个普通函数而已,因而没有自动传值那么一说
'''
静态方法是直接在类中定义一个方法,这个方法谁都可以使用
class Staticmethod_Demo():
role = 'dog'
@staticmethod
def func():
print("当普通方法用")
Staticmethod_Demo.func()
静态方法主要是用来存放逻辑性的代码,主要是一些逻辑属于类,但是和类本身没有交互
即在静态方法中,不会涉及到类中的方法和属性的操作
可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护
'''

浙公网安备 33010602011771号