我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python new 类方法和 ini

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python new 类方法和 ini

“Python 中的类都是单例模式?” 一天,一同事问我这样一个问题。这是一个奇怪的问题,可能你也这么认为。这里先不做解释,我们先来看看 __new____init__ 方法。

new 与 init

__new__ 方法属于新式类,即属于 object 类。它是一个静态方法,但是其第一个参数必须是一个类(cls),这有点像一个 classmethod,其实将其看成是一个类方法也可以。该特殊方法被调用时,会创建类(cls)的一个新实例并返回,实例被创建后解释器会将该实例以及其它的参数传递给该实例的初始化函数 __init__,以对实例进行初始化。

所以,__new__ 方法是一个类方法,用于创建一个实例,而 __init__ 方法是一个实例方法,用于初始化一个实例。

__new__ 方法在实例化一个类时被调用,重写该方法应该像如下的形式:

class A(object):

    def __new__(cls, *args, **kwargs)
        return super(A, cls).__new__(cls, *args, **kwargs)

如果 __new__ 方法不返回 cls 的一个实例,那么新的实例的 __init__ 方法不会被调用。需要注意的是,在 Python 3.3 之后,new 方法不再接收额外的参数,否则会有异常 TypeError: object() takes no parameters。

__init__ 方法在实例被创建之后被调用,该方法仅仅是对 __new__ 方法创建的实例进行一些初始化操作。注意,如果 new 方法返回实例,则 init 方法总是会被调用(这一点在用 new 方法实现单例时要特别注意)

可以来做一下验证:

class Foo(object):

    def __new__(cls, m, n):
        print "__new__ is called"
        return super(Foo, cls).__new__(cls, m, n)

    def __init__(self, m, n):
        print "__init__ is called"
        self.m = m
        self.n = n

    def __repr__(self):
        return "Foo(m={self.m}, n={self.n})".format(self=self)

    def __str__(self):
        return self.__repr__()


if __name__ == "__main__":
    f = Foo(1, 2)
    print f

输出结果:

__new__ is called
__init__ is called
Foo(m=1, n=2)

于是可以得出结论:

  • 1、 __new__ 属于类级别的方法,即使没有被 classmethod 装饰,其决定生成实例的过程。
  • 2、 __init__ 属于实例级别的方法,决定实例初始化的过程,比如添加属性,对初始化参数进行判断,转换等。

需要注意的是,在重写 __new__ 方法与 __init__ 方法的参数应该保持一致,否则会有 TypeError 发生。如果直接调用 object.__new__() 则在 Python 3.3 及以后的版本中不再支持传入参数,这一点参考自:https://stackoverflow.com/questions/34777773/typeerror...

__init__ 方法,在定义一个 class 的时候一般都会涉及到,也是比较常用。而 __new__ 方法则很少会用到,那么它到底有什么用途呢?

new 方法作用

__new__ 方法比较常用的作用大概是:

  • 1、 继承内建不可变类型时(比如int, str, tuple),提供自定义实例化过程。因为如果在 __init__ 方法中做都写操作可能会无效。例如:
class CustomInt(int):

    def __init__(self, v):
        super(CustomInt, self).__init__(self, abs(v))

print CustomInt(-1)

# 输出:-1

这可能没有达到期望的效果。但可以通过重写 __new__ 方法来实现:

class CustomInt(int):

    def __new__(cls, v):
        return super(CustomInt, cls).__new__(cls, abs(v))

print CustomInt(-1)

# 输出:1
  • 2、 实现自定义的元类(metaclass)。元类就是用来定义如何创建类,它的概念可能稍微复杂些,这里不做详细讨论。
  • 3、 实现单例。由于类产生实例的过程是通过 __new__ 方法来控制的,因此重写该方法来单例模式是非常方便的:
class Singleton(object):

    def __new__(cls):
        if not hasattr(cls, "_instance"):
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

assert Singleton() is Singleton()  # 断言成功

所谓单例模式就是每次初始化都返回同一个实例,所以两次初始化得到的对象的内存地址应该是一样的:

print Singleton(), Singleton()

结果应该是显而易见的:

<__main__.Singleton object at 0x10d698650> <__main__.Singleton object at 0x10d698650>

装饰器实现单例

说到单例模式,除了用 __new__ 方法实现外,还有一些其他的方式,如装饰器、元类等。不同方式的实现有不同的作用,元类属于 Python 中更为高级的特性,本文不做讨论,我们来看一下用装饰器实现单例的方法。

装饰器(decorator)可以动态地修改一个类或函数的功能,即类也可以被装饰器装饰。因此可以使用装饰器来装饰某个类,使其被初始化时只生成一个实例:

from functools import wraps

def singleton(cls):
    instances = {}
    @wraps(cls)
    def getinstance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return getinstance

@singleton
class MyClass(object):

    def __init__(self):
        pass

需要注意的是,使用装饰器实现单例时,类已经变成了一个函数,而不再是类。 如上用上例中 MyClass 初始化实例时,实际上调用的是被装饰后返回的 getinstance 函数。

__new__ 实现单例和用装饰实现单例的区别是,前者前者都是会调用 __init__ 方法,这就意味着每次初始化时用不同的参数,虽然返回的实例时同一个,但是实例的属性却被重新设置了;而后者则总是返回第一次初始化创建的示例和设置的属性,即使后面传入了不同的参数。

奇怪现象

接着,我们再来看一个 “奇怪” 的现象:

>>> class A(object):
...     pass
...
>>> print A(), A()
<__main__.A object at 0x104765450> <__main__.A object at 0x104765450>
>>> print A(), A()
<__main__.A object at 0x104765450> <__main__.A object at 0x104765450>
>>> print A(), A()
<__main__.A object at 0x104765450> <__main__.A object at 0x104765450>

是不是感觉有些难以置信,print 语句后两次创建的对象应该是不一样的,而他们却莫名奇妙的一样。这就是我讨论本文内容的原因。

一次同事问我,Python 中的类都是单例模式?我当时一脸懵逼,听了他的描述,我自己也试了下,果然存在如上所示的“奇怪”现象。于是我就去了解了 Python 单例模式的实现,在了解到 __new__ 的实现方式时,就想对 __new____init__ 有一个更加深入的了解。于是就有了本文所讨论的内容。

然后,我想着用 is 来判断下他们是否真的是同一个实例:

>>> A() is A()
False

我没有对 CPython 的源码进行过全面的阅读,所以对其很多内部的实现机制不是太了解。我猜 Python 解释器在内部可能做了优化,像 print A(), A() 这样的语句,解释器认为没有必要创建不同的对象,直接返回同一个实例的引用得了。是不是觉得解释器有些自作聪明!而当 A() is A() 这样的表达式出现时,解释器想,我不能再自作聪明,那样可能会误导别人。可是,在 print 语句那样的用法时,就已经误导我了,我都差点开始怀疑人生了!

从语法来看,大家应该知道,我在测试时使用的 Python 2。我后来也试了下 Python 3:

>>> class A():
...     pass
...
>>> print(A(), A())
<__console__.A object at 0x10fe7afd0> <__console__.A object at 0x10fed79e8>
>>> print(A(), A())
<__console__.A object at 0x10fec0cc0> <__console__.A object at 0x10feda160>
>>> print(A(), A())
<__console__.A object at 0x10fe7afd0> <__console__.A object at 0x10fed7940>
>>> A() is A()
False

我想,这样的结果才是不会让人困惑的。可能是 Python 社区意识到了这个问题并在 Python3 中进行了修正。这样的修正是好的,否则对于像我同事那样初次使用 Python 的人来说是很困惑的。

个人认为,Python3 对过去的一些“错误”的修正是好的。例如将 print 改为函数,提供了丰富的参数来控制输出的样式;对编码的调整等等。

Python 中还有很多令人“匪夷所思”的“奇怪”现象,感兴趣可以看看这篇博客:Python Oddity。例如其中提到的对整数的对比,其就是因为 Python 对小整数对象([-5,256])进行了缓存,对于这个问题也有人进行了详细的描述:Python解惑:整数比较。

参考资料

  • https://docs.python.org/2/reference/datamodel.html

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python new 类方法和 ini

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python new 类方法和 ini

“Python 中的类都是单例模式?” 一天,一同事问我这样一个问题。这是一个奇怪的问题,可能你也这么认为。这里先不做解释,我们先来看看 __new__ 和 __init__ 方法。new 与 init__new__ 方法属于新式类,即属于
2023-01-31

python读取/写入配置文件ini方法

在写测试脚本时,经常有一些需要变动的数据,可以单独放在ini文件里,然后读取传递给相应的函数,这样程序操作更灵活。具体的方法介绍如下:文件结构:Cofig.ini内容:[test1]ip = 10.10.10.10[test2]port =
2023-01-31

Python类方法和类方法静态方法分别是什么

这篇文章主要讲解了“Python类方法和类方法静态方法分别是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python类方法和类方法静态方法分别是什么”吧!一、前言类方法也可以进行更细致
2023-06-15

java 中newInstance()方法和new关键字的区别

java 中newInstance()方法和new关键字的区别* 它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。* 那么为什么会有两种创建对象方式?这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。*
2023-05-31

python—类的属性和方法总结

一、类的属性总结(类的属性定义在方法外,对象的属性定义在方法内)理解:类的(静态)属性:(人类的五官,理解为变量)类的(动态)方法:(人类吃穿住行,理解为一个函数,至少带一个参数self,指向类本身)对象:类的实例化,之后才能有属性和方法1
2023-01-31

python静态方法和类方法有什么区别

Python中的静态方法和类方法都是与类相关联的方法,但它们有一些区别:静态方法:- 静态方法与类的实例无关,不需要访问实例中的属性或方法。- 静态方法没有默认的参数,也无法访问类中的属性或方法。- 静态方法可以通过类名或实例来调用。类方法
2023-10-11

浅谈python中的实例方法、类方法和静态方法

在学习python代码时,看到有的类的方法中第一参数是cls,有的是self,经过了解得知,python并没有对类中方法的第一个参数名字做限制,可以是self,也可以是cls,不过根据人们的惯用用法,self一般是在实例方法中使用,而cls
2022-06-04

类属性和类方法

一、 类的结构1.1 术语 —— 实例使用面相对象开发,第 1 步 是设计 类使用 类名() 创建对象,创建对象 的动作有两步:1) 在内存中为对象 分配空间2) 调用初始化方法__init__为 对象初始化对象创建后,内存 中就有了一个对
2023-01-31

python string类方法

!/usr/bin/env python-*- coding: utf-8 -*-name = "app"t = name.capitalize() #首字母大写print(t)name = "app"t = name.center(20
2023-01-31

python Str类方法

#capitalize():字符串首字符大写string = 'this is a string.'new_str = string.capitalize()print(new_str)#输出:This is a string. #cent
2023-01-31

Python类属性和方法如何调用

这篇“Python类属性和方法如何调用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python类属性和方法如何调用”文章吧
2023-07-02

python之class类和方法怎么使用

本篇内容主要讲解“python之class类和方法怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python之class类和方法怎么使用”吧!类和方法的概念和实例类(Class):用来描
2023-07-05

Python中的类和方法使用举例

1.类的属性成员变量对象的创建创建对象的过程称之为实例化,当一个对象被创建后,包含三个方面的特性对象聚丙属性和方法,句柄用于区分不同的对象,对象的属性和方法,与类中的成员变量和成员函数对应,obj = MyClass()创建类的一个实例,扩
2023-01-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录