在Python中,当作为类方法定义中的默认值传递时,赋值运算符是否会访问类或实例变量?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Python中,当作为类方法定义中的默认值传递时,赋值运算符是否会访问类或实例变量?相关的知识,希望对你有一定的参考价值。
对于Python 3.7
我有一个类属性(类范围变量)的类:
class foo:
var="value goes here"
以及在类的init方法中创建的实例变量:
def __init__(self, var=var):
self.var=var
Passing class variable to parameter
类变量与init的参数具有相同的名称,这并不会使解释器混淆,因为解释器将“=”符号左侧的任何字段视为方法范围内的新变量。它通过为方法的范围填充新的命名空间(变量字典)来实现这一点,并以数组的形式实现: parameters[1] = "var"
或一个关联数组:parameters['var'] = pointer_to_value
。然后解释器查看方法体内部并将通用引用替换为“=”的任何引用,这些引用出现在“=”符号的右侧。实际上,这是一个谎言,但理解它比实际更简单:
解释器识别匹配的正则表达式
.*= *var(,{0,1}| *) *(;{0,1}| *)
,然后将相应的pointer_to_value传递给程序的调用堆栈。因此,解释器不关心参数的命名,也不关心var = var的模糊性。可以解决歧义的事实是语言结构的副作用,而不是有意的设计决策。毕竟,问问自己,在定义方法时,为什么要从您定义的方法内部访问变量?那么为什么要在方法定义中调用父作用域中的变量赋值操作?这些都是不合逻辑的行为,并且它们的命名空间可能性是互斥的,因此解释器永远不需要解决模糊性问题。
相反,解释器将“=”符号的右侧视为现有值,并在类的命名空间中搜索变量定义。
Storing parameter in Instance Variable
在该方法中,实例变量也具有与类变量和参数相同的名称,并且这在init方法中起作用,因为实例变量是通过self
引用访问的,例如,
self.varname = varname
The problem
方法定义
我需要从另一个方法的方法定义中访问实例变量,我想为这个函数的参数使用相同的名称:
def lookup(self, var=var):
print(var)
表达式var = var
会获取class属性还是实例属性? methodname(self)
对自己做了什么,确切地说? self
是对实际对象的引用,还是仅仅将解释器的行为从静态方法更改为实例方法?解释器是否自动将“=”符号右侧的上下文作为methodname(object)
中输入的任何对象的实例属性?
方法体
在方法体内,如果我分配给var
......
def lookup(self, var=var):
var = var
- 它会将它存储在类变量,实例变量或具有相同名称的新变量中吗?
- 它会获得类变量,实例变量或方法的变量吗?
- 我如何明确引用这些变量?
我已经阅读了文档和几个OOP教程,以及最近的一本书,这对我来说仍然不太清楚。
您可以访问实例变量的唯一方法是作为self
的属性。
当你只是引用var
时,那绝不是一个实例变量;它始终是本地的,封闭的,全局的或内置变量。
在您的方法定义中:
def lookup(self, var=var):
print(var)
...你有一个名为var
的参数。参数是局部变量。身体内的print(var)
打印出局部变量。
那这个呢?
def lookup(self, var=var):
var = var
同样,var
是一个局部变量 - 一个参数。因此,您只需将该局部变量的当前值分配给同一个变量。这没有任何有用的效果,但当然它是完全合法的。
参数的值来自哪里?在函数调用时,如果传递参数,则该参数将绑定到参数;如果不这样做,则会使用默认值填充。
好的,那么默认值来自哪里?
在函数定义时(执行def
语句时),在当前范围中查找var
,即class
定义的主体 - 并将其值作为默认值存储在函数对象中(它应该是可见的foo.lookup.__defaults__[0]
)。
所以,默认值是"value goes here"
。
请注意,它不是闭包捕获或对class属性的其他引用。当执行class
语句时,它使用相同的class
体命名空间来构建类的属性,因此最终使用foo.var
作为foo.lookup.__defaults__[0]
中相同值的另一个名称。但他们完全是这个价值的独立名称;你可以重新分配foo.var = 3
,lookup
参数的默认值仍然是"value goes here"
。
那么,回答你的具体问题:
它会将它存储在类变量,实例变量或具有相同名称的新变量中吗?
以上都不是。它将它存储在已存在的局部变量中,因为它是一个参数。
它会获得类变量,实例变量或方法的变量吗?
如果通过“方法的变量”表示参数,那么它就是最后一个。
我如何明确引用这些变量?
与您明确引用其他任何内容的方式相同:
var
是一个本地封闭的全局或内置变量。self.var
是实例属性,如果没有实例属性,则为class属性。type(self).var
是一个类属性,即使有一个实例属性。
隐式方法参数self
是实例。因此,虽然self.var
是实例变量,但您需要使用类对象作为前缀来访问类变量。有时,您可能不知道类对象,然后您可以简单地使用__class__
属性,即类变量是self.__class__.var
。
回答你的三个问题1.你在lookup
方法中的任务将创建一个名为var
的新变量。 2.它会得到你传递给方法的论点(我猜你的意思是“方法的变量”3。下面的代码展示了如何显式访问这些变量(在__init__
中说明了它,但它没有'真的很重要你在哪个方法。
class A(object):
var = 'class_variable'
def __init__(self, var=var):
print('Argument var={}'.format(var))
var = var
self.var = var
print('Instance var={}'.format(self.var))
print('Class var={}'.format(self.__class__.var))
print('Alternative access to Class var={}'.format(A.var))
这给了
>>> a = A()
Argument var=class_variable
Instance var=class_variable
Class var=class_variable
Alternative access to Class var=class_variable
>>> b = A('v')
Argument var=v
Instance var=v
Class var=class_variable
Alternative access to Class var=class_variable
>>> c = A()
Argument var=class_variable
Instance var=class_variable
Class var=class_variable
Alternative access to Class var=class_variable
我会尽力回答你的问题,但如果我可以先解决你的问题:
我想为这个函数的参数使用相同的名称
不要这样做。这样做没有合理的理由,如果它让您感到困惑,现在想象一下,当您在几小时/几天/几周/几个月/几年内查看代码时,您会感觉如何。想象一下,其他人如何看待你的代码会有什么感受。
对于我写的所有内容,想象一下我们有一个名为bob
的实例
这将导致bob.var
在每次实例化时都是“值在这里”。每个新对象都将var
设置为“值在这里”
class foo:
var="value goes here"
这将导致bob.var
成为在实例化期间传递给foo的任何值。如果没有通过,它将默认为“值到这里”
def __init__(self, var=var):
self.var=var
如果没有传递,这将打印传递的任何内容或“值到此处”
def lookup(self, var=var):
print(var)
这没有任何作用,因为所讨论的var
是局部范围的,并且只有在方法结束时才存在
def lookup(self, var=var):
var = var
我希望这有帮助,只需重申:为不同的变量使用不同的变量名称。
以上是关于在Python中,当作为类方法定义中的默认值传递时,赋值运算符是否会访问类或实例变量?的主要内容,如果未能解决你的问题,请参考以下文章