java自学教程|www.konglongmei.com

作者: 简单350
查看: 25|回复: 0

more +社区更新Forums

more +随机图赏Gallery

价值6380元 Java高级架构师-互联网企业级实战VIP精品课程视频教价值6380元 Java高级架构师-互联网企业级实战VIP精品课程视频教
Spring 5核心原理与30个类手写实战 PDF 电子书 百度云 网盘下载Spring 5核心原理与30个类手写实战 PDF 电子书 百度云 网盘下载
疯狂Java讲义(第4版) PDF 电子书 百度云 网盘下载疯狂Java讲义(第4版) PDF 电子书 百度云 网盘下载
价值825元 牛客算法通关课程视频教程 第六期 百度云 网盘下载价值825元 牛客算法通关课程视频教程 第六期 百度云 网盘下载
Spring 5核心原理与30个类手写实战+Spring Boot编程思想核心篇pdfSpring 5核心原理与30个类手写实战+Spring Boot编程思想核心篇pdf
Spring Boot编程思想核心篇+Spring 5核心原理与30个类手写实战pdfSpring Boot编程思想核心篇+Spring 5核心原理与30个类手写实战pdf

[技术知识] 03-深入类和对象

[技术知识] 03-深入类和对象

[复制链接]
简单350 | 显示全部楼层 发表于: 2019-12-3 00:16:28
简单350 发表于: 2019-12-3 00:16:28 | 显示全部楼层 |阅读模式
查看: 25|回复: 0

你还没有注册,无法下载本站所有资源,请立即注册!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
一、深入类和对象

1.1、鸭子类型和多态
维基百科中的解释为:
  鸭子类型(英语:duck typing)在程序设计中是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。这个概念的名字来源于由詹姆斯·惠特科姆·莱利提出的鸭子测试,“鸭子测试”可以这样表述:
  “当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型。
  1. class Cat():    def say(self):        print("I am a cat")class Dog():    def say(self):        print("I am a dog")class Duck():    def say(self):        print("I am a duck")animal_list = [Cat,Dog,Duck]for animal in animal_list:    animal().say()#实例化对象,在调用say方法  三个类实现同一个方法名,这就是多态。然后可以将这些类归为一种类型(鸭子类型)                  #python中的魔法函数充分也利用了鸭子类型的特性,可以在任一类中定义name_list = ["list1","list2"]name_list1 = ["love","python"]name_tuple = (3,4)name_set = set()name_set.add(5)name_set.add(6)name_list.extend(name_set)   #参数name_set:['list1', 'list2', 5, 6]参数name_tuple:['list1', 'list2', 3, 4] print(name_list)              # 参数:name_list1:['list1', 'list2', 'love', 'python']"""这里说的是只要传入的参数是一个可迭代的类型就可以,就连我们自定义的类将类的魔法函数__getitem__(返回 )、__iter__就可以变成可迭代的,都可以传入 def extend(self, *args, **kwargs): # real signature unknown        Extend list by appending elements from the iterable.         pass"""#首先这三个类里面都包含了这个say()方法,如果在JAVA里边,要实现多态的话,需要继承父类在覆盖父类的方法实现多态。# 例如:一般情况先定义一个父类Animal,然后这个Animal有一个say()方法。# 然后在写其他类例如上面的Cat类,Cat类继承Animal类,然后重写say()方法。# 然后指定类型实例化这个Cat对象,在python中不需要指定类型,在JAVA中(静态语言)必须指定类型,#这是动态语言和静态语言最大的区别。在python中都要做的一件事就是每个对象下都要写这个say()方法
复制代码
1.2、抽象基类(abc)
  python里边的抽象基类,是不能够实例化的。python是动态语言,动态语言是没有变量的类型的。在python中变量只是一个符号而已,这个符号可以指向任何类型的对象。动态语言缺少编译时检查错误的环境,在python中编写代码是很难发现错误的,只有要运行解释器才能找到错误。这也是动态语言共有的一个缺陷。python信奉的是鸭子类型,鸭子类型贯穿于整个面向对象之中。抽象基类是什么意思?在这个基础的类当中,设定好一些方法,然后所有的继承这个基类的类,都必须覆盖这个抽象基类里面的方法。抽象基类是无法实例化的。
  1. ##################去检查某个类是否有某种方法#############################class Students(object):    def __init__(self,student_list):        self.student = student_list    def __len__(self):        return len(self.student)students = Students(["lishuntao","test","python"])# print(hasattr(students,"__len__"))#True# print(hasattr(students,"__getitem__"))#False##############################判定某个对象的类型#####################################from collections.abc import Sizedprint(isinstance(students,Sized))#True######################利用抽象基类实现接口的 强制规定###########################强制某些子类必须实现某些方法#实现了一个web框架,集成cache(redis,cache,memorychache)#需要设计一个抽象基类,指定子类必须实现某些方法#如何去模拟一个抽象基类呢?class  CacheBase():    def get(self,key):        raise NotImplementedError    def set(self,key,value):        raise NotImplementedError#用户在实现这个抽象基类的子类时候,必须实现这里面的两个方法class RedisCache(CacheBase):    passredis = RedisCache()#redis.get("key")#抛出异常raise NotImplementedError NotImplementedError#但这样做不好,我们需要刚初始化的时候就抛出异常,接下来就换成abc实现个人基类import abcclass Cache1Base(metaclass=abc.ABCMeta):    @abc.abstractmethod    def get(self,key):        pass    @abc.abstractmethod    def set(self,key,value):        passclass RedisCache1(Cache1Base):    passredis_cache1 = RedisCache1() #TypeError: Can't instantiate abstract class RedisCache1 with abstract methods get, set#利用抽象基类直接初始化抛出异常#在python当中已经实现了一些通用的抽象基类,放在from collections.abc import *
复制代码
  抽象基类不是用来继承的,它只是利用抽象基类来理解继承之间的关系,以及接口的定义,我们去使用的时候一定要用我们的鸭子类型,如果一定要用接口的话,那么推荐使用mixin多继承的方式去实现它。抽象基类使用的时候设计过度,反而不容易理解它。
1.3、isinstance和type的区别
  1. class A:    passclass B(A):    passb = B()print(isinstance(b,B)) #Trueprint(isinstance(b,A)) #Trueprint(type(b) is B) #True   is与==的区别,==判断值是否相等,is判断是不是同一个对象(id(b)地址是否一样)print(type(b),A) #False  ###########判断类型:为什么更推荐用isinstance而不是type?###############因为如果判断某个对象的类型的话,用isinstance会根据树的形状去搜索,从叶子搜索到跟就可以判断是否是相同类型,#就算是不同对象可能是相同类型,然而type是同种类型,但不同对象。
复制代码
1.4、类变量和实例变量
  1. class A:    a = 1 #a是类变量    def __init__(self,x,y):#self是类的实例 x与y已经绑定到实例上的属性上了        self.x = x        self.y = ynum = A(2,3)# A.a = 11   #如果修改类属性,那么实例的值也会跟着变# num.a = 100  #如果修改实例属性,那么类属性的值不变,# 会在对象中新建一个实例属性的值,寻找的时候直接对象属性中寻找。print(num.x,num.y,num.a) #2 3 1  为什么实例num能够找到A的类属性呢,# 首先实例num先在实例属性种寻找,如果没有找到的话就会向上寻找,找到类属性print(A.a) # 1 类属性print(A.x)#AttributeError: type object 'A' has no attribute 'x'#类找实例属性找不到是因为类首先到自己的属性中找,如果没有找到的话,就不会向下寻找
复制代码
1.5、类和实例属性的查找顺序----mro查找
类查找属性的查找顺序有深度优先查找广度优先查找
广度优先查找:
  1. #python3以后称为新式类,全部都继承objectclass D:    passclass C(D):    passclass B(D):    passclass A(B,C):    passprint(A.__mro__) #(, , , , )#__mro__魔法方法直接显示出类查找属性的顺序
复制代码


深度优先查找:
  1. #python3以后称为新式类,全部都继承objectclass E:    passclass D:    passclass C(E):    passclass B(D):    passclass A(B,C):    passprint(A.__mro__)#(, , , , , )
复制代码


  但在python3中为了避免深度优先算法与广度优先算法混乱,出现了C3算法避免了两种算法出现的问题,例如菱形搜索应用深度优先算法,从AB再到D找到方法,可能C中重写了D的方法,因此深度优先算法不能解决菱形搜索的情况,然而C3算法解决了以上出现的两种情况。
1.6、类方法、静态方法和实例方法
[code]class Date:    def __init__(self,year,month,day):        self.year = year        self.month = month        self.day = day    #静态方法的缺点就是硬编码,如果换类名又要重新改返回的类名    @staticmethod    def parse_from_string(date_str):        year,month,day = tuple(date_str.split("-"))        return Date(int(year),int(month),int(day))    #为啥不用classmethod替换staticmethod呢?    #检查时间格式是否正确,不需要对象返回回来,因此这个时候它就有用了,而其余都是要将对象返回回来    @staticmethod    def valid_str(date_str):        year, month, day = tuple(date_str.split("-"))        if int(year)>0 and (int(month)>0 and int(month)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|网站地图|java自学教程|www.konglongmei.com

GMT+8, 2019-12-14 12:43 , Processed in 0.083488 second(s), 27 queries .

快速回复 返回顶部 返回列表