python class's instance is behaving inconsistently.
Code.1
class A():
def __init__(self, x):
self.x = x
def update(self, x):
self.x = x
a = A(3)
a.update(5)
print a.x # prints 5
Code.2
class A():
def __init__(self, x):
self.x = x
def update(self, x):
self = A(x)
a = A(3)
a.update(5)
print a.x # prints 3
Why is 'x' attribute getting updated in the first snippet and is not getting updated in 2nd one?
Assigning to self does not change the current object. It just assigns a new value to the (local) self parameter variable.
The only special treatment that the self gets is during invocation, in the sense that
a.update(x)
is equivalent to
A.update(a, x)
Assigning to self just overrides the value of the local parameter:
def update(self, x):
# overwrite the value of self with a different instance of A
# This has no effect outside of update().
self = A(x)
a = A(3)
a.update(5)
In this case a is still the same instance from A(3). You created a new instance of A inside update() and assigned it to the self parameter, but that modification does not carry over outside of update().
Related
I am trying to access the object of class b (self.variable) inside another class a, after class b has been inherited by class c and calls an instance of class a. I don't know how to access the instance of class b that was created during the inheritance init. Additionally, a needs to inherit from class k.
Optimal would be if I could access self.variable inside class a and further pass it on without explicitly referring to the instance of class b (namely, just calling it with self.variable instead of b.variable) and without changing the values I already assigned to the variables in class c (so no re-initializing it)
I'd appreciate any help, I've been at this for hours.
class k(object):
def __init__(self):
pass
class b(object):
def __init__(self):
self.variable = 1
class c(b):
def __init__(self):
b.__init__(self)# b is inherited from & initialized
# alternative for inheritance
#super(c,self).__init__()
print("init(): " + str(self.variable))
def run(self):
self.variable = 2
print("run(): " + str(self.variable))
a()# here I need to pass the instance of b
class a(k):
def __init__(self):
k.__init__(self)# a() needs to inherit from k()
# ERROR: cannot access variables of b()
print("a(): " + str(self.variable))
if __name__ == "__main__":
c().run()
I think I figured out how to do it.
If passing the instance is enough, this would work:
class k(object):
def __init__(self):
pass
class b(object):
def __init__(self):
self.bb = self.bb()
class bb:
def __init__(self):
self.variable = 1
class c(b):
def __init__(self):
b.__init__(self)# b is inherited from & initialized
# alternative for inheritance
#super(c,self).__init__()
print("init(): " + str(self.bb.variable))
def run(self):
self.bb.variable = 99
print("run(): " + str(self.bb.variable))
a(self)# pass instance of b
class a(k):
def __init__(self, bInstance):
k.__init__(self)# a() needs to inherit from k()
print("a(): " + str(bInstance.bb.variable))
if __name__ == "__main__":
c().run()
As I understand it, if I want to get there via self I'd need class a to inherit from class c and class c inherits and initializes class b, the call at the end is just a() (which does what I need it to do, since a inherits everything I need):
class k(object):
def __init__(self):
pass
class b(object):
def __init__(self):
self.bb = self.bb()
class bb:
def __init__(self):
self.variable = 1
class c(b):
def __init__(self):
b.__init__(self)# b is inherited from & initialized
# alternative for inheritance
#super(c,self).__init__()
print("init(): " + str(self.bb.variable))
def run(self):
self.bb.variable = 99
print("run(): " + str(self.bb.variable))
class a(k,c):
def __init__(self):
k.__init__(self)# a() needs to inherit from k()
c.__init__(self)
print("a(): " + str(self.bb.variable))
self.run()
print("a() #2: " + str(self.bb.variable))
if __name__ == "__main__":
a()
I want to use jitclass to speed up my code. I defined a class B, has 2 member variables. One is a dict, the other is a object of class A. How to define spec? I've been stuck here for a while. Thank you.
I've got this:
TypeError: spec values should be Numba type instances, got
Below is the code:
class A(object):
pass
spec = [
('x', dict), # ------ how to write this line ?
('y', A), # ------ how to write this line ?
]
#jitclass(spec)
class B(object):
def __init__(self):
self.x = dict()
self.y = A()
You cannot specify members of a jitclass that do not have an explicit numba type. You can make this work, however if A is also a jitclass and the dict is not a standard python dict, but instead is a numba typed dict (numba.typed.Dict). The typed dict is only supported in numba version 0.43 and later:
import numba as nb
#nb.jitclass([('x', nb.float64)])
class A(object):
def __init__(self, x):
self.x = x
a_type = nb.deferred_type()
dict_type = nb.deferred_type()
spec = [
('x', dict_type),
('y', a_type),
]
a_type.define(A.class_type.instance_type)
dict_type.define(nb.typeof(nb.typed.Dict.empty(key_type=nb.int64, value_type=nb.float64)))
#nb.jitclass(spec)
class B(object):
def __init__(self, x, y):
self.x = x
self.y = y
a = A(3.0)
d = nb.typed.Dict.empty(key_type=nb.int64, value_type=nb.float64)
d[1] = 1.1
b = B(d, a)
print(b.y.x) # => 3.0
print(b.x[1]) # => 1.1
Whether or not you want to or are able to use a jitclass for A or a nb.typed.Dict in place of a python dict will depend on your specific use-case.
I'm really at a loss here. I need to pass arguments to the wrapper; these arguments change with runtime. Any idea how this could be solved using wrappers for classes?
def wrapper(x=None):
def decorate(cls):
def fct(self):
print('wrapper argument is: %s' % x)
cls.fct = fct
return cls
return decorate
a = 'first'
#wrapper(x=a)
class Test():
pass
test = Test()
test.fct() # Prints: first
a = 'second'
test.fct() # Prints: first (instead of second)
I can't put code in a comment, so here's how you'd do it.
def wrapper(x=None):
def decorate(cls):
def fct(self):
print('wrapper argument is: %s' % x[0])
cls.fct = fct
return cls
return decorate
a = ['first']
#wrapper(x=a)
class Test():
pass
test = Test()
test.fct() # Prints: first
a[0] = 'second'
test.fct() # Prints: second
The key is that strings are immutable, whereas lists are mutable. When you pass in a string, it's basically copied. When you pass in a list, you're sort of passing a reference to the original list, which is itself mutable.
Here is a minimal example:
This works in both python 3.5 and 2.7:
class A(object):
def __init__(self, foo):
self._foo = foo
class B(A):
def __init__(self, foo):
A.__init__(self, foo=foo)
b = B(1)
Change line:
A.__init__(self, foo=foo)
to
A.__init__(self=self, foo=foo)
In python 3.5 works without problems, but in python 2.7 you will receive the following error:
Traceback (most recent call last):
File "self_key.py", line 9, in <module>
b = B(1)
File "self_key.py", line 7, in __init__
A.__init__(self=self, foo=foo)
TypeError: unbound method __init__() must be called with A instance as first argument (got nothing instead)
Is self as keyword argument forbidden in python 2.7 or is this a bug?
Update
I'm aware that python will use the first parameter of a bound function to pass the reference to the object from which has been called. I also know that the __init__ function expects that this parameter is an instance of the class. In this case A.__init__ is unbound so we must provide that parameter manually.
When I asked about self as keyword argument forbidden I'm speaking about self as "the first parameter of __init__", which is supposed to receive a reference of the object to initialize. The name of the variable itself doesn't matter. We can perfectly change the name to this:, for example:
class A(object):
def __init__(this, foo):
this._foo = foo
class B(A):
def __init__(self, foo):
A.__init__(this=self, foo=foo)
b = B(1)
And it will be the same.
My question is why when calling the function we can perfectly specify that parameter as a positional argument (A.__init__(self, foo=foo)) but when we try to pass it as a keyword argument (A.__init__(this=self, foo=foo)) python 2.7 throws an error.
Actually, you don't have to use self keyword unless you're consistent. Check out this example, where I changed self to test :
class funcs():
def init(test, a, b):
test.a=a
test.b=b
def plus(test):
c = test.a + test.b
print"%d + %d = %d" %(test.a, test.b, c)
def minus(test):
c = test.a - test.b
print"%d - %d = %d" %(test.a, test.b, c)
obj = funcs()
obj.init(10, 6)
obj.plus()
obj.minus()
You can try to mix those instance name, so it won't be named self.
class A(object):
def __init__(a_obj, foo):
a_obj._foo = foo
class B(A):
def __init__(self, test, foo):
A.__init__(self, a_obj=test, foo=foo) # here you pass object of class B and actually another object of class B
a = A(2)
b = B(a, 1)
Giving output:
A.__init__(self, a_obj=test, foo=foo)
TypeError: __init__() got multiple values for keyword argument 'a_obj'
I'm not sure what actually you want to accomplish by passing those object like this. In your code, self in class A and self in class B are not the same objects.
I suppose that here: A.__init__(self=self, foo=foo) you are doing something like A_instance=B_instance (self=self)
Always use self for the first argument to instance methods.
Source: Python Documentation
I have a repeating set of lengthy try/except1/except2/etc blocks in a series of class methods that only differ by the outside class method being called on an outside class instance. Below is a simplified version (there are actually 4 exceptions that I am handling and eight methods that only differ by the instance method being called):
class MyClass(object):
def __init__(self):
self.arg = 'foo'
def method1(self, arg1):
err = -1
y = None
try:
x = AnOutsideClass(self.arg) # Creates a class instance of an imported class
y = x.outsideclassmethod1(arg1) # Calls an instance method that returns another different class instance
except MyException1:
x.dosomething() # Needed to handle error
except MyException2:
err = 0
finally:
del x
return y, err
def method2(self, arg1, arg2, arg3):
err = -1
y = None
try:
x = AnOutsideClass(self.arg)
y = x.outsideclassmethod2(arg1, arg2, arg3) # This is the only thing changed
# A different method with different argument requirements
except MyException1:
x.dosomething()
except MyException2:
err = 0
finally:
del x
return y, err
def method3 ...
I have been trying various ways of condensing this code by trying to wrap the two statements in the try: portion of the code by using nested functions, decorators, etc, but seem to fail due to the fact that I am have trouble translating other examples of this due to: 1) am creating a class instance that needs to be used later in one of the except blocks and 2) am calling an instance method and 3) I need to return the result of the instance method.
Is there anyway of accomplishing this with partial from functools or descriptors or any other means? I have a clunky implementation currently with an extended if/elif block that picks the instance method based on an integer code that I use in a wrapper function, but am thinking there must be a more elegant way. I am relatively new to Python and am at a loss...
You could use a function factory (i.e., a function that returns a function).
def make_method(methname):
def method(self, *args):
err = -1
y = None
try:
x = AnOutsideClass(self.arg) # Creates a class instance of an imported class
y = getattr(x, methname)(*args) # Calls an instance method that returns another different class instance
except MyException1:
x.dosomething() # Needed to handle error
except MyException2:
err = 0
finally:
del x
return y, err
return method
class MyClass(object):
def __init__(self):
self.arg = 'foo'
method1 = make_method('outsideclassmethod1')
method2 = make_method('outsideclassmethod2')
The make_method is passed the outside method name as a string.
getattr is used (inside method) to get the actual method from x given the string methname.
getattr(x, 'foo') is equivalent to x.foo.
The * in def method(self, *args) tells Python that method can accept an arbitrary number of positional arguments.
Inside method, args is a tuple. The * in y = getattr(x, methname)(*args) tells Python to pass the elements in args as individual arguments to the method returned by getattr(x, methname). The * unpacking operator is explained in the docs, here, and also in this blog.