Python和C#阐明了类的对象如何使用函数并在内存中表示函数



这可能是我在Python中遇到的最奇怪的行为。考虑以下代码:

class wow:
var = 90
def __init__(self):

self.wow = 30
def great(self):
self.eme = 90
print('wow')

var = wow()
varss = wow()
varsss = wow()

print(id(var.great))
print(id(varss.great))
print(id(varsss.great))
print(var.great is varsss.great)

输出

1861171310144
1861171310080
1861171310144
False

为什么,每次我从同一个类创建一个新对象时,是否每次都会创建新函数,为什么第一个和第三个的内存地址匹配,但第二个(也不是id(wow.great)(不匹配。为什么当我比较具有相同内存地址的两者时,它会返回false?

另一个问题是,从wow类创建一个新对象,是否将wow类的所有方法都添加到该对象中,或者该对象是否在需要时从类中调用方法。我问这个问题是因为我在做var.时看不到wow类的方法。dict

此外,当我创建三个不同的实例时,这些实例中的每一个是否都有自己的函数,或者这些函数是否可以由wow类使用,并且所有实例都可以随时访问相同的函数,这样这些函数就不需要在内存中复制三次了?

最后,我想知道C#是否真的是这样,每个实例都有自己的函数(非静态(,还是每个实例只能访问其中一个函数?

SargeTM在评论(链接(中链接的帖子实际上解释了很多关于正在发生的事情。请务必查看;(。每次访问实例上的方法时,都会创建一个绑定方法对象。您可以将其视为一个单独的对象,大致以以下方式工作:

class BoundMethod:
def __init__(self, instance, method):
self.instance = instance
self.method = method
def __call__(self, *args, **kwargs):
return self.method(self.instance, *args, **kwargs)

因此,每次访问var.greatvarss.greatvarsss.great时,都会生成一个新的绑定方法对象。

您观察到的内存地址不清楚。执行print(id(var.great))时,将创建引用计数等于1的绑定方法对象,打印其id,并减少引用计数。绑定的方法对象将被取消分配。您观察到的行为很可能是python内存管理实现的组合,也可能是一些随机性。就我个人而言,当我运行代码时,所有的内存地址都是相等的——这意味着每次都使用相同的内存。

然而,当您执行print(var.great is varsss.great)时,会创建两个独立的绑定方法对象,它们具有不同的内存地址(因为很明显,现在不能使用相同的内存(。为了更清楚地观察这一点,让我们重写代码:

>>> x = var.great
>>> y = varsss.great
>>> print(id(x))
3018906862144
>>> print(id(y))
3018906862272
>>> print(x is y)
False

因此,print(var.great is varsss.great)不会比较具有相同内存地址的对象。唯一的原因是,在前面的print调用中,分配绑定方法对象时碰巧使用了相同的内存。


方法存储在类对象上。Python中的方法调用,如var.great(),本质上等同于type(var).great(var),尽管这是通过首先创建绑定方法对象来实现的,该对象大致相当于bound_method = BoundMethod(var, type(var).great)

您也可以直接将方法/函数作为属性分配给实例,但它们的行为与普通方法不同(即没有创建绑定方法对象。因此,函数不会以self作为参数调用(。使用以下代码可以观察到这种行为:

class X:
def __init__(self):
self.amazing = lambda *args: args 
x = X()
print(x.amazing())

(此代码的输出为()(

最新更新