首页 Tech python 面向对象

python 面向对象

作者 Worthify 1692 字 · 8 分钟阅读# Tech
python 面向对象

编程思维——面向过程与面向对象

编程思维就是我们人类用编程语言解决某个问题的方式,其中最主要的就是面向过程和面型对象。

面向过程

在接触面向对象之前,我所写的代码基本都是面向过程思维,即遇到问题需要解决时,先将他拆解成一个个小的步骤,最终完成目标。我们可以举一个实际的例子:

  • 面向过程: 洗衣服:加水,放衣服,倒洗衣液,揉搓,拧干,晾晒。 这就是面向过程,注重实现某个目标的具体步骤。

面向对象

面向对象的思想与面向过程非常不同,它只在乎结果,具体的实现细节并不需要考虑,我们依旧按照上面洗衣服的例子,看看面向对象如何实现的:

  • 面向对象: 拿衣服,放入洗衣机 | 丢给干洗店 | 让其他人去洗,晾晒 这就是面向对象的思维,它不关心某些功能的具体实现,只关注最后事情完成的结果。

面向对象的基本思想

面向对象的主要实现核心思想如下:

  • 面向对象让编程与实际事物更加接近,所有对象都赋予了属性和方法,使编程过程更具人性化。
  • 宗旨在于模拟现实世界。
  • 现实生活中,所有事物都被称为对象。

面向对象的三大特征

所有支持面向对象的语言,都需要实现面向对象的三大基本特征:

  • 封装: 隐藏具体实现细节,把属性和方法封装在一起,仅提供外部方法供人们访问,简化开发。
  • 继承: 孩子继承父亲的东西,重复列用,增加代码复用性。
  • 多态: 同一个函数在不同的环境下,表现出不同的状态,增加代码耦合性,扩展性。

类

定义: 类是是一组对象的抽象集合,具有相同特性的对象使用同一个类。 我们举例来说,面包车,轿车,跑车,越野车它们都同属于车这个大类,这里的车就是类,而轿车,跑车等就是这个类的对象,或者说实例。 再比如,我们电脑分为很多类型,台式机,笔记本,二合一平板。但他们都统称为电脑。这里,电脑就是类,是各种其他类型电脑的超类。而台式,笔记本这些就是电脑的子类 用代码表示可以这样表示:

PYTHON
# 使用 class 关键字创建一个电脑类
class  computer:
	# 初始化方法
    def __init__(self, cpu, ram, hdd):
        self.cpu = cpu
        self.ram = ram
        self.hdd = hdd
    # 品牌标记方法
    def brand(self, brand_name:str): 
        self.brand_name = brand_name
        print(f"Brand: {self.brand_name}")
	# 输出电脑配置
    def config(self):
        print("Configuration of the computer:")
        print(f"CPU: {self.cpu}")
        print(f"RAM: {self.ram} GB")
        print(f"HDD: {self.hdd} TB")
	
    def __add__(self, other):
        total_ram = self.ram + other.ram
        total_hdd = self.hdd + other.hdd
        return computer("Combined CPU", total_ram, total_hdd)

创建了类后,我们就需要创建类的实例去使用它。比如我们现现在创建两个实例,代码如下:

PYTHON
# 创建两个计算机对象
# 台式电脑
comp1 = computer("desktop","Intel i5", 8, 1)
# 笔记本电脑
comp2 = computer("laptop","AMD Ryzen 5", 16, 2)
# 品牌标记
comp1.brand("Dell")
# 输出配置
comp1.config()
# 品牌标记
comp2.brand("HP")
# 输出配置
comp2.config()  

执行效果如下:

PYTHON
# 创建两个计算机对象
comp1 = computer("desktop","Intel i5", 8, 1)
comp2 = computer("laptop","AMD Ryzen 5", 16, 2)
comp1.brand("Dell")
comp1.config()
comp2.brand("HP")
comp2.config()  

类的命名空间

定义: 命名空间是一个名字到对象的映射,类似于字典,其中,键可以使变量名,函数,类。值是这些名称引用的对象。 pythong 中命名空间的层次关系为:模块/全局命名空间 –> 类命名空间 –> 实例命名空间 –> 局部命名空间(函数命名空间) 为了更好的理解,我们先来看一段代码:

PYTHON

# 1. 学校储物柜系统(模块/全局命名空间)
class_shelves = {}  # 每个班级的储物柜架
global_items = {"学校名": "阳光中学", "校长": "张老师"}

# 2. 班级储物柜架(类命名空间)
class Class7A:
    # 班级公共储物柜(类属性)
    classroom = "301"
    teacher = "王老师"
    class_items = ["地图", "地球仪", "粉笔"]  # 所有学生共享
  
    def __init__(self, student_name):
        # 学生个人储物柜(实例属性)
        self.student_name = student_name
        self.personal_items = []  # 每个学生自己的物品
  
    def add_item(self, item):
        # 往个人储物柜放东西
        self.personal_items.append(item)
  
    @classmethod
    def change_classroom(cls, new_room):
        # 修改班级公共储物柜位置
        cls.classroom = new_room

# 3. 实际使用
zhang = Class7A("张三")
li = Class7A("李四")

# 类属性访问(班级公共储物柜)
print(zhang.classroom)     # 301
print(li.classroom)        # 301
print(Class7A.classroom)   # 301

# 修改类属性(移动班级)
Class7A.classroom = "302"
print(zhang.classroom)     # 302(所有实例都变了)
print(li.classroom)        # 302

# 实例属性(个人储物柜)
zhang.add_item("数学书")
li.add_item("语文书")

print(zhang.personal_items)  # ['数学书']
print(li.personal_items)     # ['语文书'](互不影响)

上面这个例子就很好的说明了各个命名空间之前的关系,学校的储物系统作用于学习里的所有班级(全局变量),各个班级有属于自己的公共储物箱(类命名空间),班级里的学生也有自己的个人储物箱(实例命名空间)。 学校的所有变动直接作用于所有班级,例如修改学校名字,学校换了新的校长。班级中变动作用于属于这个班级的学生,比如上面代码中修改了班级的公共储物(修改类属性会作用于所所有属于该类的实例),而学生自己的的个人储物箱不受其他学生的影响(实例命名空间之前互不影响)。

深入研究——类命名空间和实例命名空间。

先看代码:

PYTHON
class Car:
    # 类命名空间中的内容
    wheels = 4  # 类属性
    engine_type = None  # 类属性

    def __init__(self, brand):
        # 实例命名空间中的内容
        self.brand = brand  # 实例属性
        self.speed = 0  # 实例属性

    @classmethod
    def set_default_wheels(cls, num):
        # 操作类命名空间
        cls.wheels = num

    def accelerate(self):
        # 操作实例命名空间
        self.speed += 10

# 创建实例
BYD = Car("比亚迪")
BBA = Car("宝马")
# 查看实例属性
print("查看各个实例中属性值")
print(f"BYD 中的实例属性值:{BYD.__dict__}") # 暑促:BYD 中的实例属性值:{'brand': '比亚迪', 'speed': 0}
print(f"BBA 中的实例属性值:{BBA.__dict__}") # 输出:BBA 中的实例属性值:{'brand': '宝马', 'speed': 0}

这里创建了两个实例 BYD 和 BBA ,通过 __dict__ 查看当前实例内容并不一样。现在我们尝试修改 Car 类中的属性。

PYTHON
# 修改类属性(影响所有实例)
Car.set_default_wheels(6)
print("BYD 轮胎数量:",BYD.wheels) # 输出: 6
print("BBA 轮胎数量:",BBA.wheels) # 输出: 6

可以看到,类属性的修改直接作用于属于该类的所有实例。 那么接下来,我们尝试修改 BBA 属性中的 wheels 属性,查看有什么变化:

PYTHON
# 尝试通过实例修改类属性:
BBA.wheels = 4
print("类属性",Car.wheels) # 6 (类属性不受影响)
print("BYD 轮胎:",BYD.wheels) # 6 (BYD 实例不受影响)
print("BBA 轮胎数量:",BBA.wheels) # 4 (BBA 修改自己实例中的内容,只租用与当前的实例,其他实例不受影响。)

从输出结果来看,这里的 BBA 修改的实例属性 wheels ,只对自己的实力空间有效,其他实例空间和类空间之间不受影响。

动态操作命名空间

在 python 中,可以随时动态增加和删除类或实例命名空间中的属性和方法,代码如下:

PYTHON
'''
动态操作命名空间
'''
print("动态操作命名空间")

class DynamicClass:
    """演示动态操作命名空间"""

    def __init__(self):
        self.data = {}

# 查看当前实例命名空间。
obj = DynamicClass()
print("obj 当前实例空间:",obj.__dict__) # 输出:obj 当前实例空间: {'data': {}}

代码中创建了一个 DynamicClass 类,并创建了其实例 obj,当前 obj 的实例空间中只有一个 data 属性。我们可以直接动态的添加实例属性:

PYTHON
# 动态添加实例属性
obj.new_attribute = "动态添加的属性"
print("obj 动态添加属性后的命名空间:",obj.__dict__) # 输出:{'data': {}, 'new_attribute': '动态添加的属性'}

除了属性,我们也可以动态添加方法:

PYTHON
# 动态添加方法:
def dynamic_mathod(self):
    return f"动态方法,动态属性 new_attribute 值为:{self.new_attribute}"

# 绑定动态方法到实例
import types
# 使用 types.MethodType 将动态方法和实例绑定。
obj.show_info = types.MethodType(dynamic_mathod,obj)
print("调用动态方法:",obj.show_info() )
# 输出: 调用动态方法: 动态方法,动态属性 new_attribute 值为:动态添加的属性

同样,我也可以直接动态操作类命名空间:

PYTHON
# 动态添加类属性:
DynamicClass.clasVerion = "1.0"
print(f"动态添加的雷属性{DynamicClass.clasVerion}")
# 输出:动态添加的雷属性1.0

想要删除某个属性,可以知己使用 del 关键字动态删除:

PYTHON
# 动态删除属性:
del obj.new_attribute
try:
    print("obj 动态属性:",obj.new_attribute)
except Exception as e:
    print(f"发现错误{e},obj 的当前状态:{obj.__dict__}")
    # 输出:发现错误'DynamicClass' object has no attribute 'new_attribute',obj 的当前状态:{'data': {}, 'show_info': <bound method dynamic_mathod of <__main__.DynamicClass object at 0x000001E553CA6BA0>>}

属性,函数和方法。

属性

我们在类中定义的变量,就是这个类属性,我们可以使用代码来演示。

PYTHON
class Animal:
    # 2. 属性(Attributes)- 特征
    def __init__(self, name, age):
        self.name = name  # 名字属性
        self.age = age    # 年龄属性
	
	# 3. 方法(Methods)- 行为
    def eat(self):
        print(f"{self.name}正在吃东西")
  
    def make_sound(self):
        print(f"{self.name}发出声音")

我们就可以使用这个创建实例是定义这个属性`

PYTHON
lion = Animal("辛巴", 5)  # 狮子辛巴
elephant = Animal("小飞象", 10)  # 大象小飞象

方法和函数

我们可以注意到,类中的定义的所谓“方法”,看起来似乎普通的函数一样,不过前面会多出来一个 self 的参数。

PYTHON
class Class:
    def method(self):
        print("我有一个 swlf 参数。")

def function():
    print("我啥也没有")

类方法中的 self 参数是为了其关联到它所属的示例,在实际调用是不需要指定该参数。在使用不同实例调用方法时会返回不同的结果,而普通的函数无法实现这个效果。

继承

之前我我们说过超类,和子类。这个概念就是属于继承的范畴。我们使用下面的代码来进行解释。

PYTHON
# 创建父类/基类 Animal 所有动物都继承自 Animal
class Animal:
    def __init__(self, name):
        self.name = name
    def eat(self):
        print(f"{self.name}吃东西")

# dog 类,继承至 Animal 类
class Dog(Animal):
    def __init__(self, name):
        Animal.__init__(self, name)
    # 子类可以新增方法。
    def woof(self):
        print(F"{self.name} 汪汪叫")
    # 重写父类的方法。
    def eat(self):
        print(f"{self.name} 吃狗粮")

class Cat(Animal):
    def __init__(self, name):
        Animal.__init__(self, name)
    def maomao(self):
        print(f"{self.name} 喵喵叫")

# 创建实例 dog
dog = Dog("球球")
dog.eat() # 输出:球球 吃狗粮
dog.woof() # 输出:球球 汪汪叫
# 创建实例 cat
cat = Cat("芝麻团")
cat.eat() # 输出:芝麻团吃东西
cat.maomao() # 输出:芝麻团 喵喵叫

上面的例子就很好的展示了继承的概念。但是上面的的代码只是一个演示,正常环境代码如下;

PYTHON
class Filter:
    def __init__(self, name = None):
        self.name = name

    def  filter(self, sequence):
        return [item for item in sequence if self.name not in item]
# 创建一个子类 SubFilter,继承自 Filter
# 子类可以继承父类的属性和方法 
# 也可以重写父类的方法
# 还可以使用 super() 函数调用父类的方法
class SubFilter(Filter):
    def __init__(self, name):
        super().__init__(name)

上面的代码实现了关键词过程功能,父类 Filter 负责实现功能,子类 subFilter 继承父类方法,并用于创建实例。

PYTHON
filter2 = SubFilter("spam")
# 使用子类对象调用继承自父类的方法
print(filter2.filter(["spam","eggs","harn"]))# 输出 ['eggs', 'harn']

issubclass 函数和 isinstanc 函数

有时候可能需要判断类与类之间的继承关系,我们可以使用 insubclass(a,b) 判断 a 类是否为 b 类的子类。

PYTHON

# 查看某个类是否为另一个类的子类
print(issubclass(SubFilter,Filter)) # 输出 True
print(issubclass (Filter,SubFilter))    # 输出 False

isintance() 函数其实并不是判断类的继承关系的,它主要用于类型检查。因为 isinstance() 会考虑类的继承关系,判断并不准确。

PYTHON
# 查看对象是否为某个类的实例,可以使用 isinstance() 函数
print(isinstance(filter2,SubFilter))# 输出 True
print(isinstance(filter2,Filter))# 输出 True
print(isinstance(filter2,object))# 输出 True

为了编码这种情况,可以采用 type() 函数来判断。

PYTHON
# 通常更好的方法是使用 type() 函数
print(type(filter2) == SubFilter) # 输出 True

多重继承

一个子类可以继承多个父类,父类可以被多个子类继承,父类与子类属于多对多关系:

PYTHON
# 多重继承
class Calb:
    value = 0
    def  cabl(self,expressions):
        self.value = eval(expressions)
    # 测试多同名方法
    def takeing(self):
        print(f"I think the  expressions result is {self.value} —— Calb")
class Take:
    def takeing(self):
        print(f"En... I think the  expressions result is {self.value} —— Take")
class TakeCable(Calb,Take):
    pass

takecable = TakeCable()
takecable.cabl("2 * 8 + 1")
# 调用父类的方法
takecable.takeing() # 输出 En... I think the  expressions result is 17

封装

定义: 封装其实就是隐藏类方法中具体的实现细节,只提供公告接口给其使用。 这个概念可能比较抽象,我们用现实中的例子来解释一个: 我们使用的笔记本,一体机,台式机等,其大多数配件都是装在机箱里。我们不必过多关注电脑具体有那些配件组成,只需要通过键盘,鼠标,屏幕使用电脑就可以了。 上面的例子中,键盘,鼠标,屏幕就是提供使用的公共接口,而其电脑中的电子元件就是隐藏在内部的细节。 python 中没有 Java 语言里的 private 的关键字,隐藏类中的方式使用需要使用 _ 或者 __ 前缀。

PYTHON
class Seretive:
    # 私有方法
    def __intarnal_mathod(self,x:int,y:int):
        return x + y
    # 公共方法
    def  public_method(self,a,b):
           return self.__intarnal_mathod(a,b)
    # 受保护方法
    def _prodected_method(self):
        print("This is a protected method")
# 创建 Seretive 对象
obj = Seretive()
# 尝试调用私有方法
# obj.__intarnal_mathod(3,4)  # 这将引发 AttributeErr
# 正确的调用方式是通过公共方法
result = obj.public_method(1,3)
print(result)  # 输出 4

需要注意,python 中没哟严格意义上的私有方法,即使使用 __ 前嘴隐藏方法,通过其他调用方式也完全可以访问。保持自觉,是 python 的设计理念之一。

多态

定义: 不同的类型,通过统一的接口,依据不同类型进行不同的实现。 这个概念依旧很抽象,我们使用生活中的例子来解释:动物都会叫,小猫,小狗,鸡,鸭,鹅这些动物都会叫,但是他们的叫的声音和方式都不同。这就是多态,不同类型(各种会叫的动物),通过统一的接口(嘴,发声器官),依据不同类型进行不同的实现(每个动物都叫的不一样)。我使用代码的模拟上面的例子:

PYTHON
# 多态代码演示,用户解释什么是多态。

# 创建 dog 类
class Dog:
    # 实现 说话方法
    def speak(self):
        print("汪汪汪")

# 创建 cat 类
class Cat:
    # 实现说话方法
    def speak(self):
        print("喵喵喵")

# 创建 dock 类
class Duck:
    # 实现说话方法
    def speak(self ):
        print("嘎嘎噶")

animals = [Dog(),Cat(),Duck()]

# 使用多态。
for animal in animals:
    # 调用统一接口
    animal.speak()
    # 输出:汪汪汪
    # 喵喵喵
    # 嘎嘎噶

上面的代码中,采用 for 循环调用 dog,cat,duck 类中统一的 speak 方法,不同的类依据不同的实现返回结果。 在实际使用开发中,我们编写的大多数函数都是多态的,比如我们编写一个 add() 加法函数。

PYTHON
# 编写 add() 函数

def add(a,b):
    return a + b

# 测四字符相加
print("字符相加",add("inter","nation"))	# 输出:internation
# 测试数字相加
print("数字相加",add(20,10)) # 输出:30

上面的 add() 函数就完美的体现了多态的特性,通过统一的 add() 函数,依据不同的类型返回结果。 还有一个常见的多态的函数是 repr() 它可以适用于任何对象。

PYTHON

def length_message(x):
    print(f"The length of {repr(x)} is {len(x)}")


length_message("internation")
length_message([2,4,6,8,10])

抽象类

定义: 抽象类主要用于规定和设计某个的功能的大体框架,抽象类并不实现这些方法,而是让其子类继承和实现。 抽象类用更加容易理解的方式解释就是:计算机组成原理中说过,冯洛伊曼定义计算机必须要包括 运算器,控制器,存储,输入设备,输出设备这五大部分。这个规定就是计算机设计的蓝图(抽象基类),所有制造计算机的厂商必须按照这个要求来生产计算机(继承抽象,具体实现)。 创建抽象类是需要注意以下几点:

  • 抽象类必须继承自 ABS,ABS 是所有抽象类的父类。
  • 抽象类不能被实例化,只能被其子类继承。
  • 子类必须实现抽象类中的所有抽象方法
  • 抽象类中的抽象方法需要使用 @abstractmethod 修饰符修饰。
  • 抽象类中可以包含已经实现的方法。 我们可以用代码来演示:
PYTHON
# 此代码用于解释抽象类。
from abc import ABC, abstractmethod
from idlelib.debugobj import ClassTreeItem

# python 中,所有抽象类必须继承自  ABC 抽象基类不能被实例化,只能由
class Computer(ABC):
    # 抽象类中的抽象方法必须有 @abstractmethod 修饰符。
  
    # 创建 CPU 抽象方法(CPU 包括运算器和控制器)
    @abstractmethod
    def CPU(self):
        pass

    # 创建存储抽象类
    @abstractmethod
    def Storage(self):
        pass

    # 创建 输入设备抽象类
    @abstractmethod
    def InputDriver(self):
        pass

    # 输出设备:屏幕。抽象类可以包含已经实现的方法。
    def OutputDriver(self):
        print("输出设备为:Screen")

# 继承 Computer 抽象类,具体实现。
class Production(Computer):
    def __init__(self,CPU,Storage,InputDriver):
        self.CPU = CPU
        self.Storage = Storage
        self.InputDriver = InputDriver
  
    # 实现抽象基类 Computer 中的抽象方法。
    def CPU(self):
        print(f"该机器使用的 CPU 为:{self.CPU}")

    def Storage(self):
        print(f"该机器使用的内存为:{self.Storage}")

    def InputDriver(self):
        print(f"该机器使用的输入设备为:{self.InputDriver}")

    def get_config(self):
        Production.CPU(self)
        Production.Storage(self)
        Production.InputDriver(self)
        super().OutputDriver()


# 实例化子类。
# 创建一个 Dell 实例,定义电脑配置
Dell = Production("intel i7-10520","DDR5:32G,SSD:1TB","keyboard")
# 输出配置
Dell.get_config()
输出:

# 创建一个 Lenovo 实例,定义电脑配置
Lenovo = Production("AMD Ryzen 9700x3D","DDR5:64G,SSD:2TB","keyboard")
# 输出配置。
Lenovo.get_config()

可以看到,上面的代码中,定义了一个抽象基类 Computer。该抽象基类用于规定了基本框架,继承它的子类必须实现其所有抽象方法。

接口和内省

定义: 接口是一个具有强约束力的“协议”,就好像“合同”,规定某个功能必须有什么,但关系具体实现。 python 中乜有 java 语法中 interface 关键字定义接口,通常直接使用抽象类来实现。但需要注意,作为接口的抽象了中不包含已经实现的方法。 例如下面的代码:

PYTHON
# 该程序用演示 python 中接口的定义。
from  abc import ABC, abstractmethod

# 支出接口,需要子类继承实现
class PaymantMathd(ABC):

    # 支付方法,子类必须要实现
    @abstractmethod
    def process_payment(self,amount):
        pass

    # 图款方法,子类必须实现
    @abstractmethod
    def refund(self,amount):
        pass

# 物流接口,需要子类实现。
class ShipingService(ABC):

    @abstractmethod
    def ship(self):
        # 发货方法。
        pass

    @abstractmethod
    def track_package(self):
        # 追踪包裹方法。
        pass

上面的代码中定义了两个接口,一个支付接口,一个物理接口。继承的子类需要实现其具体的功能。

PYTHON
# 实现支付接口
class Alipay(PaymantMathd):

    def process_payment(self,amount):
        print(f"请支付,因为扫描二维码,支付 {amount} 元")
        return f"支付成功,支付 {amount}"

    def refund(self,amount):
        print(f"退款中,原路返回 {amount} 元")

class CreateCard(PaymantMathd):

    def process_payment(self,amount):
        print(F"信用卡支付,支付 {amount} 元")
        return f"支付成功,支付 {amount} 元"

    def refund(self,amount):
        print(f"退款中,原路返回 {amount} 元")

子类实现了网络支付和信用卡支付,我们创建一个函数使用接口。

PYTHON
# 使用接口,不关心具体实现方法。
def checkout(payment_Mathed:PaymantMathd,amount):
    return payment_Mathed.process_payment(amount)

alipay = Alipay()
card = CreateCard()

checkout(alipay,10) # 输出:请支付,因为扫描二维码,支付 10 元

checkout(card,30) # 输出:信用卡支付,支付 30 元

我们使用 checkout() 函数来访问上面实现的功能,依据不同的实现(网络支付,信用卡支付)返回结果。这点有类似于多态。

内省

定义: 内省是在程序运行时,检查对象类型,属性和方法的能力。 用日常的例子来说的话:去厂库拿东西,如果没有内省,你根本就不知道各个箱子里装的是什么;有内省的情况下,箱子上标记了标签,记录的箱子里的物品,数量,入库日期等等。

基础内省工具

我们依旧使用代码举例:

PYTHON
# 我们先创建一个示例类
class Car:
    def __init__(self, brand, model, year):
        self.brand = brand
        self.model = model 
        self.year = year
        self.__serial_number = "ABC123"  # 私有属性
  
    def start_engine(self):
        print(f"{self.brand} {self.model}引擎启动!")
  
    def drive(self, distance):
        print(f"行驶了{distance}公里")

# 创建对象
my_car = Car("Tesla", "Model 3", 2023)

上面的代码创建一个 Car 类其中包含 start_engine 和 drive 方法。

使用 type() 和 isinstance() 查看对象类型

type() 函数用于返回对象类型:

PYTHON
# 使用 type() 方法查看对象类型
# 类示例
print(type(my_car)) # 输出:<class '__main__.Car'>
# 布尔类型
print(type(True)) # 输出:<class 'bool'>

isinstance() 函数用户判断对象是否属于某个类型:

PYTHON
# 使用 isinstance() 方法判断对是否属于某个类型,也可用户判断继承。
print(isinstance(my_car, Car))  # 输出: True
print(isinstance(my_car, object))   # 输出:True (所有对象都继承自 object )
print(isinstance(my_car, int))  # 输出:False
print(isinstance(my_car, (Car,str,int))) # 输出 True (只要包含其中一个就返回 True)

使用 dir() 函数查看对象包含什么。

dir() 函数用户查看对象中包含那些内容,在遇到不熟悉的库或者类时,可以使用该函数快速浏览大体内容:

PYTHON
# 查看对象所有可用的属性或者方法:
print(dir(my_car))
# 输出:['_Car__serial_number', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__firstlineno__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__static_attributes__', '__str__', '__subclasshook__', '__weakref__', 'brand', 'drive', 'model', 'start_engine', 'year']
# 查看仅字节有的属性和方法
print([ atter for  atter in dir(my_car) if not atter.startswith("__")])
# 输出:['_Car__serial_number', 'brand', 'drive', 'model', 'start_engine', 'year']

使用 hasattr() 查看对象有没有对应属性或方法。

hasattr() 方法可以查看对象是否存在该属性或者方法。

PYTHON
# 使用 hasattr() 查看是否有属性或者方法
print(hasattr(my_car,"brand"))  #  输出:True
print(hasattr(my_car,"color"))  #  输出:False
print(hasattr(my_car,"start_engine"))   # 输出:True 

使用 getattr() 函数获取对象属性。

getattr() 函数获取对象的属性值:

PYTHON
# getattr() 获取对象属性 安全方式
brand = getattr(my_car,"brand")
print(brand) # 输出:Tesla

# 获取不存在的 属性
color = getattr(my_car,"color","unknown")
print(color) # 输出:unknown 

# 相当于:
# if hasattr(my_car, 'color'):
#     color = my_car.color
# else:
#     color = 'unknown'

使用 setattr() 函数修改对象属性

setattr() 函数可以动态的增加或修改对象的属性。

PYTHON
# 使用 `setattr()` 函数,动态设置对象属性。
print(hasattr(my_car,"color")) # 输出: True
setattr(my_car,"color","red")
print(getattr(my_car,"color")) # 输出: red
print(hasattr(my_car,"color")) # 输出:True

# 修改已有的属性
setattr(my_car,"brand","Mac")
print(getattr(my_car,"brand")) # 输出:Mac

使用 callable() 函数查看对象是否可调用

callable() 函数可以查看对象的属性是否可以被调用。

PYTHON
# 使用 callable() 函数查看对象可调用。
print(callable(my_car.brand)) # 输出:False  属性不可调用
print(callable(my_car.start_engine)) # 输出:True,属性方法可调用
print(callable(Car)) # 类可调用。

使用 __clase__ 和 __name__ 查看对象所属类。

__class 和 __name__ 参数可以查看对象的所属类。

PYTHON
# __clss__ 和 __name__ 方法,查看对象所属类
print(my_car.__class__) # 输出:<class '__main__.Car'>
print(my_car.__class__.__name__) # 输出:Car

# 获取类的父类
print(Car.__bases__) # 输出:(<class 'object'>,)

# 获取方法解析顺序(MRO)
print(Car.__mro__) # 输出:(<class 'object'>,)

使用 __dict__ 查看对象的所有属性

__dict__ 可以查看对象中的所有属性,包私有属性,使用 keys() 可以获取类属性

PYTHON
# 查看对象的所有实例属性.
print(my_car.__dict__)
# 输出:{'brand': 'Mac', 'model': 'Model 3', 'year': 2023, '_Car__serial_number': 'ABC123', 'color': 'red'}
# 查看类的属性:
print(my_car.__dict__.keys())
# 输出:dict_keys(['brand', 'model', 'year', '_Car__serial_number', 'color'])

查看函数内容属性的具体内容

PYTHON

# 查看函数的具体参数:
def calculate_price(car, tax_rate=0.1, discount=0):
    """计算汽车价格"""
    base_price = 30000
    return base_price * (1 + tax_rate - discount)

print(calculate_price.__name__) # 输出:calculate_price
print(calculate_price.__doc__) # 输出:计算汽车价格
print(calculate_price.__module__) # 输出:__main__

# 查看参数值
import inspect

sig = inspect.signature(calculate_price)
print(sig)  # 输出:(car, tax_rate=0.1, discount=0)

# 查看参数写。
params = inspect.signature(calculate_price).parameters
for name,params in params.items():
    print(f"{name}:{params.default}")
    # 输出:
    # car:<class 'inspect._empty'>
    # tax_rate:0.1
    # discount:0