python高级编程(3) - 深入类和多态

深入类和多态

一,鸭子类型和多态

  1. 鸭子类型

    当你看到一只鸟走起来想鸭子,游泳起来像鸭子,叫起来像鸭子,那么这只鸟就叫做鸭子类型

    • 我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
    • 我们只关心一个类被不同的魔法函数赋予了不同的特性,我们看他是什么类型,是看他实现了哪些魔法函数,具有哪些特性
    • Java 里面如果要实现一个特点的类型,必须继承一个类,而 python 只需要写几个魔法函数,赋予它那种数据类型的特性就行, 这就是鸭子类型
    • 又比如 list.extend()方法中,我们并不关心它的参数是不是list,只要它是可迭代的,所以它的参数可以是list/tuple/dict/字符串/生成器等.

    例子:比方说我创建了一个类叫狗类,但是我在这个狗类里面定义了一个魔法方法,使他具有鸟的飞行能力,那么我们就称这种为鸭子类型

  2. 多态

    从语言层面上讲就已经是多态的了,背后已经帮我们实现了

    class Cat(object):
        def say(self):
            print('i am a cat')
    
    
    class Dog(object):
        def say(self):
            print('i am a dog')
    
    
    class Duck(object):
        def say(self):
         print('i am a Duck')
    
    • 三个对象都能够实现 say 方法,并且能够打印不同的内容,他们定义的方法是一样的,但功能不一样,多态

二,抽象基类(abc模块)

  • 特点
  1. 在一个基础的类中设定一些特点的方法,所有继承这个抽象基类的子类都必须实现这些方法
  2. 抽象基类不能被实例化
  • 应用
  1. 我们在某些情况下希望判定某个对象的类型

    from collections.abc import Sized
    print(isinstance(com, Sized))
    
    # 我们想判断我们实现的类是不是一个Sized的子类,那么我们必须Sized这个抽象基类的接口
    
  2. 我们需要某个子类必须实现某些方法,比方说设计一个web框架,必须设计一个抽象基类,每个继承的类都必须实现特点的几个接口,以便于用户使用的方便。

    比如数据的存入,要选择不同的数据库,我们不知道用户要用哪种,为了避免日后少改动代码和出错,不许定义一个抽象基类

  • 实现方法
  1. 在调用的时候出错,不正式

    class CacheBase():
        def get(self, key):
            raise NotImplementedError
        def set(self, key, value):
            raise NotImplementedError
    
    c = CacheBase()
    c.set('aa', 'bb')
    ...
    Traceback (most recent call last):
      File "D:/Python/Python笔记/python高级编程和异步IO并发编程/Code/chapter04/abc_text.py", line 50, in <module>
        c.set('aa', 'bb')
      File "D:/Python/Python笔记/python高级编程和异步IO并发编程/Code/chapter04/abc_text.py", line 47, in set
        raise NotImplementedError
    NotImplementedError
    
    # 我们发现上面只有在调用的时候才会出错,在用户创建的时候不会抛出异常
    
  2. 在定义类的时候,就会抛出异常,强制对象一定要实现方法

    import abc
    
    class CacheBase(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
        def get(self, key):
            pass
    
        @abc.abstractmethod
        def set(self, key, value):
            pass
    
    c = CacheBase()
    ...
    Traceback (most recent call last):
      File "D:/Python/Python笔记/python高级编程和异步IO并发编程/Code/chapter04/abc_text.py", line 56, in <module>
        c = CacheBase()
    TypeError: Can't instantiate abstract class CacheBase with abstract methods get, set
    
  • 实际在开发过程中,一般使用鸭子类型,如果一定要使用,建议用多继承的方法去实现
  • 抽象基类设计过度不容易理解他,所以一般是用多继承的方式来

三,isinstance和type的区别

判断一个对象的类型,用 isinstance 而不是 type

class A:
    pass

class B(A):
    pass


b = B()
print('instance 判断b是否属于A类 =>', isinstance(b, A))
print('instance 判断b是否属于B类 =>', isinstance(b, A))
print('type 判断a是否属于A类 =>', type(b) is A)
print('type 判断a是否属于B类 =>', type(b) is B)

使用type is 判断类型会有偏差,因为 is 是判断两个对象的内存地址,不能顾及到继承,所以不推荐

内置的 isinstance 内部会有优化机制,会从对象本身,到继承一层一层忘上找,判断

四,类变量和对象变量

class Dog:
	tall = 20
	
	def __init__(x, y):
		self.x = x
		self.y = y
		
dog = Dog(10, 20)
dog.tall		# 类变量
dog.x			# 实例属性
dog.y			# 实例属性,也叫对象属性

五,类和实例的查找顺序

深度算法和广度算法,C3算法

六,类方法,静态方法,实例方法

class Date():def __init__(self, year, moth, day):
        self.year = year
        self.moth = moth
        self.day = day

    def tomorrow(self):						②
        self.day += 1

    def __str__(self):return '{}/{}/{}'.format(self.year, self.moth, self.day)

if __name__ == '__main__':
    date = Date(2019, 9, 11)
    print(date)

① 我们实现了一个 Date 类,并且这个类实现了三个方法

② 我们自己定义的方法,每个初始化的实例都有这个方法,我们称他为实例方法

③ 打印实例的时候回调用这个方法

如果我们传入的值是一个字符串,在输出之前要对他进行字符创的处理,我们可以使用静态方法

  • 不适用静态方法

    class Date():
    
        def __init__(self, year, moth, day):
            self.year = year
            self.moth = moth
            self.day = day
    
        def tomorrow(self):
            self.day += 1
    
        def __str__(self):
            return '{}/{}/{}'.format(self.year, self.moth, self.day)
    
    if __name__ == '__main__':
        date_str = '2019-12-1'
        year, moth, day = tuple(date_str.split('-'))
        date = Date(year, moth, day)
        print(date)
    

    我们发现,这种方法的使用比较烦,用起来不顺手

  • 使用静态方法 staticmethod

    staticmethod 的用法:把 实例方法 转换成一个函数,就是真正的函数,如果要使用,必须进入类内部

    class Date():
    
        def __init__(self, year, moth, day):
            self.year = year
            self.moth = moth
            self.day = day
    
        def tomorrow(self):
            self.day += 1
    
        @staticmethoddef parse_from_string(string):
            year, moth, day = tuple(string.split('-'))
            return Date(year, moth, day)
        
         @staticmethoddef string_is_date(string):
            year, moth, day = tuple(string.split('-'))
            if len(year) == 4 and len(moth) == 2 and day == 2:
                return True
            else:
                return False
    
        def __str__(self):
            return '{}/{}/{}'.format(self.year, self.moth, self.day)
    
        
    if __name__ == '__main__':
        date_str = '2019-12-1'
        date = Date.parse_from_string(date_str)
        print(date)
    

    staticmethod 的用法不在这里,这里只是演示他能实现这个功能,如果涉及和类实例相关,用classmethod

    ② 这里介绍了staticmethod 方法的主要用法

    classmethod 的用法:把第一个参数变成类对象本身,方便我们在实例之前,对数据进行处理,返回实例

    class Date():
    
        def __init__(self, year, moth, day):
            self.year = year
            self.moth = moth
            self.day = day
    
        def tomorrow(self):
            self.day += 1
    
        @classmethod
        def parse_from_string(cls, string):
            year, moth, day = tuple(string.split('-'))
            return cls(year, moth, day)
    
        def __str__(self):
            return '{}/{}/{}'.format(self.year, self.moth, self.day)
    
    if __name__ == '__main__':
        date_str = '2019-12-1'
        date = Date.parse_from_string(date_str)
        print(date)
    

六,数据封装和私有属性

class Date():

    def __init__(self, year, moth, day):
        self.year = year
        self.moth = moth
        self.day = day

    def tomorrow(self):
        self.day += 1

    @classmethod
    def parse_from_string(cls, string):
        year, moth, day = tuple(string.split('-'))
        return cls(year, moth, day)

    def __str__(self):
        return '{}/{}/{}'.format(self.year, self.moth, self.day)


class User:
    def __init__(self, birthday):
        self.__birthday = birthday

    def get_age(self):
        # 返回年龄
        return 2019 - self.__birthday.year


if __name__ == '__main__':
    user = User(Date(1999, 12, 1))
    print(user.get_age())

七,python对象的自省机制

我们可以使用 __dict__ 来查看 python 类的自省机制,储存在字典里,是效率很高的数据结构

class Person:
    pass

class Student:
    def __init__(self, name):
        self.name = name


if __name__ == '__main__':
    xyb = Student('xyb')
    print(xyb.__dict__)
    print(Student.__dict__)
    
...
{'name': 'xyb'}
{'__module__': '__main__', '__init__': <function Student.__init__ at 0x000002053AC248C8>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}

如果要查找一个对象实现了所有方法,使用 dir() 函数

class Person:
    pass

class Student:
    def __init__(self, name):
        self.name = name


if __name__ == '__main__':
    xyb = Student('xyb')
    print(dir(xyb))

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']

流畅的python 里面具体介绍了 python 的自省机制,但是如果有几十万上百万的数据要储存,要用元组,字典虽然效率极高,但是占用内存大

八,super的调用顺序

super 调用顺序为__mro__ 打印的结果

在使用Python来安装geopandas包时,由于geopandas依赖于几个其他的Python库(如GDAL, Fiona, Pyproj, Shapely等),因此安装过程可能需要一些额外的步骤。以下是一个基本的安装指南,适用于大多数用户: 使用pip安装 确保Python和pip已安装: 首先,确保你的计算机上已安装了Python和pip。pip是Python的包管理工具,用于安装和管理Python包。 安装依赖库: 由于geopandas依赖于GDAL, Fiona, Pyproj, Shapely等库,你可能需要先安装这些库。通常,你可以通过pip直接安装这些库,但有时候可能需要从其他源下载预编译的二进制包(wheel文件),特别是GDAL和Fiona,因为它们可能包含一些系统级的依赖。 bash pip install GDAL Fiona Pyproj Shapely 注意:在某些系统上,直接使用pip安装GDAL和Fiona可能会遇到问题,因为它们需要编译一些C/C++代码。如果遇到问题,你可以考虑使用conda(一个Python包、依赖和环境管理器)来安装这些库,或者从Unofficial Windows Binaries for Python Extension Packages这样的网站下载预编译的wheel文件。 安装geopandas: 在安装了所有依赖库之后,你可以使用pip来安装geopandas。 bash pip install geopandas 使用conda安装 如果你正在使用conda作为你的Python包管理器,那么安装geopandas和它的依赖可能会更简单一些。 创建一个新的conda环境(可选,但推荐): bash conda create -n geoenv python=3.x anaconda conda activate geoenv 其中3.x是你希望使用的Python版本。 安装geopandas: 使用conda-forge频道来安装geopandas,因为它提供了许多地理空间相关的包。 bash conda install -c conda-forge geopandas 这条命令会自动安装geopandas及其所有依赖。 注意事项 如果你在安装过程中遇到任何问题,比如编译错误或依赖问题,请检查你的Python版本和pip/conda的版本是否是最新的,或者尝试在不同的环境中安装。 某些库(如GDAL)可能需要额外的系统级依赖,如地理空间库(如PROJ和GEOS)。这些依赖可能需要单独安装,具体取决于你的操作系统。 如果你在Windows上遇到问题,并且pip安装失败,尝试从Unofficial Windows Binaries for Python Extension Packages网站下载相应的wheel文件,并使用pip进行安装。 脚本示例 虽然你的问题主要是关于如何安装geopandas,但如果你想要一个Python脚本来重命名文件夹下的文件,在原始名字前面加上字符串"geopandas",以下是一个简单的示例: python import os # 指定文件夹路径 folder_path = 'path/to/your/folder' # 遍历文件夹中的文件 for filename in os.listdir(folder_path): # 构造原始文件路径 old_file_path = os.path.join(folder_path, filename) # 构造新文件名 new_filename = 'geopandas_' + filename # 构造新文件路径 new_file_path = os.path.join(folder_path, new_filename) # 重命名文件 os.rename(old_file_path, new_file_path) print(f'Renamed "{filename}" to "{new_filename}"') 请确保将'path/to/your/folder'替换为你想要重命名文件的实际文件夹路径。
在使用Python来安装geopandas包时,由于geopandas依赖于几个其他的Python库(如GDAL, Fiona, Pyproj, Shapely等),因此安装过程可能需要一些额外的步骤。以下是一个基本的安装指南,适用于大多数用户: 使用pip安装 确保Python和pip已安装: 首先,确保你的计算机上已安装了Python和pip。pip是Python的包管理工具,用于安装和管理Python包。 安装依赖库: 由于geopandas依赖于GDAL, Fiona, Pyproj, Shapely等库,你可能需要先安装这些库。通常,你可以通过pip直接安装这些库,但有时候可能需要从其他源下载预编译的二进制包(wheel文件),特别是GDAL和Fiona,因为它们可能包含一些系统级的依赖。 bash pip install GDAL Fiona Pyproj Shapely 注意:在某些系统上,直接使用pip安装GDAL和Fiona可能会遇到问题,因为它们需要编译一些C/C++代码。如果遇到问题,你可以考虑使用conda(一个Python包、依赖和环境管理器)来安装这些库,或者从Unofficial Windows Binaries for Python Extension Packages这样的网站下载预编译的wheel文件。 安装geopandas: 在安装了所有依赖库之后,你可以使用pip来安装geopandas。 bash pip install geopandas 使用conda安装 如果你正在使用conda作为你的Python包管理器,那么安装geopandas和它的依赖可能会更简单一些。 创建一个新的conda环境(可选,但推荐): bash conda create -n geoenv python=3.x anaconda conda activate geoenv 其中3.x是你希望使用的Python版本。 安装geopandas: 使用conda-forge频道来安装geopandas,因为它提供了许多地理空间相关的包。 bash conda install -c conda-forge geopandas 这条命令会自动安装geopandas及其所有依赖。 注意事项 如果你在安装过程中遇到任何问题,比如编译错误或依赖问题,请检查你的Python版本和pip/conda的版本是否是最新的,或者尝试在不同的环境中安装。 某些库(如GDAL)可能需要额外的系统级依赖,如地理空间库(如PROJ和GEOS)。这些依赖可能需要单独安装,具体取决于你的操作系统。 如果你在Windows上遇到问题,并且pip安装失败,尝试从Unofficial Windows Binaries for Python Extension Packages网站下载相应的wheel文件,并使用pip进行安装。 脚本示例 虽然你的问题主要是关于如何安装geopandas,但如果你想要一个Python脚本来重命名文件夹下的文件,在原始名字前面加上字符串"geopandas",以下是一个简单的示例: python import os # 指定文件夹路径 folder_path = 'path/to/your/folder' # 遍历文件夹中的文件 for filename in os.listdir(folder_path): # 构造原始文件路径 old_file_path = os.path.join(folder_path, filename) # 构造新文件名 new_filename = 'geopandas_' + filename # 构造新文件路径 new_file_path = os.path.join(folder_path, new_filename) # 重命名文件 os.rename(old_file_path, new_file_path) print(f'Renamed "{filename}" to "{new_filename}"') 请确保将'path/to/your/folder'替换为你想要重命名文件的实际文件夹路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值