面向对象之封装

含义

将类中的某些名字按照特殊的书写方式"隐藏"起来,不让外界直接调用,目的是为了不然外界可以直接修改类中的名字,而是提供专门的通道去访问,在通道内可以添加额外的功能。

实现

在类中可以使用双下划线开头(__)的命名方式来实现封装效果。

class A:
# 使用双下划线开头
__name = 'from A'
print(A.__name) # 报错,显示找不到"__name"

类中的名字进行封装后就无法直接调用了,实际上,"__name"被变形成了"_A__name",就是"__名称"变成了"_类名__名称"。

我们可以调用__dict__查看类中的名称空间

print(A.__dict__)

结果

{'__module__': '__main__', '_A__name': 'from A', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}

类A中的名称空间多了一个'_A__name': 'from A'键值对,这个就是封装的结果,我们可以直接用A._A__name的方式获取到类中__name的值,但并不推荐这样使用。

一般情况下,我们封装的目的就是为了不让外界直接可以获取或者修改名称的值,而是提供一个接口(函数)让外界去获取或者修改值。

class A:
# 封装
__name = 'from A'
# 提供接口
def get(self):
return self.__name
obj = A()
print(obj.get()) # 输出:from A

实际应用

class Student:
def __init__(self, name, age):
self.__name = name
self.__age = age # 访问学生数据的通道(接口)
def get_info(self):
print("学生姓名:%s 学生年龄:%s" % (self.__name, self.__age)) # 专门开设一个修改学生数据的通道(接口)
def change_info(self, name, age):
if len(name) == 0:
print('用户名不能为空')
return
if not isinstance(age, int):
print('年龄必须是数字')
return
self.__name = name
self.__age = age stu1 = Student('tom', 18)
stu1.get_info() # 输出:学生姓名:tom 学生年龄:18
stu1.change_info('jason', 28)
stu1.get_info() # 输出:学生姓名:jason 学生年龄:28
stu1.change_info('', 'haha') # 输出:用户名不能为空

@property

@property的作用就是可以将方法伪装成数据,比如一个方法需要加上括号才可以调用,但是加了@property后不用加括号就调用了。

class A:
def __init__(self, name):
self.name = name
@property
def get_name(self):
return self.name
obj = A('tom')
print('name = %s' % obj.get_name) # 输出:name = tom

面向对象之多态

含义

多态指的是一类事物有多种形态,比如动物有多种形态:猫、狗、猪,水有多种形态:固态、液态、气态。

代码展示

# 动物类
class Animal:
def speak(self):
pass
# 动物之一:猫
class Cat(Animal):
def speak(self):
print('喵喵喵')
# 动物之一:狗
class Dog(Animal):
def speak(self):
print('汪汪汪')
# 动物之一:猪
class Pig(Animal):
def speak(self):
print('哼哼哼')
# 实例化
cat = Cat()
dog = Dog()
pig = Pig()
#
cat.speak()
dog.speak()
pig.speak()

以上代码体现的就是面向对象的多态特性,狗、猫、猪都是属于动物,那么它们就应该有一个共同的speak方法。

此外,我们还可以在定义一个函数让它更加灵活。

def speak(animal):
animal.speak()
speak(cat)
speak(dog)
speak(pig)

其实在很早之前我们就已经接触过面向对象的多态性了,比如str、list、dict数据类型都有一个共同的方法len。

# 多态性
s1 = 'hello world'
l1 = [1, 2, 3, 4]
d1 = {'name': 'jason', 'pwd': 123}
print(len(s1))
print(len(l1))
print(len(d1))

多态性的好处在于增强了程序的灵活性和可扩展性,比如通过继承Animal类创建了一个新的类,实例化得到的对象obj,可以使用相同的方式使用obj.speak()。

强制多态

python在面向对象中提供了强制性的措施来实现多态性,但不推荐使用。

强制多态需要导入abc模块。

import abc
# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
def talk(self): # 抽象方法中无需实现具体的功能
pass
class Person(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
def talk(self):
pass
p1=Person() # 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化

多态衍生

由多态性衍生出一个鸭子类型理论:只要你看着像鸭子,走路像鸭子,说话像鸭子,那么你就是鸭子!

class Txt: #Txt类有两个与文件类型同名的方法,即read和write
def read(self):
pass
def write(self):
pass class Disk: #Disk类也有两个与文件类型同名的方法:read和write
def read(self):
pass
def write(self):
pass

这两个类看起来都像文件,因而就可以当文件一样去用,然而它们并没有直接的关系,但它们属于鸭子类型。

面向对象之反射

含义

专业解释:指程序可以访问、检测和修改本身状态或者行为的一种能力。

大白话:其实就是通过字符串来操作对象的数据和功能。

反射的四个方法

  • hasattr(object, str):判断对象是否含有字符串对应的数据或者功能
  • getattr(object, str):根据字符串获取对应的变量名或者函数名
  • setattr(object, key, value):根据字符串给对象设置键值对(名称空间中的名字)
  • delattr(object, str):根据字符串删除对象对应的键值对(名称空间中的名字)

实际应用

class Student:
school = '清华大学'
def get(self):
pass

hasattr(object, str):判断对象是否含有字符串对应的数据或者功能

obj = Student()
print(hasattr(obj, 'school')) # 输出:True
print(hasattr(obj, 'get')) # 输出:True
print(hasattr(obj, 'abc')) # 输出:False

getattr(object, str):根据字符串获取对应的变量名或者函数名

obj = Student()
print(getattr(obj, 'school')) # 输出:清华大学
print(getattr(obj, 'abc')) # 报错,类中没有abc的名称

setattr(object, key, value):根据字符串给对象设置键值对(名称空间中的名字)

obj = Student()
setattr(obj, 'name', 'tom')
print(obj.__dict__) # 输出:{'name': 'tom'}
print(obj.name) # 输出:tom

delattr(object, str):根据字符串删除对象对应的键值对(名称空间中的名字)

obj = Student()
setattr(obj, 'name', 'tom')
print(obj.__dict__) # 输出:{'name': 'tom'}
delattr(obj, 'name')
print(obj.__dict__) # 输出:{}

反射的应用场景

以后只要在业务中看到关键字:对象、字符串(用户输入、自定义、指定),那么肯定用反射。

比如如果我想要调用对象中的某个数据或者功能,但是我只能获取那个数据或功能的名称的字符串形式,这个时候就需要用到反射了。

实际案例

实现一个根据用户输入的指令不同,执行的功能不同

class FtpServer:
def serve_forever(self):
while True:
inp = input('input your cmd>>: ').strip()
cmd, file = inp.split()
if hasattr(self, cmd): # 根据用户输入的cmd,判断对象self有无对应的方法属性
func = getattr(self, cmd) # 根据字符串cmd,获取对象self对应的方法属性
func(file) def get(self, file):
print('Downloading %s...' % file) def put(self, file):
print('Uploading %s...' % file) obj = FtpServer()
obj.serve_forever()

input

get a.py

output

Downloading a.py...

input

put a.py

output

Uploading a.py...

python面向对象(封装、多态、反射)的更多相关文章

  1. python面向对象(封装,继承,多态)

    python面向对象(封装,继承,多态) 学习完本篇,你将会深入掌握 如何封装一个优雅的借口 python是如何实现继承 python的多态 封装 含义: 1.把对象的属性和方法结合成一个独立的单位, ...

  2. python 面向对象编程 之 反射

    1 什么是反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被 ...

  3. Python 面向对象 组合-多态与多态性-封装-property

    面向对象-组合 1.什么是组合 组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象 class Foo: xxx = 111 class Bar: yyy = 222 obj = Foo( ...

  4. python面向对象-封装and多态

    python 接口类和抽象类 为什么讲封装之前要将这个东西? 我才不会说为什么 首先: python没有接口类这个概念!!!!!!!! 哈哈哈......神经病 python抽象类和接口类更接近于一种 ...

  5. Python面向对象之多态

    多态 面向对象三大特性 封装 根据职责将属性和方法封装到一个抽象的类中:--定义类的准则 继承 实现代码的重用,相同的代码不需要重复的编写:--设计类的技巧:子类针对自己的需求,编写特定的代码: 多态 ...

  6. python 面向对象之多态与绑定方法

    多态与多态性 一,多态 1,多态指的是一类事物有多种形态(python里面原生多态) 1.1动物有多种形态:人,狗,猪 import abc class Animal(metaclass=abc.AB ...

  7. Python 面向对象5 多态

    一.多态 多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作,简单的说就是一句话:允许将 ...

  8. python面向对象封装案例(附:is和==的区别)

    面向对象封装案例 目标 封装 小明爱跑步 存放家具 01. 封装 封装 是面向对象编程的一大特点 面向对象编程的 第一步 —— 将 属性 和 方法 封装 到一个抽象的 类 中 外界 使用 类 创建 对 ...

  9. python面向对象-封装-property-接口-抽象-鸭子类型-03

    封装 什么是封装: # 将复杂的丑陋的隐私的细节隐藏到内部,对外提供简单的使用接口 或 # 对外隐藏内部实现细节,并提供访问的接口 为什么需要封装 1.为了保证关键数据的安全性 2.对外部隐藏内部的实 ...

随机推荐

  1. ubantu系统之 在当前文件夹打开终端

    直接安装一个软件包 "nautilus-open-terminal"终端输入:sudo apt-get install nautilus-open-terminal重启系统!

  2. JSDOM基础

    JavaScript 通过 HTML DOM,可访问 JavaScript HTML 文档的所有元素. HTML DOM 模型被构造为对象的树: HTML DOM 树 JavaScript 能够改变页 ...

  3. eclipse 执行main方法 错误: 找不到或无法加载主类

    检查环境变量是否正确 JAVA_HOME JAVA的实际安装目录 CLASSPATH .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\ ...

  4. 帝国CMS如何互相转移分表之间的数据

    最近发现帝国CMS文章数据添加太多到某一张分表中了,如图 这是极其不合理的,需要优化下,所以这篇文章要告诉大家的也就是如何互相转移分表之间的数据. 我现在要将:phome_ecms_news_data ...

  5. Python 速通爆肝、列表推导式、生成器、装饰器、生命游戏

    列表推导式.赋值.切片(替换.插入).字符串处理与判断.enumerate().格式化字符串.读写文件.global 关键字.字符串startswith().类与对象.生成器.装饰器.Self.*ar ...

  6. Spring Cloud之负载均衡组件Ribbon原理分析

    目录 前言 一个问题引发的思考 Ribbon的简单使用 Ribbon 原理分析 @LoadBalanced 注解 @Qualifier注解 LoadBalancerAutoConfiguration ...

  7. Java语言学习day10--7月9日

    ###09方法的重载 * A: 方法的重载 * 在同一个类中,方法名相同,参数列表不同.与返回值类型无关. * 参数列表不同: * A:参数个数不同 * B:参数类型不同 * C:参数的顺序不同(算重 ...

  8. 阿里巴巴稀疏模型训练引擎-DeepRec

    导读:DeepRec从2016年起深耕至今,支持了淘宝搜索.推荐.广告等核心业务,沉淀了大量优化的算子.图优化.Runtime优化.编译优化以及高性能分布式训练框架,在稀疏模型的训练方面有着优异性能的 ...

  9. Day 003:PAT练习--1041 考试座位号 (15 分)

    题目要求: 我写的代码如下: //考试座位号 #include<iostream> #include<algorithm> #include<string> usi ...

  10. python学习-Day24

    目录 今日内容详细 主菜 : ATM+购物车作业 项目开发流程 需求分析 架构设计 分组开发 项目测试 交付上线 需求分析 提炼项目功能 项目大致技术栈 架构设计 编程历经过程 三层架构 将ATM分为 ...