我很难在之间获得积分差
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"
现在看起来很像你的第二个例子。