class Example:
def __init__(self, x):
self.x = x
def function(self, y=self.x):
pass
Example(72)
When I run this code, I get the following error.
Traceback (most recent call last):
File "/home/millertime/Desktop/example.py", line 1, in <module>
class Example:
File "/home/millertime/Desktop/example.py", line 7, in Example
def function(self, y=self.x):
NameError: name 'self' is not defined
Evidently, Python isn't happy with having an argument preset to a class variable. Is there a proper way to do this? I know the class info is being passed in the first argument, self
. Any way to reference this further along to make my code possible? I've tried changing y=self.x
to y=x
, but as I suspected this just threw a NameError
. I'm well aware of other ways to do this inside the function, but I'm interested if it's possible or not.
CodePudding user response:
In python, the expressions in default arguments of functions are calculated when the function is defined, not when it's called. In the case above there won't be any instantiation hence the error.
You can do this instead
class Example:
def __init__(self, x):
self.x = x
def function(self, y=None):
if y is None:
y=self.x
pass
Example(72)
CodePudding user response:
Python doc says:
Default parameter values are evaluated from left to right when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call.
When you set default parameter value y = self.x
, it is evaluated when the function definition is executed, at which point self
(an instance) is not defined.
A common remedy (also proposed in the doc) is to set y = None
as default, and use if y is None
to check whether parameter value for y
is given.
class Example:
def __init__(self, x):
self.x = x
def function(self, y=None):
if y is None:
y = self.x
return y
ex = Example(72)
print(ex.function()) # 72
print(ex.function(42)) # 42
CodePudding user response:
This works, though it's not necessarily more palatable than the other ways to do it inside the function that you mention:
class Example:
def __init__(self, x):
self.x =x
def _function(self, y):
return y * self.x
def normal_func(self, y):
return y self.x
def __getattr__(self, attr):
if attr == 'function':
return lambda y=self.x: self._function(y)
return super().__getattr__(self, attr)
a = Example(5)
print(a.function(10)) # should return 10 * 5
print(a.function()) # should return 5 * 5
print(a.normal_func(7)) # should return 7 5
prints:
50
25
12
Note that you might not get what you expect if you hold a reference to the function object, then execute it later:
f = a.function # This instance of the function has default y=5
a.x = 8 # This doesn't change default y in our stored f
print(f()) # So this gives 5 * 8
prints:
40