推广 热搜: csgo  vue  angelababy  2023  gps  新车  htc  落地  app  p2p 

Python中5对必知的魔法方法

   2023-07-17 网络整理佚名1490
核心提示:具体地说,在方法中,你需要为创建的实例对象设置初始属性。我们不会直接调用类中的方法时,它在类中担负着初始化实例的作用,例如,要创建一个新的实例,可以使用以下代码:如你所见,当实例对象嵌入到with语句中时,将调用方法。在with语句中完成操作后,将调用方法。但是,需要注意的是,我们可以用和方法来创建上下文管理器。要正确使用它,你必须借助super()来使用超类方法。

推荐书籍:《大学实践教程》

适合零基础初学者阅读

介绍

在 中,我们可以使用下划线、字母和数字来命名函数。 单词之间的下划线并没有多大意义——它们只是通过在单词之间创建空格来提高可读性。 这被称为蛇形命名风格。 例如,比 更容易阅读。 您可能知道,除了这种使用下划线的常见方式之外,我们还在函数名称前添加一个或两个下划线前缀(例如:_func, )来表示类或模块中的私有函数,即那些不带下划线前缀的函数名称被视为公共 API。

下划线在方法命名中的另一个用途是定义“魔术方法”,也称为“特殊方法”。 具体来说,我们在方法名称前后使用两个下划线 - 类似于 . 由于使用了两个下划线,有些人将特殊方法称为“方法”或简称为“”。 本文介绍了五对密切相关的常用魔法方法,每一对代表一个概念。

1. 实例化:和

在学习了数据结构的基础知识(例如字典、列表)之后,您应该已经看到了一些自定义类的示例,其中必须有一个神奇的方法: 。 该方法用于初始化实例对象。 具体来说,在该方法中,需要为创建的实例对象设置初始属性。 这是一个简单的例子:

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

当我们不直接调用类中的方法时,它负责初始化类中的实例。 例如,要创建一个新实例,您可以使用以下代码:

product = Product("Vacuum", 150.0)

与方法密切相关的是方法,我们通常不会在自定义类中实现方法。 其实是真正的构造方法,构造实例对象,传递给方法完成初始化过程。

换句话说,构造一个新的实例对象(这个过程称为实例化)需要依次调用和方法。

下面的代码演示了这种连锁反应:

>>> class Product:
...     def __new__(cls, *args):
...         new_product = object.__new__(cls)
...         print("Product __new__ gets called")
...         return new_product
... 
...     def __init__(self, name, price):
...         self.name = name
...         self.price = price
...         print("Product __init__ gets called")
... 
>>> product = Product("Vacuum", 150.0)
Product __new__ gets called
Product __init__ gets called

2. 字符串表示法:和

这两个方法都很重要,因为它们是可以在自定义类中指定的字符串表示方法。 在解释它们之前,让我们快速浏览一下以下实现:

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def __repr__(self):
        return f"Product({self.name!r}, {self.price!r})"

    def __str__(self):
        return f"Product: {self.name}, ${self.price:.2f}"

该方法应该返回一个字符串,其内容是创建实例对象。 具体来说,可以将字符串传递给 eval() 来创建实例对象。 以下代码片段显示了这一点的实际效果:

>>> product = Product("Vacuum", 150.0)
>>> repr(product)
"Product('Vacuum', 150.0)"
>>> evaluated = eval(repr(product))
>>> type(evaluated)
'__main__.Product'>

该方法的返回结果对于实例对象更具描述性。 需要注意的是,print() 函数使用方法来显示与实例相关的信息,如下所示。

>>> print(product)
Product: Vacuum, $150.00

虽然这两个方法都应该返回字符串,但这些方法通常是面向开发人员的,主要显示实例化信息; 而这些方法是面向用户的,通常会显示更多的信息内容。

3. 迭代:和

用代码自动重复的某项工作称为迭代,可以用 for 循环来实现。 我们将可在 for 循环中使用的对象称为可迭代对象。 for循环的基本形式如下:

for item in iterable:
    # Operations go here

在幕后,可迭代对象被转换为迭代器对象,它为每个循环提供可迭代对象中的项目。 一般来说,迭代器是可用于实现项目迭代的对象。 转换过程是通过实施特殊方法来完成的。 此外,检索迭代器的下一项涉及特殊方法的实现。 现在我们继续前面的示例,使用该类作为 for 循环的迭代器:

>>> class Product:
...     def __init__(self, name, price):
...         self.name = name
...         self.price = price
... 
...     def __str__(self):
...         return f"Product: {self.name}, ${self.price:.2f}"
... 
...     def __iter__(self):
...         self._free_samples = [Product(self.name, 0) for _ in range(3)]
...         print("Iterator of the product is created.")
...         return self
... 
...     def __next__(self):
...         if self._free_samples:
...             return self._free_samples.pop()
...         else:
...             raise StopIteration("All free samples have been dispensed.")
... 
>>> product = Product("Perfume", 5.0)
>>> for i, sample in enumerate(product, 1):
...     print(f"Dispense the next sample #{i}: {sample}")
... 
Iterator of the product is created.
Dispense the next sample #1: Product: Perfume, $0.00
Dispense the next sample #2: Product: Perfume, $0.00
Dispense the next sample #3: Product: Perfume, $0.00

如上所示,我们使用该方法创建一些示例数据并创建一个迭代器实例。 为了实现迭代行为,在循环期间调用该方法来显示实例中的所有样本。 当读取样本时,迭代结束。

4. 上下文管理器:和

在处理 中的文件对象时,最常见的语法可能是这样的:

with open('filename.txt') as file:
    # Your file operations go here

with 语句的使用称为上下文管理器。 具体来说,在上面的文件操作例子中,with语句会为文件对象创建一个上下文管理器,在文件操作完成后,上下文管理器会帮我们关闭文件对象,这样共享资源(即文件)就可以被使用了其他过程。

因此,一般来说,上下文管理器是管理共享资源的对象,例如打开和关闭。 如果没有上下文管理器,我们就必须手动管理这些资源,这很容易出错。

为了使用自定义类实现此类行为,需要实现和方法。 该方法设置上下文管理器,准备操作所需的资源,同时该方法清除任何应释放的已用资源,使它们可用。 让我们考虑一个与上一类相关的简单示例:

>>> class Product:
...     def __init__(self, name, price):
...         self.name = name
...         self.price = price
... 
...     def __str__(self):
...         return f"Product: {self.name}, ${self.price:.2f}"
... 
...     def _move_to_center(self):
...         print(f"The product ({self}) occupies the center exhibit spot.")
... 
...     def _move_to_side(self):
...         print(f"Move {self} back.")
... 
...     def __enter__(self):
...         print("__enter__ is called")
...         self._move_to_center()
... 
...     def __exit__(self, exc_type, exc_val, exc_tb):
...         print("__exit__ is called")
...         self._move_to_side()
... 
>>> product = Product("BMW Car", 50000)
>>> with product:
...     print("It's a very good car.")
... 
__enter__ is called
The product (Product: BMW Car, $50000.00) occupies the center exhibit spot.
It's a very good car.
__exit__ is called
Move Product: BMW Car, $50000.00 back.

正如您所看到的,当实例对象嵌入到with语句中时,该方法被调用。 with 语句中的操作完成后调用该方法。

不过,需要注意的是,我们可以使用 和 方法来创建上下文管理器。 使用上下文管理器的装饰器功能可以更轻松地完成此操作。

5. 属性访问控制:和

如果您有其他语言的编程经验,您可能已经为实例属性设置了显式的(访问属性)和(设置属性)。 在 中,我们不需要对每个属性都使用这些访问控制技术。 然而,我们可以通过实现和方法来实现某种控制。 具体来说,当访问实例对象的属性时,会调用该方法; 当设置实例对象的属性时,会调用该方法。

>>> class Product:
...     def __init__(self, name):
...         self.name = name
... 
...     def __getattr__(self, item):
...         if item == "formatted_name":
...             print(f"__getattr__ is called for {item}")
...             formatted = self.name.capitalize()
...             setattr(self, "formatted_name", formatted)
...             return formatted
...         else:
...             raise AttributeError(f"no attribute of {item}")
... 
...     def __setattr__(self, key, value):
...         print(f"__setattr__ is called for {key!r}: {value!r}")
...         super().__setattr__(key, value)
... 
>>> product = Product("taBLe")
__setattr__ is called for 'name''taBLe'
>>> product.name
'taBLe'
>>> product.formatted_name
__getattr__ is called for formatted_name
__setattr__ is called for 'formatted_name''Table'
'Table'
>>> product.formatted_name
'Table'

每次尝试设置对象的属性时都会调用该方法。 要正确使用它,必须将超类方法与 super() 一起使用。 否则就会陷入无限递归。

一旦设置了属性,它就成为对象的一部分,因此不会被调用。

另外,还有一种与访问控制密切相关的特殊方法,称为 . 它很相似,但每次访问属性时都会调用它。 此时,与 类似。 同样,您应该使用 super() 实现方法以避免无限递归错误。

综上所述

本文回顾了五对重要的特殊方法。 通过这些方法,我们了解了与之相关的五个概念。 我希望您能更好地理解这些概念,并更好地理解如何在自己的项目中使用特殊方法。

参考链接:

 
反对 0举报 0 收藏 0 打赏 0评论 0
 
更多>同类资讯
推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报
Powered By DESTOON