New方法、单例模式、装饰器

New方法、单例模式、装饰器

Yiuhang Chan

类中的_ _new_ _(魔术方法/构造器)

在Python中,__new__方法确实是一个特别的方法,但它和__init__方法有着明显的区别。__new__是一个静态方法(虽然通常不明确地声明为静态方法),而__init__是一个实例方法。

_ _new_ _方法的作用

__new__方法主要用于创建一个新的实例对象。它是类的一个静态方法,即便不明确声明也是如此。__new____init__方法之前被调用,用于生成实例对象。通常情况下,我们不需要自己编写__new__方法,但在某些特殊情况下,修改__new__方法能够提供额外的灵活性。

_ _new_ _ 方法的基本结构

1
2
3
4
5
class MyClass(object):
def __new__(cls, *args, **kwargs):
# 创建对象的逻辑
instance = super(MyClass, cls).__new__(cls, *args, **kwargs)
return instance

类定义

1
class MyClass(object):

这行代码定义了一个名为MyClass的新类,它继承自Python内置的object类。在Python 3中,所有的类默认继承自object,所以即使不显式地继承,它仍然会继承自object

_ _new_ _ 方法

1
def __new__(cls, *args, **kwargs):

这是__new__方法的定义。__new__是一个特殊方法,用于在一个对象实例化时创建并返回这个对象。

  • cls:这个参数是对当前类MyClass的引用,这与实例方法中的self参数类似,但cls是在对象创建之前使用的。
  • *args**kwargs:这两个参数允许传递任意数量的位置参数和关键字参数。这些参数将会被传递给__init__方法。

创建实例的逻辑

1
instance = super(MyClass, cls).__new__(cls, *args, **kwargs)

这行代码是创建类实例的核心。

  • super(MyClass, cls):这部分调用了MyClass的父类的方法。在这个例子中,父类是objectsuper函数是用来获取父类定义,以便调用其方法的一种方式。
  • .__new__(cls, *args, **kwargs):这部分实际上调用了父类object__new__方法,并传递了必要的参数。这个调用负责创建一个新的实例。
  • instance__new__方法返回的是一个实例对象,这里我们将其赋值给变量instance

返回实例

1
return instance

最后,__new__方法返回了新创建的实例instance。这个实例接下来将被用来调用__init__方法,以便进行进一步的初始化。

总结

这个MyClass类示例展示了如何在Python中自定义__new__方法。通常,不需要重写__new__,除非有改变实例创建方式的特殊需求,比如实现单例模式、返回一个不同的类的实例或者在创建实例之前做一些额外的操作。在大多数情况下,只需要关注__init__方法来初始化实例。

使用场景

__new__方法通常在下面的情况下使用:

  1. 单例模式:确保一个类只有一个实例。
  2. 不可变类型的子类:例如扩展某些内置不可变类型,如tuplestr
  3. 控制实例的创建:在某些复杂的情况下,可能需要在对象创建时进行额外的处理。

单例模式

单例模式是一种常见的软件设计模式,其核心思想是确保一个类在应用程序中只有一个实例,并提供一个全局访问点来获取这个实例。这种模式在需要控制资源的访问或管理共享资源时特别有用,如数据库连接或文件系统的操作。

单例模式的特点

  1. 唯一实例:单例类只允许创建一个实例。
  2. 全局访问点:单例类提供一个全局访问的方法,全局的代码都可以通过这个方法访问到这个唯一实例。
  3. 自我管理:单例类负责创建、初始化和管理自己的唯一实例。

Python中实现单例模式

在Python中,单例模式可以通过多种方法实现,如使用模块级别的变量、装饰器、元类或重写__new__方法等。以下是通过重写__new__方法实现单例模式的一个示例:

1
2
3
4
5
6
7
class Singleton:
_instance = None

def __new__(cls):
if cls._instance is None:
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
  • 类变量_instance用于存储类的唯一实例。
  • __new__方法中,首先检查_instance是否已经被创建。如果没有,则创建一个新实例并将其赋值给_instance
  • 之后的所有实例化操作都将返回这个已创建的实例。

单例模式的使用场景

单例模式通常用于以下场景:

  • 管理共享资源,如数据库连接、日志记录、配置信息等。
  • 控制资源的访问,确保资源的一致性和状态的同步。
  • 减少资源的重复创建和销毁,提高效率。

注意事项

  • 单例模式在多线程环境下可能需要特别的处理来保证线程安全。
  • 过度使用单例模式可能导致代码间的耦合度过高,应当谨慎使用。
  • 在分布式系统中,单例模式的使用需要考虑到进程间的通信和资源共享的问题。

单例模式是一种简单但强大的设计模式,能够有效地管理共享资源和全局状态,但也需要注意其带来的限制和潜在问题。

私有属性

在Python中,私有属性(Private Attributes)是指仅能在其所属的类内部访问的属性,而无法从类外部直接访问。这是面向对象编程中封装的一个重要概念,用于隐藏类的内部实现细节,并保护类的状态免受外部干扰。

如何定义私有属性

在Python中,私有属性通常是通过在属性名前加上双下划线(__)来定义的。

1
2
3
class MyClass:
def __init__(self):
self.__private_attribute = 42

在这个例子中,__private_attribute就是一个私有属性。由于它的名字以双下划线开头,它只能在MyClass内部访问。

访问和修改私有属性

私有属性只能在定义它们的类的内部访问和修改。如果你试图从类外部访问或修改这些属性,将会导致AttributeError

1
2
obj = MyClass()
print(obj.__private_attribute) # 将引发错误

要在类外部访问或修改私有属性的值,你需要在类内部提供公共的方法(例如getter和setter方法)。

1
2
3
4
5
6
7
8
9
10
11
12
13
class MyClass:
def __init__(self):
self.__private_attribute = 42

def get_private_attribute(self):
return self.__private_attribute

def set_private_attribute(self, value):
self.__private_attribute = value

obj = MyClass()
print(obj.get_private_attribute()) # 正确
obj.set_private_attribute(100) # 正确

名称改写(Name Mangling)

在Python中,私有属性的名称实际上会被改写,这个过程称为名称改写(Name Mangling)。Python解释器自动地把属性名__private_attribute转换为_MyClass__private_attribute。这意味着理论上你可以通过改写过的名称来访问私有属性,但这并不是一个好的做法,因为它违反了封装的原则。

1
print(obj._MyClass__private_attribute)  # 可行,但不推荐

为什么使用私有属性

使用私有属性的主要理由是封装和抽象。通过限制对类内部状态的直接访问,你可以防止外部代码无意中破坏类的内部状态,从而保持对象的完整性和一致性。

总结

私有属性是面向对象编程中的一个重要概念,它有助于实现封装和数据隐藏。在Python中,私有属性通过在属性名前加双下划线来定义,并且只能通过类内部定义的方法进行访问和修改。尽管技术上可以通过名称改写访问私有属性,但这并不符合封装的原则,应当避免这样做

装饰器

装饰器(Decorators)是Python中一个非常强大且有用的功能,它们允许程序员修改或增强函数和方法的行为,而不需要改变其本身的代码。装饰器在很多高级Python应用中都有广泛的使用,如Web框架、事件监听、日志处理等。

装饰器的基本原理

在Python中,装饰器本质上是一个Python函数,它可以接收一个函数作为参数并返回一个新的函数。使用装饰器可以在不修改原函数的情况下,增加额外的功能。

1
2
3
4
5
6
7
8
9
10
11
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper

def say_hello():
print("Hello!")

say_hello = my_decorator(say_hello)

在上面的例子中,my_decorator是一个装饰器,它在say_hello函数前后添加了额外的打印操作。

使用@语法糖

Python提供了一个简单的方式来应用装饰器,即使用@符号,这也被称为语法糖。这让代码更加简洁易读。

1
2
3
@my_decorator
def say_hello():
print("Hello!")

使用@my_decorator语法,上面的代码与之前例子中的功能完全相同。

带参数的装饰器

装饰器也可以带参数,这需要在其外层再加一层函数。这种装饰器也称为装饰器工厂。

1
2
3
4
5
6
7
8
9
10
11
12
def repeat(number=3):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(number):
value = func(*args, **kwargs)
return value
return wrapper
return decorator_repeat

@repeat(number=4)
def greet(name):
print(f"Hello {name}")

在这个例子中,repeat是一个带参数的装饰器,它接受一个参数number,指定了函数执行的次数。

装饰器的用途

  • 日志记录:添加日志功能,以跟踪函数的调用细节。
  • 性能测试:检测函数执行时间,用于性能优化。
  • 权限验证:检查用户是否有权执行某个操作。
  • 缓存:缓存函数的返回结果,提高程序性能。

总结

装饰器是Python中非常有用的工具,可以在不修改原有函数代码的情况下,给函数增加新的功能。它通过语法简单但功能强大的方式,提高了代码的可读性和可维护性。在Python的日常使用中,熟练运用装饰器是一个非常有价值的技能。

信息

在Python中,装饰器的实现通常依赖于闭包的概念。

闭包(Closure)简介

闭包是一种在动态编程语言中常见的概念,它指的是一个函数记住了它的词法作用域,即使这个函数在自己的词法作用域之外执行。在Python中,闭包表现为一个内嵌函数记住了其外部函数的状态或环境。

装饰器中的闭包

在装饰器中使用闭包,是为了在装饰器函数内创建一个包装函数(wrapper),这个包装函数能够记住并访问其外部函数(即装饰器函数)的变量和参数。这使得装饰器能够在不修改被装饰函数的情况下增加额外的功能。

  • my_decorator 是一个装饰器函数。
  • wrapper 是一个内嵌函数,它是闭包的体现。wrapper 能够记住并访问func,即使在my_decorator函数的执行已经完成之后。
  • 当我们使用@my_decorator装饰say_hello函数时,实际上是将say_hello作为参数传递给了my_decorator,并将返回的wrapper函数赋值给了say_hello

闭包的作用

闭包在装饰器中的主要作用是让我们能够延伸或修改函数的行为。闭包使得装饰器内部的包装函数能够访问到装饰器接收的原始函数,从而在不改变原始函数定义的前提下,对其进行包装,增加额外的操作和逻辑。

总结

简言之,装饰器中的闭包是Python中一种强大的函数式编程特性,它允许内嵌函数捕获并保持外部函数的状态,从而使得我们可以在不修改原函数的情况下,为其增加新的功能。这种特性在Python中广泛用于日志记录、性能测试、权限校验等场景。

详见函数篇 闭包

  • 标题: New方法、单例模式、装饰器
  • 作者: Yiuhang Chan
  • 创建于 : 2018-09-15 17:24:27
  • 更新于 : 2024-02-28 18:49:10
  • 链接: https://www.yiuhangblog.com/2018/09/15/20180915New单例模式装饰器/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论