Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

assigning class variable as default value to class method argument

I would like to build a method inside a class with default values arguments taken from this class. In general I do filtering on some data. Inside my class I have a method where normally I pass vector of data. Sometimes I don't have the vector and I take simulated data. Every time I do not pass a particular vector I would like to take simulated data by default. I thought it should be an easy construction where inside my method definition I say a=self.vector. But for some reason I have an error NameError: name 'self' is not defined. The simplified construction is:

class baseClass(object):  # This class takes an initial data or simulation     def __init__(self):         self.x = 1         self.y = 2  class extendedClass(baseClass): # This class does some filtering     def __init__(self):         baseClass.__init__(self)         self.z = 5     def doSomething(self, a=self.z):         self.z = 3         self.b = a  if __name__ == '__main__':     a = extendedClass()     print a.__dict__     a.doSomething()     print a.__dict__ 

An output I expected should be:

{'y': 2, 'x': 1, 'z': 5} {'y': 2, 'x': 1, 'z': 3, 'b': 5} 

I tried default assignment as def doSomething(self, a=z): obviously it doesn't work ever. As far as I understand self.z is visible in this scope and should not be a problem to have it as a default value. Don't know why I have this error and how to do it. This is probably an easy question, but I try to figure it out or find the solution with no lack for sometime already. I found similar questions only for other languages.

like image 375
tomasz74 Avatar asked Mar 03 '13 18:03

tomasz74


People also ask

Can we give default value to arguments?

In addition to passing arguments to functions via a function call, you can also set default argument values in Python functions. These default values are assigned to function arguments if you do not explicitly pass a parameter value to the given argument. Parameters are the values actually passed to function arguments.

How can we set default value to the variable?

You can set the default values for variables by adding ! default flag to the end of the variable value. It will not re-assign the value, if it is already assigned to the variable.

What are default arguments where are the default arguments assigned?

A default argument is a value in the function declaration automatically assigned by the compiler if the calling function does not pass any value to that argument. The values passed in the default arguments are not constant. These values can be overwritten if the value is passed to the function.

Do class variables have default values?

Instance variables have default values. For numbers, the default value is 0, for Booleans it is false, and for object references it is null. Values can be assigned during the declaration or within the constructor. Instance variables can be accessed directly by calling the variable name inside the class.


2 Answers

Your understanding is wrong. self is itself a parameter to that function definition, so there's no way it can be in scope at that point. It's only in scope within the function itself.

The answer is simply to default the argument to None, and then check for that inside the method:

def doSomething(self, a=None):     if a is None:         a = self.z     self.z = 3     self.b = a 
like image 111
Daniel Roseman Avatar answered Sep 29 '22 11:09

Daniel Roseman


Here's the disassembly of the code for a simple example module. A code object is a read-only container for bytecode, the constants and names it uses, and metadata about the number of local variables, required stack size, etc. Notice that all of the code objects are compiled as constants. These are created at compilation time. But the objects class A and function test are instantiated at execution time (e.g. when the module is imported).

To make the class, BUILD_CLASS takes the name 'A', the bases tuple (object,), and a dict that contains the attributes of the class namespace. This is like manually instantiating a type by calling type(name, bases, dict). To make the dict, a function is created from code object A and called. Finally, the class object is stored in the module namespace via STORE_NAME.

In code object A, self.z is loaded on the stack as the argument to MAKE_FUNCTION. The bytecode op LOAD_NAME will search for self in the current locals (i.e. the class namespace being defined), the module globals, and builtins. This will obviously fail if self isn't defined in the global or builtins scope; it clearly isn't defined in the local scope.

If it did succeed, however, the function would be created with (self.z,) as its __defaults__ attribute, and then stored to the local name test.

>>> code = compile(''' ... class A(object): ...   def test(self, a=self.z): pass ... ''', '<input>', 'exec')  >>> dis.dis(code)   2           0 LOAD_CONST               0 ('A')               3 LOAD_NAME                0 (object)               6 BUILD_TUPLE              1               9 LOAD_CONST               1 (<code object A ...>)              12 MAKE_FUNCTION            0              15 CALL_FUNCTION            0              18 BUILD_CLASS                       19 STORE_NAME               1 (A)              22 LOAD_CONST               2 (None)              25 RETURN_VALUE  >>> dis.dis(code.co_consts[1]) # code object A   2           0 LOAD_NAME                0 (__name__)               3 STORE_NAME               1 (__module__)    3           6 LOAD_NAME                2 (self)               9 LOAD_ATTR                3 (z)              12 LOAD_CONST               0 (<code object test ...>)              15 MAKE_FUNCTION            1              18 STORE_NAME               4 (test)              21 LOAD_LOCALS                       22 RETURN_VALUE        

@uselpa: Your pastebin example (rewritten for 2.x):

>>> code = compile(''' ... default = 1 ... class Cl(object): ...     def __init__(self, a=default): ...         print a ... Cl() ... default = 2 ... Cl() ... ''', '<input>', 'exec') >>> dis.dis(code)   2           0 LOAD_CONST               0 (1)               3 STORE_NAME               0 (default)    3           6 LOAD_CONST               1 ('Cl')               9 LOAD_NAME                1 (object)              12 BUILD_TUPLE              1              15 LOAD_CONST               2 (<code object Cl ...>)              18 MAKE_FUNCTION            0              21 CALL_FUNCTION            0              24 BUILD_CLASS                       25 STORE_NAME               2 (Cl)    6          28 LOAD_NAME                2 (Cl)              31 CALL_FUNCTION            0              34 POP_TOP                 7          35 LOAD_CONST               3 (2)              38 STORE_NAME               0 (default)    8          41 LOAD_NAME                2 (Cl)              44 CALL_FUNCTION            0              47 POP_TOP                           48 LOAD_CONST               4 (None)              51 RETURN_VALUE         

As you can see, class object Cl (and function object __init__) is only instantiated and stored to the local name 'Cl' once. The module executes sequentially at run time, so subsequently rebinding the name default will have no effect on the default value in __init__.

You could dynamically instantiate a new function using the previously compiled code and a new default value:

>>> default = 1 >>> class Cl(object): ...     def __init__(self, a=default): ...         print a ...   >>> from types import FunctionType >>> default = 2 >>> Cl.__init__ = FunctionType( ...   Cl.__init__.__code__, globals(), '__init__', (default,), None) >>> c = Cl() 2 

This reuses the already compiled code object from __init__.__code__ to create a function with a new __defaults__ tuple:

>>> Cl.__init__.__defaults__ (2,) 
like image 25
Eryk Sun Avatar answered Sep 29 '22 12:09

Eryk Sun