美文网首页
类与对象

类与对象

作者: Biomamba生信基地 | 来源:发表于2023-08-08 22:42 被阅读0次

一、类

类中可以定义属性(变量)与行为(函数/方法)。在定义方法的时候我们其实已经提到过类的定义方式,具体语法为:

class 类名称:
类的属性
类的行为

创建类对象的语法:
对象 = 类名称
例如:

# 简单的定义一个类
class my_class:
    name = None # 预定义name变量,并预设值为None
    
    def my_function(self, date): # 在类中定义方法时,必须加上一个self参数,用于调用类内部的变量
        print(f"I am {self.name}, Today is {date}.")
# 简单操作一下刚才定义的类的变量
my_new = my_class() # 创建类对象
print(my_new.name) # 查看类中name的初始值
## None
my_class.name = "Biomamba" # 给类中的变量赋值
print(my_new.name) # 查看修改后的值
## Biomamba
# 使用刚才定义的类中的方法
my_new.name = "Biomamba" 
my_new.my_function(date = "Friday")
# 可以看到类中包含方法的print函数内容被成功输出
## I am Biomamba, Today is Friday.

二、构造方法

Python类可以使用:init()方法,成为构造方法。这样构建的方法会在创建类对象的时候会利用传入参数自动传递给__init__()自动执行。

# 定义包含构造方法的类:
class my_class:
   # 定义变量的过程可以省略 
    def __init__(self,name,date): 
        print(f"I am {name}, Today is {date}.")
        
my_newclass = my_class(name="Biomamba",date="Friday")
# 可以看到由于构造方法的存在,省去了一些变量的定义过程,并且在生成类对象时同事执行构造方法
## I am Biomamba, Today is Friday.

三、类内置方法(魔术方法)

例如一部分中的__init__构造方法是Python的类内置方法,类中还有数十种其它各自具有特殊功能的类内置方法,又称为魔术方法。本文只介绍其中常见的几种。

16.3.1 字符串方法

通过__str__即可定义:
我们先用一个例子体会一下为什么需要字符串方法

# 简单定义一个类并调用其中的方法:
class my_class:
    def my_print(self,my_content):
        print(my_content)
my_new = my_class()
my_new.my_print("Biomamba")
# 可以看出这个类中方法的作用就是打印出输入的内容:
## Biomamba
# 但是当我们打印这个类对象本身时,返回的并不是我们输入的内容,而是一个内存地址:
print(my_new)
## <__main__.my_class object at 0x000001AFF51EF0B8>
# 即使我们将其转换为字符串,返回的依旧是一个内存地址:
print(str(my_new))
## <__main__.my_class object at 0x000001AFF51EF0B8>
# 那么这时就可以通过__str__来对类进行改造
class my_class:
    def my_print(self,my_content):
        print(my_content)
        
    def __str__(self):
        return "我是魔术方法返回的字符串"
        
my_new = my_class()
print(type(my_new))
## <class '__main__.my_class'>
print(my_new)
## 我是魔术方法返回的字符串
print(str(my_new))
# 可以看到,虽然my_new的类型是一个类,但是其本身和其转换为字符串后的值都可以被正常打印
## 我是魔术方法返回的字符串

16.3.2 大小比较符方法

通过__lt__即可定义。由于两个对象不可直接进行比较,因此比较魔术方法可以指定比较的变量,让对象带上比较的功能。
注:__lt__只能用于><这两种比较,<=>=这类比较运算符需要通过__le__实现。==需要通过__eq__来实现,定义方法与__lt__逻辑相同。

# 定义包含构造方法的类:
class my_class:
   # 定义变量的过程可以省略 
    def __init__(self,name,oclock): 
        print(f"I am {name}, Now is {oclock}.")
        
my_newclass_1 = my_class(name="Biomamba",oclock= 1)
## I am Biomamba, Now is 1.
my_newclass_2 = my_class(name="Biomamba",oclock= 2)
## I am Biomamba, Now is 2.
# 可以看到这两个类变量之前不可比较
my_newclass_1 > my_newclass_2

TypeError: ‘>’ not supported between instances of ‘my_class’ and ‘my_class’

# 改造一下这个类定义
# 定义包含构造方法的类:
class my_class:
   # 定义变量的过程可以省略 
    def __init__(self,name,oclock): 
        print(f"I am {name}, Now is {oclock} oclock.")
        self.oclock = oclock

    def __lt__(self,other): # self表示当前类,other代表其它用于比较的类
        return self.oclock <  other.oclock 

my_newclass_1 = my_class(name="Biomamba",oclock= 1)
## I am Biomamba, Now is 1 oclock.
my_newclass_2 = my_class(name="Biomamba",oclock= 2)
## I am Biomamba, Now is 2 oclock.
# 其实大于和小于都能用于比较
print(my_newclass_1 < my_newclass_2)
## True
print(my_newclass_1 > my_newclass_2)
## False

四、封装

封装是指将数据(属性)和行为(方法)包装到类对象中。在方法內部对属性进行操作,在类对象的外部调用方法。这一操作能够提高程序的安全性。
私有成员:
在类的定义中,可以设置私有成员对象和私有成员方法,这些私有成员不可被用户调用,不对外开放。

# 定义一个包含私有成员的类
class my_class:
    __my_var = "我是一个私有变量"
    def __my_function(self):
        print("我是一个私有成员方法")
        
my_new = my_class()
# 私有变量不可用
my_new.__my_var

AttributeError: ‘my_class’ object has no attribute ’__my_var’

# 私有成员存在的意义是供类中的其它成员调用:

#  调用私有变量
class my_class:
    __my_var = "我是一个私有变量"
    def my_function(self):
        print(self.__my_var)
        
my_new = my_class()
my_new.my_function()
# 可以看到私有变量__my_var被成功打印
## 我是一个私有变量
# 调用私有方法
class my_class:
    def __my_function(self):
        print("我是一个私有成员方法")
    def open_function(self):
        self.__my_function()
        
my_new = my_class()
my_new.open_function()
# 可以看到私有方法被成功调用
## 我是一个私有成员方法

五、继承

继承,顾名思义,可以让新的类继承原有类的变量与方法,语法为:
class 新类名(原有类名)
即:
class 类名(父类)

16.5.1 单继承

指一个子类继承一个父类

# 定义原有类
class old_class:
    def old_function(self):
        print("这是初始版本的类")

my_oldclass =  old_class()
my_oldclass.old_function()
## 这是初始版本的类
# 定义一个新得类,并继承原有类的功能:
class new_class(old_class):
    def new_function(self):
        print("这是最新版本的类")

my_newclass =  new_class()
my_newclass.old_function()
## 这是初始版本的类
my_newclass.new_function()
# 可以看到新定义的类不仅能执行新添加的方法,还能执行初始版本的方法
## 这是最新版本的类

16.5.2 多继承

指一个子类继承多个父类,语法也很简单:
class 新类名(父类1,父类2,父类3...)

# 定义父类1
class old_class_1:
    def old_function_1(self):
        print("这是父类1的功能")
        
# 定义父类2
class old_class_2:
    def old_function_2(self):
        print("这是父类2的功能")
       
# 定义父类3
class old_class_3:
    def old_function_3(self):
        print("这是父类3的功能")
        
# 定义一个新得类,并继承原有类的功能:
class new_class(old_class_1,old_class_2,old_class_3):
    def new_function(self):
        print("这是最新版本的类")

my_newclass =  new_class()

my_newclass.old_function_1()
## 这是父类1的功能
my_newclass.old_function_2()
## 这是父类2的功能
my_newclass.old_function_3()
## 这是父类3的功能
my_newclass.new_function()
# 可以发现所有父类的功能均可以被调用:
## 这是最新版本的类

16.5.3 合并类

上面的新类定义中我们均加入了新的功能,我们也可以通过pass来定义一个空的类,来继承原有的父类:

# 定义父类1
class old_class_1:
    def old_function_1(self):
        print("这是父类1的功能")
        
# 定义父类2
class old_class_2:
    def old_function_2(self):
        print("这是父类2的功能")
       
# 定义父类3
class old_class_3:
    def old_function_3(self):
        print("这是父类3的功能")
        
# 定义一个新得类,并继承原有类的功能:
class new_class(old_class_1,old_class_2,old_class_3):
    pass

my_newclass =  new_class()

my_newclass.old_function_1()
## 这是父类1的功能
my_newclass.old_function_2()
## 这是父类2的功能
my_newclass.old_function_3()

# 可以发现所有父类的功能均可以被调用:
## 这是父类3的功能

16.5.4 继承顺序

当多继承中父类存在相同的变量名与方法名,则优先级为左侧优先:

# 定义父类1
class old_class_1:
    def old_function(self):
        print("这是父类1的功能")
        
# 定义父类2
class old_class_2:
    def old_function(self):
        print("这是父类2的功能")
       
# 定义父类3
class old_class_3:
    def old_function(self):
        print("这是父类3的功能")
        
# 定义一个新得类,并继承原有类的功能:
class new_class(old_class_1,old_class_2,old_class_3):
    pass

my_newclass =  new_class()

my_newclass.old_function()
# 只会出现父类1的运行结果
## 这是父类1的功能

16.5.5 复写父类成员

在子类继承父类的成员属性和方法后,可以通过复写对父类中的成员进行修改。完成方式很简单,重新定义同名成员即可。

# 定义父类
class old_class_1:
    def old_function(self):
        print("这是父类1的功能")
        
#
        
# 继承并复写:
class new_class(old_class_1,old_class_2,old_class_3):
    def old_function(self):
        print("这是复写后的功能")

my_newclass =  new_class()

my_newclass.old_function()
# 返回的是复写后的结果

当你复写之后可以通过如下两种方式调用父类中的原有成员:

# 原有父类成员调用方式一:
# 父类名.父类成员

# 定义父类:
class old_class_1:
    def old_function(self):
        print("这是父类1的功能")
        

        
# 复写并调用原父类方法:
class new_class(old_class_1,old_class_2,old_class_3):
    def old_function(self):
        myraw = old_class_1()
        myraw.old_function()
        print("这是复写后的功能")

my_newclass =  new_class()
my_newclass.old_function()
# 可以看到父类和子类的功能可以被分别调用
## 这是父类1的功能
## 这是复写后的功能
# 原有父类成员调用方式二:
# super().父类成员

# 定义父类:
class old_class_1:
    def old_function(self):
        print("这是父类1的功能")
        

        
# 复写并调用原父类方法:
class new_class(old_class_1,old_class_2,old_class_3):
    def old_function(self):
        myraw = super().old_function()
        print("这是复写后的功能")

my_newclass =  new_class()
my_newclass.old_function()
# 可以看到父类和子类的功能可以被分别调用
## 这是父类1的功能
## 这是复写后的功能

六、类型注释

对类型注解后有利于我们调用对应类型的各种方法,方便静态类型检查工具、IDE等第三方工具提供快捷功能。通常有读变量的类型注解、对函数(方法)形参列表和返回值的类型注解。

16.6.1 变量类型注解

变量类型注解的语法很简单:
方式一:变量:类型

# 基础变量的注解
my_var1: str = "Biomamba"
type(my_var1)
## <class 'str'>
# 各类数据容器的注解:
# 对于负责数据容器来说,可以支持其中的每一个元素的分别注解
my_list: list[int] = [1,2,3]
my_tuple: tuple[str, int, bool] = ["Biomamba",2023,True]
my_set: set[int] = {1,2,3}
my_dict: dict[str, int] = {"Biomamba": 2023}
# 测试一下
print(f"{my_tuple[0]}的类型是{type(my_tuple[0])}")
# 没问题:
## Biomamba的类型是<class 'str'>
方式二–在注释中操作:

# type:类型
例如:

var_1 = 15 # type: int
type(var_1)
## <class 'int'>

16.6.2 函数与方法的类型注解

函数和方法中可以对形参返回值进行类型注解。

# 例如定义函数时对形参my_data进行注解
def my_function(my_data:str):
    return my_data.name
# 对返回值进行注解:
def my_function(my_data) -> list:
    return my_data.name

16.6.3 Union类型联合注解

# 导包与模块
from typing import Union
# 表示list中的元素既可以是字符串,又可以是整数:
my_list: list[Union[str, int]] = [2023,"Biomamba","Bioinformatics"]

七、多态

完成某一行为时,使用不同的对象即会得到不同的状态。
例如上面继承的例子:

# 一个父类
class old_class_1:
    def my_function(self):
        pass
        
# 定义两个子类
class new_class_1(old_class_1):
    def my_function(self):
        print("这是子类1的功能")
       
class new_class_2(old_class_1):
    def my_function(self):
        print("这是子类2的功能")

# 定义新函数,传入变量为原来定义的类
def print_back(myclass:old_class_1):
    myclass.my_function()

my_new_1 = new_class_1()
my_new_2 = new_class_2()

print_back(my_new_1)
## 这是子类1的功能

print_back(my_new_2)
# 可以看出,对于同样的输入方式,不同的输入对象会执行不同的功能(不同的状态)
## 这是子类2的功能

往期回顾

生信Python速查手册

Python安装(Windows+Linux)

Python的"Rstudio"——Pycharm

码Python神器:jupyter notebook

一文了解Python基础:字面量、注释、变量、类型、运算符

Python判断语句

Python循环语句

Python函数与方法

一文掌握Python数据容器

Python函数进阶

Python文件操作

Python异常

Python模块

Python包的创建、导入、安装

Python数据可视化案例:pyecharts

相关文章

  • 类与对象(类与对象定义)

    类与对象的定义和使用 如果在程序之中要定义一个类可以使用class关键字完成,而定义的语法如下: 在这个类中只是定...

  • 函数类和对象区别

    类与类:行为不同 对象与对象:数据不同

  • python入门开发学习笔记之类与对象

    本节重点 掌握什么是类、什么是对象 掌握如何定义及使用类与对象 了解对类与对象之间的关系 类与对象的概念 类即类别...

  • 类对象与类的对象

    类对象(obj.getClass)描述的是类的代码信息,比如哪些属性、属性是什么类型、变量名是什么、哪些方法、方法...

  • python-高级、面向对象

    一、类与对象 二、类和对象

  • Java面向对象笔记

    类和对象 对象的概念 什么是面向对象 类 什么是对象的属性 什么是对象的方法 类与对象的关系/与区别 什么是对象 ...

  • 006-面向对象1

    面向过程与面向对象 开车问题 吃饭问题 做饭问题 类与对象 类的概念 对象的概念 练习: 区分类与对象 类的组成 ...

  • 三、元类对象的本质

    1. 元类对象结构。 与类对象的结构一样。 与类对象比较 2. 元类对象的获取。 通过object_getClas...

  • 格物致知iOS类与对象

    格物致知iOS类与对象 格物致知iOS类与对象

  • 类与对象

    类与对象是整个面向对象之中最为基础的组成单元;类是共性的集合,对象是个性的产物。所有的类都是用来描述出对象的结构,...

网友评论

      本文标题:类与对象

      本文链接:https://www.haomeiwen.com/subject/ahkopdtx.html