python全栈学习记录(二十二)多态性、封装、绑定方法与非绑定方法

news/2024/10/9 0:32:22 标签: python, 学习

多态性、封装、绑定方法与非绑定方法

文章目录

  • 多态性、封装、绑定方法与非绑定方法
  • 一、多态性
  • 二、封装
  • 三、绑定方法与非绑定方法

一、多态性

多态指的是同一种事物的多种形态,如水:冰、水蒸气、液态水,又如动物:猫、狗、猪。
多态性是指不考虑对象类型的情况下直接使用对象的方法,这就要求设计者把对象的方法统一为一种,例如:

python">#猫狗猪都是可以叫,那就可以使用一个接口来调用叫这个功能
class Aminal():
	pass
	
class Cat(Aminal):
	def talk(self):
		print('喵喵喵')

class Dog(Aminal):
	def talk(self):
		print('汪汪汪')

class Pig(Aminal):
	def talk(self):
		print('哼哼哼')

#接口函数
def talk(aminal):
	aminal.talk()

c=Cat()
d=Dog()
p=Pig()
talk(c)
talk(d)
talk(p)
<<<喵喵喵
<<<汪汪汪
<<<哼哼哼

python本身也是支持多态性的,len函数就是对多种容器类型封装的接口函数,所以使用len函数时只需要将容器的实例传入就可以得到容器的长度值。

由上面的例子我们可以知道多态性的本质就是在不同的类型中定义相同的方法,这样就可以不考虑具体的类型直接调用统一的方法了。
python中还可以使用抽象类来实现多态性。

python">import abc

# Animal是抽象类,用来指定子类的标准,不能被实例化
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod #这个装饰器用来约束子类必须定义speak方法
    def speak(self):
        pass       

class People(Animal):
	#继承抽象类的子类不定义speak方法时会报错
    def speak(self):
        print('say hello')

class Dog(Animal):
    def speak(self):
        print('汪汪汪')

p=People()
d=Dog()
p.speak()
d.speak()
<<<say hello
<<<汪汪汪

python中还存在一种名为鸭子类型的规范,也就是叫的声音像鸭子,并且你走路的样子也像鸭子,那你就是鸭子。

python">class Disk:
    def read(self):
        print('disk read')

    def write(self):
        print('disk wirte')


class Process:
    def read(self):
        print('process read')

    def write(self):
        print('process wirte')


class File:
    def read(self):
        print('file read')

    def write(self):
        print('file wirte')

上述代码定义了三个类型鸭子、管道、文件,虽然这三者之间没有任何的联系,但是他们都有read和write方法,所以可以将他们都视为文件类型来使用。通过这种约定式的方式实现多态可以减少程序的耦合度。

二、封装

封指属性对外是隐藏的,但对内是开放的。装指申请一个名称空间,往里装入一系列名字/属性。所以封装指使用类存放一系列属性方法,并且这些属性方法只对类内部开放。

封装属性的目的: 隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口然后让类外部的使用通过接口来间接地操作隐藏的属性。精髓在于:我们可以在接口之上附加任意逻辑,从而严格控制使用者对属性的操作。

封装方法的目的:隐藏方法是为了不让外不直接使用,需要类内部开辟一个接口然后在接口内去调用隐藏的功能。精髓在于:隔离了复杂度。

python中隐藏属性和方法的方式是在变量前面加上__。但是

  • 这种隐藏仅仅只是一种语法上的变形操作(变量在类定义阶段被修改为_类名__属性/方法)
  • 这种语法上的变形只在类定义阶段发生一次,因为类体代码仅仅只在类定义阶段检测一次
  • 这种隐藏是对外不对内的,即在类的内部可以直接访问,而在类的外则无法直接访问,原因是在类定义阶段,类体内代码统一发生了一次变形
  • 如果不想让子类的方法覆盖父类的,可以将该方法名前加一个__开头
python">class A():
    __a=1
    def __b(self):
    	#类内部可以直接访问隐藏属性
        print(self.__a)

a=A()
print(A.__dict__)
#在类外部可以通过_类名__属性/方法的方式访问
a._A__b()
#类外部加入的__属性不会再次改名
a.__c=2
print(a.__dict__)
<<< {...,'_A__a': 1, '_A__b': <function A.__b at 0x0000018C8E8E9160>,...}
<<<1
<<< {'__c': 2}

将属性隐藏起来的目的是通过设置相应的接口来限制用户对隐藏属性的修改。

python">#控制名字的输入
class TellName():
    def __init__(self,name):
        self.__tell_name(name)
        self.__name=name

    def __tell_name(self,name):
        if not isinstance(name,str): #判断name是否为str类型的对象
            raise TypeError('姓名必须为字符串') #抛出TypeError('姓名必须为字符串')的报错信息
        
    def check_name(self):
        print(self.__name)

t=TellName(111)
<<< TypeError: 姓名必须为字符串

t=TellName('李四')
t.check_name()
<<<李四

将方法隐藏起来的目的是为了减少复杂度。

python">class Atm():
	def __card(self):
		pass
	def __auth(self):
		pass
	def __input(self):
		pass
	def __take_money(self):
		pass
	def withdraw(self):
		self.__card()
		self.__auth()
		self.__input()
		self.__take_money()

a=Atm()
a.withdraw()

上述代码只需要在类外调用withdraw方法就可以完成整个取款流程了,大大降低了操作的复杂度。

python中property装饰器用于将被装饰的方法伪装成一个数据属性,在使用时可以不用加括号而直接引用。

python">class People:
    def __init__(self,name):
        self.__name=name

    @property #伪装成obj.name
    def name(self):
    	#返回值就是伪装的obj.name的值
        return '<名字是:%s>' %self.__name

    @name.setter #伪装name的修改方式obj.name=值
    def name(self,name):
        if type(name) is not str:
            raise TypeError('名字必须是str类型')
        self.__name=name

    @name.deleter #伪装name的删除方式del obj.name
    def name(self):
        del self.__name

peo1=People('111')
print(peo1.name)
peo1.name='222'
print(peo1.name)
del peo1.name
print(peo1.name)

<<< <名字是:111>
<<< <名字是:222>
<<< AttributeError: 'People' object has no attribute '_People__name'

三、绑定方法与非绑定方法

绑定方法:绑定给谁就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入
绑定方法分为两类:

  • 绑定给对象方法:在类内部定义的函数(没有被任何装饰器修饰的),默认就是绑定给对象用的
  • 绑定给类的方法:在类内部定义的函数如果被装饰器@classmethod装饰,那么则是绑定给类的,应该由类来调用,类来调用就自动将类当作第一个参数自动传入。

非绑定方法:类中定义的函数如果被装饰器@staticmethod装饰,那么该函数就变成非绑定方法,既不与类绑定,又不与对象绑定,意味着类与对象都可以来调用,但是无论谁来调用,都没有任何自动传值的效果,就是一个普通函数。

python">class Mysql:
    def __init__(self, ip):
        self.ip=ip
	
	#绑定给对象的方法,第一个值为self,默认是给对象调用的
    def tell_info(self):
        print('%s'%self.ip)
	
	#绑定给类的方法,第一个值为cls,默认是给类调用的
    @classmethod
    def from_conf(cls):
    	#cls就是Mysql,cls('127.0.0.1')这是一种在类内部完成实例化的方式
        return cls('127.0.0.1')
	
	#不绑定的方法,对象和类都可以调用
    @staticmethod
    def func():
        print('不与任何人绑定')

m=Mysql('172.30.156.0')
m.tell_info()
#绑定给对象的方法一般都是通过类调用的
#若是通过对象调用m.from_conf().tell_info(),会将对象对应的类传给cls
Mysql.from_conf().tell_info()
m.func()
Mysql.func()

<<<172.30.156.0
<<<127.0.0.1
<<<不与任何人绑定
<<<不与任何人绑定

http://www.niftyadmin.cn/n/5695049.html

相关文章

刷题 二叉树

面试经典 150 题 - 二叉树 104. 二叉树的最大深度 广度优先遍历 class Solution { public:// 广度优先遍历int maxDepth(TreeNode* root) {if (root nullptr) return 0;queue<TreeNode*> que;que.push(root);int result 0;while (!que.empty()) {result;int num que…

C++ STL容器(五) —— priority_queue 底层剖析

这篇来讲下 priority_queue&#xff0c;其属于 STL 的容器适配器&#xff0c;容器适配器是在已有容器的基础上修改活泼限制某些数据接口以适应更特定的需求&#xff0c;比如 stack 栈使数据满足后进先出&#xff0c;queue 队列使数据满足先进先出&#xff0c;其都是在已有容器上…

c语言:二叉树的创建、前序遍历、中序遍历、后续遍历

代码中创建的二叉树如下图 013##4##25##6##代码&#xff1a; #include <stdio.h> #include <stdlib.h>typedef struct Tree{int value;struct Tree* lchild;struct Tree* rchild; } Tree;// 创建节点 Tree* Tree_createnode(int value){Tree* node (Tree* )mallo…

别再熬夜赶稿!AI自动成文插图,惊呆我了,效果如何?

今天试了下 Napkin 这个工具&#xff0c;发现简直是做自媒体专业文的写作神器&#xff0c;可以把已经准备好的文章快速配上数据图。 当然也可以一句简单的 prompt 生成文章&#xff0c;然后针对每一段可以生成对应的插图&#xff0c;还在在此基础上进一步调整&#xff0c;太牛了…

【Java 并发编程】多线程安全问题(上)

前言 虽然并发编程让我们的 CPU 核心能够得到充分的使用&#xff0c;程序运行效率更高效。但是也会引发一些问题。比如当进程中有多个并发线程进入一个重要数据的代码块时&#xff0c;在修改数据的过程中&#xff0c;很有可能引发线程安全问题&#xff0c;从而造成数据异常。 p…

『网络游戏』窗口基类【06】

创建脚本&#xff1a;WindowRoot.cs 编写脚本&#xff1a; 修改脚本&#xff1a;LoginWnd.cs 修改脚本&#xff1a;LoadingWnd.cs 修改脚本&#xff1a;ResSvc.cs 修改脚本&#xff1a;LoginSys.cs 运行项目 - 功能不变 本章结束

二维数组的旋转与翻转(C++)(上(这只是简单讲解))

二维数组的旋转与翻转&#xff08;C&#xff09; 引言 在计算机科学中&#xff0c;二维数组是一种常见的数据结构&#xff0c;广泛应用于图像处理、数据挖掘、机器学习等多个领域。二维数组的旋转与翻转是处理二维数据时经常需要用到的操作。本文将详细介绍二维数组的旋转与翻…

101 公司战略的基本概念

公司战略的概念 传统概念&#xff08;战略是终点途径&#xff09;&#xff1a;计划性、全局性、长期性现代概念&#xff08;战略是途径&#xff09;&#xff1a;应变性、竞争性、风险性综合概念&#xff08;前二者的折中&#xff09;&#xff1a;预先性、反应性公司的使命与目标…