在创建实例后,使构造函数和赋值变量有什么区别



我很难在之间获得积分差

class Item:
def __init__(self, name):
self.name = name
item = Item("Phone")

并分配类似的变量

class Item:
def __str__(self):
return self.name
item = Item()
item.name = "Phone"

我花了两个多小时才理解,但我找不到问题的答案

Meh,在第一种情况下,您需要引入名称才能实例化。而在第二秒你没有。另一个区别是,只需执行print(item),就可以看到区别。

在第一种情况下,类Item的所有实例都将具有属性name。在第二种情况下,您将属性name仅添加到类Item的单个实例中。(__str__方法独立于动态分配name属性。)

类类似于为如何创建对象而定义的原理图。对象是您实际使用的对象(大部分时间)。

class Item:                       # every object i make is called "Item"
def __init__(self, name):     # creating an object requires a name
self.name = name          # the name is stored as the attribute "name"
item = Item('banana')             # create an item with name=banana

Python中的许多对象都可以动态地为它们分配额外的属性,正如您上面演示的那样。这超出了类的原理图设置范围,但这是完全允许的。

item = Item('banana')
item.is_tasty = True              # nom nom nom...

通常,您不会动态分配属性,因为如果属性开始出现在类定义之外,其他人很难对您的代码进行推理。

动态属性赋值也适用于类之外的实例。例如,您可以为函数分配一个属性(我相信django曾经这样做过)。同样,这不是标准做法,但这是可能的。

def running_sum(x):
running_sum.total += x
return running_sum.total
running_sum.total = 0
print(running_sum(3))
print(running_sum(8))
print(running_sum(9))
# prints:
# 3
# 11
# 20

__init__是一种方便,因此您不需要在创建后进行赋值。

当你调用一个类型时,你可以想象它的定义是这样的:

def Item_(name):
obj = Item.__new__(Item, name)
if isinstance(obj, Item):
obj.__init__(name)
return obj
item = Item_("Phone")

__init__被调用时,self被绑定到Item的新实例,使得";内部";调用Item时,self绑定到分配给item的对象,name绑定到字符串"Phone",因此__init__内部的self.name = name与外部的item.name = "Phone"完全等效。


挖掘更深

您可能会认为我必须在函数名Item_和实际类名Item之间进行区分,这有点像疣。然而,要认识到Item_的定义实际上是一个纯粹的Python";模拟";CCD_ 23。

(回想一下,__new__是一个静态方法,只是有特殊情况,所以如果覆盖它,就不需要显式地将其修饰为这样。)

# Since type is the metaclass, self is an instance of the metaclass,
# namely the class being instantiated.
def __call__(self, *args, **kwargs):
obj = self.__new__(self, *args, **kwargs)
if isinstance(obj, self):
obj.__init__(*args, **kwargs)
return obj
item = Item("Phone")
# item = Item.__call__("Phone")
#      = type.__call__(Item, "Phone")

考虑到这个定义,我们可以";内联";CCD_ 25和CCD_ 26的定义使得CCD_

item = Item.__new__(Item, "Phone")
if isinstance(item, Item):
item.name = "Phone"

检查__new__返回的值的类型的整个业务是必要的,因为__new__不一定返回其第一个参数指定的类型的实例。但在这种情况下确实如此(我们没有重写Item.__new__来做任何奇怪的事情),所以我们可以进一步简化到的内联

item = Item.__new__(Item, "Phone")
item.name = "Phone"

由于没有覆盖__new__Item.__new__解析为object.__new__,它接受但忽略除第一个参数外的所有参数,因此我们可以进一步内联对__new__的调用,并删除被忽略的参数

item = object.__new__(Item)
item.name = "Phone"

现在看起来很像你的第二个例子。

相关内容

  • 没有找到相关文章

最新更新