python之类的多态(鸭子类型 )、封装和内置函数property
一、多态
1、什么是多态:一个类表现出的多种状态--->通过继承来实现的
例如:
class Animal:pass
class Dog(Animal):pass
class Cat(Animal):pass
Animal类表现出了Dog,Cat两种形态
好了,多态就是这样,结束...
哈哈,有没看懂的吧,那么我们一步一步来解释:
首先我们来看:
s = 'abc'
print(type(s))   # <class 'str'>
s = 'abc' 我们都知道s就是一个str类型,在python中一切皆对象,其实你打开源码可以看到str是一个类,
它在源码中是这样定义的:class str(object): ...   
而我们定义一个变量的时候s = 'abc'  ,它在内部是进行了一个这样的转换:s = str('abc')
刚才说了str是一个类,那str()就是实例化 , str('abc')就是把参数'abc'传进去初始化一个对象,那么s就是一个str类的对象,s的type就是str,
也就是说其实我们平时定义的变量都是对象,例如:
a = 10  是一个int类的对象
b = [1,2,3]  是一个list类的对象等等
那么我们自己定义的类也是一样的:
class A:
      pass
a = A() 
print(type(a))       # 对象a的数据类型就是A
2、我们引用一下java中的例子再来了解一下(假设下面是java代码)
class ApplePay:
def pay(self):
pass 在java中,参数是要指定类型的,其他类型的数据是不能传进去的,这里指定了是ApplePay类型
def My_pay(ApplePay obj,int money):
obj.pay() app = ApplePay() # app是ApplePay类的对象,所以app就是ApplePay类型的数据
My_pay(app,100) 这么一看,好像没什么问题,但是这么写的话,这个My_pay函数只能给ApplePay类使用了,其他类就不能使用了,
扩展性很差,那么这个时候就需要多态了,且看下面例子: class Payment: # 首先定义一个父类
pass class ApplePay(Payment): #每个子类都继承父类
def pay(self):
pass class Alipay(Payment): #每个子类都继承父类
def pay(self):
pass #这里obj类型写父类的类型Payment,因为子类继承父类,也继承了父类的类型
def My_pay(Payment obj,int money):
obj.pay() app = ApplePay() # 这里app既是ApplePay类型,也是Payment类型
My_pay(app,100) alp = Alipay() # 这里alp既是Alipay类型,也是Payment类型
My_pay(alp,200) 这样利用多态就解决了参数类型的问题
3、总结(为什么在python中,我们写的函数都不用指定类型?)
1,
在java中:多态用来解决传参数的时候数据类型的规范问题。
在java中的表现 : 在一个函数中需要给参数指定数据类型,如果这个地方可以接收两个以上类型的参数,
那么这些类型应该有一个父类,这个父类是所有子类对象的类型
2,
在python中:函数的参数不需要指定数据类型,我们也不需要通过继承的形式来统一数据类型,
因为python中所有的对象都继承了object类,所以都是object类型,因此在python当中处处都是多态。
4、鸭子类型(拓展)
定义:
不是明确的通过继承实现的多态,
而是通过一个模糊的概念来判断这个函数能不能接收这个类型的参数
例如:
def func(arg):
arg.send()
# 对应参数arg,我们没有明确地表明这是什么类型的参数,arg可以是任意的,但是它必须有send方法,因此判断只要是一个类,类中有send方法,就可以作为这个函数的参数
二、封装
1、定义:
	  广义上的封装:把属性和函数都放到类里
	  狭义上的封装:定义私有成员
1,广义上的封装:
class 类名:
      def 方法1(self):pass
是为了只有这个类的对象才能使用定义在类中的方法
2,狭义上的封装:   __属性名      __方法名
把一个属性(方法)藏在类中 
class Goods:
      __discount = 0.7         # 私有的静态变量
print(Goods.__discount) # 报错
在类的外部不能引用私有的静态变量
class Goods:
      __discount = 0.7    # 私有的静态变量
	  print(__discount)    # 类内部打印输入
程序一执行就打印出0.7
因为:
类中的静态变量和方法名在程序加载的过程中就已经执行完了,不需要等待调用
在这个类加载完成之前,Goods这个名字还没有出现在内存空间中
私有的静态属性可以在类的内部使用,用来隐藏某个变量的值
3,变形
其实用双下划线定义好一个私有变量后,python会自动把这个私有变量进行一个变形,例如私有变量__discount,变形如下:
__discount          --->        _Goods__discount
也就是:
__私有变量        --->        _类名__私有变量
class Goods:
      __discount = 0.7    # 私有的静态变量
print(Goods.__dict__)        # 查看Goods类的所有属性和方法可以看到里面有个变量_Goods__discount的值是0.7
print(Goods._Goods__discount)  # 可以看到0.7  但从编程规范的角度上出发 我们不能在类的外部使用私有的变量
2、
类中的私有成员:
      1,私有的静态属性
      2,私有的对象属性
      3,私有的方法
为什么要定义一个私有变量呢:
      1,不想让你修改这个值
      2,不想让你看到这个值
      3,想让你在修改这个值得时候有一些限制
      4,有些方法或者属性不希望被子类继承
话不多说,请看例子理解
例1:私有的静态属性、不想让你修改这个值
class Student:
def __init__(self,name,age):
self.__name = name # 设置了一个私有变量__name用来储存学生的名字
self.age = age
def name(self): # 因为私有变量在外部不能引用,所有设置一个方法用来打印学生的名字
return self.__name xiaoming = Student('xiaoming',18)
print(xiaoming.age) #
print(xiaoming.name()) # xiaoming xiaoming.age = 28
print(xiaoming.age) # xiaoming.name = 'xiaogou' #这里只是为这个对象新增了一个属性name,并没有修改原本的__name
print(xiaoming.name()) #报错
那么肯定会有人问,这样做确实不能修改__name,但是别人可以新增name啊,而且__name还要用name()这样才能显示,多麻烦。
好,这个问题等下在后面的内容会给你解决,现在你只要明确地知道你一开始传进去的学生名字__name是修改不了就行了。
例2:私有的静态属性、修改的时候有限制
class Goods:
__discount = 0.7 # 私有的静态变量
def __init__(self,name,price):
self.name = name
self.__price = price def price(self): #折扣价
return self.__price * Goods.__discount def change_price(self,new_price):
if type(new_price) is int:
self.__price = new_price
else:
print('本次价格修改不成功') apple = Goods('苹果',5)
print(apple.price()) apple.change_price(6)
print(apple.price())
例3:私有的对象属性、不想让你看到这个值(通过算法把密码变成密文的形式)
class User:
def __init__(self,username,password):
self.username = username
self.__pwd = password
self.pwd = self.__getpwd() def __getpwd(self): # 把密码转换成哈希值
return hash(self.__pwd) obj = User('xiaoming','') # 用户名:xiaoming 密码: 123456
print(obj.username,obj.pwd) # 用户名:xiaoming 密码的密文:-1675187800842546722
3、私有变量能不能在外部被定义?(不能)
class A:
__country = 'China' print(A.__dict__) A.__Language = 'Chinese' # 其实这里只是定义了一个名为__Language的属性,并不是私有变量
print(A.__dict__)
4、私有变量能不能被继承?(可以)
class A:
__country = 'China' # __country 就是 _A__country
def __init__(self,name):
self.__name = name # __name 就是 _A__name 继承A的B类的对象初始化的时候 self.__name 就是
# self._A__name
# 此时为self._A__name赋值,并没有形成self的私有变量
# 而本身的A类对象初识化的时候,为self.__name赋值,会形成self的私有变量 class B(A): def get_country(self):
print(__country) # 报错:name '_B__country' is not defined
print(B._A__country) # China def get_name(self):
return self.__name # 报错:'B' object has no attribute '_B__name' b = B('xiaoming')
b.get_country()
print(b.get_name())
print(b.__dict__) # {'_A__name': 'xiaoming'}
总结:
子类可以继承父类的所有属性(包括私有属性)和方法,但是继承的私有属性是变形后的形式,在子类中不再是私有属性,
在子类中用 __私有属性名 是找不到继承的私有属性的 因为它会默认去找自己类中的私有属性,
要想调用父类的私有属性则应该用变形后的变量 _父类名__变量名
三、内置函数property
1、
装饰器的分类:
      装饰函数:
      装饰方法 : property
      装饰类:
装饰器函数都怎么用:
在函数、方法、类的上面一行直接@装饰器的名字
2、property是一个装饰器函数(就是用来解决刚才私有属性的问题)
property:将一个方法伪装成一个属性
2-1学生信息中,姓名不想给别人修改,就设置为私有属性,在定义一个同名的方法伪装成属性,便于查找
class Student:
def __init__(self,name,age):
self.__name = name
self.age = age @property
def name(self): # 声明了@property使用此方法的时候就可以不写括号,就伪装成了属性
return self.__name xiaoming = Student('小明',18)
print(xiaoming.name) # 小明 xiaoming.name = '小狗' # 改:报错
print(xiaoming.name)
2-2圆的半径可以修改,但是面积和周长应该是属性的形式比较正确,但是直接设置为属性,圆的半径改了后,
周长和面积并不会改变
class Circle:
def __init__(self,r):
self.r = r
self.area = 3.14 * self.r ** 2
self.perimeter = 2 * 3.14 * self.r
c = Circle(6)
print(c.area) # 113.04
print(c.perimeter) # 37.68 c.r = 3 # 改变了半径
print(c.area) # 113.04
print(c.perimeter) # 37.68
2-3因此上面的圆可以写成这样:
class Circle:
def __init__(self,r):
self.r = r @property
def area(self):
return 3.14 * self.r ** 2 @property
def perimeter(self):
return 2 * 3.14 * self.r c = Circle(6)
print(c.area) # 113.04
print(c.perimeter) # 37.68 c.r = 3 # 改变了半径
print(c.area) # 28.26
print(c.perimeter) # 18.84
python之类的多态(鸭子类型 )、封装和内置函数property的更多相关文章
- Python【map、reduce、filter】内置函数使用说明(转载)
		
转自:http://www.blogjava.net/vagasnail/articles/301140.html?opt=admin 介绍下Python 中 map,reduce,和filter 内 ...
 - Python【map、reduce、filter】内置函数使用说明
		
题记 介绍下Python 中 map,reduce,和filter 内置函数的方法 一:map map(...) map(function, sequence[, sequence, ...]) -& ...
 - day30 继承、派生与多态,类中方法和内置函数
		
目录 一.多继承出现的问题(mixins机制) 二.派生与方法重用 三.多态 1 什么是多态 2 为什么要有多态 3 python中多态的鸭子类型 四.绑定方法与非绑定方法 1 绑定方法 1.1对象的 ...
 - python部落刷题宝学到的内置函数
		
最近加入了python部落,感觉里面的刷题宝很有意思,玩了一下,知道了许多以前并不清楚的内置函数,然后感觉到快要记不住了,所以开始陈列一下 1.divmod(a,b):取a除以b的商和余数,功效等价于 ...
 - python入门(二):isinstance、内置函数、常用运算等
		
1. isinstance(变量名,类型) #判断什么类型 ps: 只支持输入两个参数,输入3个参数会报错 >>> isin ...
 - python中的运算符及表达式及常用内置函数
		
知识内容: 1.运算符与表达式 2.for\while初步了解 3.常用内置函数 一.运算符与表达式 python与其他语言一样支持大多数算数运算符.关系运算符.逻辑运算符以及位运算符,并且有和大多数 ...
 - python 基础篇 14 程程器表达式 内置函数
		
昨日内容回顾 可迭代对象: 内部含有__iter__方法的就是可迭代对象. 可迭代对象不能取值,因为内部不含有__next__方法. 可迭代对象 ---> ...
 - Python中生成器,迭代器,以及一些常用的内置函数.
		
知识点总结 生成器 生成器的本质就是迭代器. 迭代器:Python中提供的已经写好的工具或者通过数据转化得来的. 生成器:需要我们自己用Python代码构建的 创建生成器的三种方法: 通过生成器函数 ...
 - Python语法速查: 1. 数据类型与内置函数
		
返回目录 (1)常用内置数据类型 分类 类型名称 描述 数字 int 整数 float 浮点数 complex 复数 bool 布尔值 序列 str 字符串(不可变序列) list 列表 tuple ...
 
随机推荐
- js数组方法大全
			
JavaScript中创建数组有两种方式 (一)使用 Array 构造函数: var arr1 = new Array(); //创建一个空数组var arr2 = new Array(20); // ...
 - java泛型-泛型类,泛型接口,常用形式
			
泛型简单使用: package com.etc; import java.util.ArrayList; import java.util.List; /* 泛型就相当于<>一个标签,泛化 ...
 - 林业有害生物监测系统(重庆宇创GIS)
			
本文由重庆宇创GIS团队原创,转载请注明来源http://www.cnblogs.com/ycdigit/p/8916073.html 一.概述 林业有害生物监测信息平台(森林病虫害监测预警系统) ...
 - 如何在WIN10内置Ubuntu中有多个terminal
			
使用的是tmux来实现在WIN10的内置Ubuntu实现多终端窗口 先安装tmux:sudo apt-get install tumx 启动tmux,tmux 然后就可以在tmux中实现多窗口.其操作 ...
 - QT 启动shell脚本
			
1.QProcess *p = new QProcess(this); 2.QString str = qApp->applicationDirPath() + "/update.sh ...
 - 导致spring事务配置不起作用的一种原因
			
@Component public class AnalyticsApplication { @Autowired private InitializationActionService initia ...
 - Chrome浏览器清除缓存
			
1.功能列表点击历史记录 可以是按时间清除 自动清除: 使用谷歌的无痕模式可以自动清除缓存
 - git add 添加多个文件
			
在使用git add提交多个文件的方式: git add . 后面加一个".",匹配所有的文件 总结下,提交多个文件时,git add后可以有如下参数以及参数的解释: git ...
 - 英语进阶系列-A04-英语升级练习二
			
古诗背诵 要求:背诵和朗读,然后翻译成现代文,并绘制图像描述图中的内容,同时看看某些内容可以用什么单词替换,时间限制到15 minutes. 速记词汇系列 要求:将词汇快速朗读并记忆,时间为8 min ...
 - 上传本地文件到GitHub上
			
问题解决 今天在windows上上传本地文件到github,出现用户名和仓库不匹配的情况,解决方式如下: 打开控制面板,选择用户账户 把该删除的账户删除一下就行了. 上传文件的步骤如下: 将上传的文件 ...