Python 中的魔法方法,也称为双下划线方法或特殊方法,格式为 “方法名”。这些方法无需主动调用,而是在特定场景下由 Python 解释器自动调用。魔法方法的作用是自定义类的行为,以便与内置操作符(例如 +、-、*、/、== 等)和函数(例如 len()、str() 等)交互。
魔法方法在不同的场景下被调用,例如:
这些魔法方法只是 Python 中的一部分,还有其他用于自定义对象行为的魔法方法,具体用法取决于我们的需求。使用魔法方法可以使我们的自定义类更具 Pythonic 和可读性。
__new__ 和 __init__ 在对象创建过程中起着至关重要的作用。__init__ 是我们很熟悉的初始化方法,在对象初始化的时候调用,通常被理解为 “构造函数”。实际上,当我们调用 x = SomeClass() 的时候,__init__ 并不是第一个执行的,__new__ 才是。
__new__ 是用来创建类并返回这个类的实例,而 __init__ 只是将传入的参数来初始化该实例。__new__ 在创建一个实例的过程中必定会被调用,但 __init__ 就不一定,比如通过 pickle.load 的方式反序列化一个实例时就不会调用 __init__。__new__ 方法总是需要返回该类的一个实例,而 __init__ 不能返回除了 None 的任何值。
例如:
class Foo(object):
def __init__(self):
print('foo __init__')
return None # 必须返回 None,否则抛 TypeError
def __del__(self):
print('foo __del__')
在对象的生命周期结束时,__del__ 会被调用,可以将 __del__ 理解为 “析构函数”。__del__ 定义的是当一个对象进行垃圾回收时候的行为。有一点容易被人误解,实际上,x.__del__() 并不是对于 del x 的实现,但是往往执行 del x 时会调用 x.__del__()。
__str__ 和 __repr__ 在对象字符串表示中有不同的用途。__str__ 是一个对象的非正式的、易于阅读的字符串描述,当类 str 实例化(str(object))时会被调用,以及会被内置函数 format() 和 print() 调用。目的是面向终端用户,提供用户友好的对象的字符串表示内容,不一定是对象完整精确描述,只对终端用户负责。如果类没有定义 __str__ 方法,Python 会试图把调用 __repr__ 的字符串结果返回给用户。
例如:
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Dog named {self.name} who is {self.age} years old"
my_dog = Dog("Buddy", 3)
print(my_dog)
__repr__ 是一个对象的官方的字符串描述,会被内置函数 repr() 方法调用,它的描述必须是信息丰富的和明确的。面向 Python 内部,是对象合法的表达式字符串,通过该表达式字符串,可通过 eval() 函数执行并重新生成原始对象,即 eval(repr(obj)) == obj 应该为 True。如果类只定义了 __str__ 而没有定义 __repr__ 方法,Python 会试图调用 __str__ 方法来代替,但这通常不是一个好的做法。
例如:
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Dog(name='{self.name}', age={self.age})"
my_dog = Dog("Buddy", 3)
print(repr(my_dog))
__getattr__、__setattr__、__delattr__ 方法对对象属性的获取、设置和删除操作起着重要作用。
例如:
class Access(object):
def __getattr__(self, name):
print('__getattr__')
return super(Access, self).__getattr__(name)
def __setattr__(self, name, value):
print('__setattr__')
return super(Access, self).__setattr__(name, value)
def __delattr__(self, name):
print('__delattr__')
return super(Access, self).__delattr__(name)
access = Access()
access.attr1 = True # __setattr__调用
access.attr1 # 属性存在,只有__getattribute__调用
try:
access.attr2 # 属性不存在,先调用__getattribute__,后调用__getattr__
except AttributeError:
pass
del access.attr1 # __delattr__调用
__getattribute__、__call__、__len__ 等方法在不同场景下有着重要的应用。
例如:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __call__(self, *args, **kwargs):
return "<Point {}:{}>".format(self.x, self.y)
p = Point(4, 5)
print(p())
class MyList:
def __init__(self, values=None):
self.values = values or []
def __len__(self):
return len(self.values)
my_list = MyList([1, 2, 3])
print(len(my_list))
在 Python 中,setup 方法主要用于构建和安装软件包。它提供了一种简单而灵活的方式来定义软件包的元数据、依赖关系等。
setup 方法通常位于 setup.py 文件中,通过使用 setuptools 模块的 setup 函数来实现。以下是一个简单的 setup.py 文件示例:
from setuptools import setup
setup(
name='mypackage',
version='1.0',
author='Your Name',
author_email='your@email.com',
description='A brief description of my package',
packages=['mypackage'],
install_requires=['dependency1', 'dependency2'],
)
在这个示例中,name 参数指定了包的名称,version 参数指定了包的版本号,author 和 author_email 参数指定了包的作者信息,description 参数提供了包的简要描述。packages 参数指定了要安装的包的名称,这里假设 mypackage 是一个包含 __init__.py 文件的 Python 包。install_requires 参数列出了包的依赖关系,当安装这个包时,这些依赖项会自动被安装。
例如,如果我们的软件包依赖于 numpy 和 matplotlib,可以这样指定:
setup(
...
install_requires=['numpy', 'matplotlib'],
)
这样,在安装我们的软件包时,如果用户的环境中没有安装 numpy 和 matplotlib,它们将会被自动安装。
除了基本用法外,setup 方法还提供了一些参数以满足更复杂的需求。
例如,要创建一个名为 mytool 的工具,可以在 setup 函数中添加以下代码:
setup(
...
entry_points={'console_scripts': ['mytool=mypackage.tool:main',]},
)
这将创建一个名为 mytool 的可执行文件,执行 mypackage.tool 模块中的 main 函数。
例如,要将一个名为 config.ini 的配置文件包含在软件包中,可以在 setup 函数中添加以下代码:
setup(
...
data_files=[('config', ['config.ini']),],
)
这将把 config.ini 文件复制到软件包安装路径下的 config 目录中。
使用 setup 方法打包的软件包可以通过多种方式进行安装。
pip install .
这将根据 setup.py 文件中的配置信息安装软件包及其依赖库。
pip install -e .
总之,setup 方法在 Python 软件包的构建和安装中起着重要的作用,通过合理使用其各种参数和安装方式,可以方便地管理和分发 Python 代码。
Magic Method 和 Setup 方法在 Python 编程中虽然有着不同的功能,但也存在一些关联和相互作用。
Magic Method 主要用于自定义类的行为,使得对象能够与内置操作符和函数进行交互,从而实现更加灵活和强大的编程。例如,通过定义 __str__ 和 __repr__ 方法,可以控制对象的字符串表示形式,方便在调试和输出时提供更有意义的信息。通过定义 __add__、__eq__ 等方法,可以实现自定义对象的运算和比较操作。
Setup 方法则主要用于构建和安装软件包,定义软件包的元数据、依赖关系以及安装方式等。它为开发者提供了一种方便的方式来组织和分发代码。
在某些情况下,Magic Method 可以与 Setup 方法结合使用。例如,在构建一个自定义的数据结构类时,可以使用 Magic Method 来定义该类的特殊行为,如 __len__ 方法用于返回数据结构的长度。如果这个数据结构类被打包成一个软件包,那么 Setup 方法可以用来安装这个软件包,并确保其依赖关系得到满足。
另外,当使用 Setup 方法创建可执行脚本或命令行工具时,可以利用 Magic Method 来定义这些工具的行为。例如,可以定义 __call__ 方法,使得工具对象可以像函数一样被调用。
总之,Magic Method 和 Setup 方法在 Python 编程中各有其独特的作用,但它们也可以相互结合,为开发者提供更全面的编程解决方案。了解它们之间的关联和相互作用,可以帮助开发者更好地利用 Python 的强大功能,提高开发效率。