python new init_python的new与init

特别说明:

这篇文章的灵感来源于stackoverflow的一个提问,准确说,我只是做了些知识梳理的工作,对其中的优秀回答进行了总结和提炼,旨在帮助自己和读者对此有个深刻的认识。

本文章节中的new是__new__的简写,init是__init__的简称,只是为了语言叙述的方便而做出的省略。

Part I: 为什么new总是先于init?

new是静态的类方法,static method。

init是实例方法。

它们有不同的参数与返回值:

new的参数总是:cls 返回值总是self

init的参数总是:self 总是无返回值

Part II: 三段代码的思考

Block 1: 基于原文的代码

class B(object):

_dict = dict()

def __new__(cls):

if 'key' in B._dict:

print("EXISTS:", B._dict['key'])

return B._dict['key']

else:

print("NEW")

return super(B, cls).__new__(cls)

def __init__(self):

print("INIT")

B._dict['key'] = self

print("")

b1 = B()

b2 = B()

b3 = B()

# 运行结果如下:

NEW

INIT

EXISTS: <__main__.b object at>

INIT

EXISTS: <__main__.b object at>

INIT

关于原文中的代码解释:

在每次实例化之前,也就是new的操作时,都查询了是否存在第一个实例。在第一次初始化时,把第一个实例self赋值给了类的公有属性:test_dict。之后的每次实例化之前,new都会查询到它(实例)已经存在,new并且总是返回了第一个实例给了init。然后init参与对该实例(总是第一个实例)进行构建工作。

我只能揣测,原问题的作者似乎意外创建了一个单例的类。你可以在init中执行print(self),会发现打印出来的对象总是第一个实例。当然,如果确实是想要实现单例模式,应该使用装饰器。即:

def singleton(cls):

instances = {}

def getinstance():

if cls not in instances:

instances[cls] = cls()

return instances[cls]

return getinstance

@singleton

class MyClass:

...

为什么instances使用的是字典?因为Python总是用字典去存储一个新的实例,并且init中的属性也同样以字典的方法存储的。当然,如果你想节约内存,不使用字典而用列表,可以重载new方法,或者使用__slot__。

Block 2: 基于Block 1 的修改

class A(object):

test_dict = dict()

def __new__(cls):

if 'key' in A.test_dict:

print("EXISTS:", A.test_dict['key'])

return A.test_dict['key']

else:

print("NEW")

return super(A, cls).__new__(cls)

def __init__(self):

print("INIT")

if 'key' in A.test_dict:

print('修改')

A.test_dict['key'] += 1

else:

print('第一次创建')

A.test_dict['key'] = 0

print('')

a1 = A()

a2 = A()

a3 = A()

Block 3: 基于Block 2 的修改

class A(object):

test_dict = dict() 1.类的公有属性

def __new__(cls): 2.执行__new__

if 'key' in A.test_dict:

print("EXISTS:", A.test_dict['key'])

return super(A, cls).__new__(cls)

else:

print("NEW")

return super(A, cls).__new__(cls)

def __init__(self):

print("INIT")

if 'key' in A.test_dict:

print('修改')

A.test_dict['key'] += 1

else:

print('第一次创建')

A.test_dict['key'] = 0

print('')

a1 = A()

a2 = A()

a3 = A()

Q&A

new 总是先于 int 执行,为什么?

答:

注意事项: new是类的静态方法,

Use new when you need to control the creation of a new instance.

Use init when you need to control initialization of a new instance.

前者用于控制创建一个新实例,后者用于控制对该新实例进行初始化。

精要:

它们负责的工作不同:前者负责创建新实例,后者负责实例初始化

它们服务的层级不同:前者是cls(类),后者是self(实例本身)

__new__是秘书给领导打工,后者领导的一众小弟们打工。

为什么上述代码的__init__没有被执行,而下面的每次都正常执行了?

答:

用于我在上述代码中恶意使用了new, 没有对new进行返回实例。

new__总是第一个被Call(调用),并且他的返回值:当且仅当是一个新的实例!!

代码1中,并没有返回这个新的实例,第一次实例化对象,自动进行了__int,后面的,

都是只创建了新示例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值