I have:
cdef class BaseClass():
def __cinit__(self,char* name):
print "BaseClass __cinit__()"
#...
def __dealloc__():
print "BaseClass __dealloc__()"
#...
cdef class DerClass(BaseClass):
def __cinit__(self,char* name,int n):
print "DerClass __cinit__()"
#...
def __dealloc__():
print "DerClass __dealloc__()"
#...
when i call the DerClass in cyhton happen that the construcor of the BaseClass is called automatically,what it has to print is:
BaseClass __cinit__()
DerClass __cinit__()
DerClass __dealloc__()
BaseClass __dealloc__()
but it does not,it crash ones that i call the DerClass('Ciao').
why does happen so and how can i avoid calling the cinit of BaseClass.
Thank you!
The above answer may not pose quite the best solution. Reading the section "Initialisation methods: __cinit__() and __init__()" of the link above gives this information:
If your extension type has a base type, the __cinit__() method of the base type is automatically called before your __cinit__() method is called; you cannot explicitly call the inherited __cinit__() method.
and
If you anticipate subclassing your extension type in Python, you may find it useful to give the __cinit__() method * and ** arguments so that it can accept and ignore extra arguments.
So my solution would be to just replace the arguments of __cinit()__ in BaseClass so that a variable number of arguments can be passed to any derived class:
cdef class BaseClass:
def __cinit__(self, *argv):
print "BaseClass __cinit__()"
#...
def __dealloc__(self):
print "BaseClass __dealloc__()"
#...
cdef class DerClass(BaseClass):
def __cinit__(self,char* name, int n):
print "DerClass __cinit__()"
#...
def __dealloc__(self):
print "DerClass __dealloc__()"
#...
See here for an explanation of the *args variable in python
Well, you are right that you should see the cinit method called on your parent class. It says so right here in the docs.
http://docs.cython.org/src/userguide/special_methods.html
Here is what I tried using:
cdef class BaseClass:
def __cinit__(self,char* name):
print "BaseClass __cinit__()"
#...
def __dealloc__(self):
print "BaseClass __dealloc__()"
#...
cdef class DerClass(BaseClass):
def __cinit__(self,char* name,int n):
print "DerClass __cinit__()"
#...
def __dealloc__(self):
print "DerClass __dealloc__()"
#...
It compiled but it gave me this error when I tried to run it:
mike#computer:~/testing$ python runner.py
DerClass __dealloc__()
BaseClass __dealloc__()
Traceback (most recent call last):
File "runner.py", line 4, in <module>
DerClass('Ciao', 1)
File "test.pyx", line 2, in test.BaseClass.__cinit__ (test.c:488)
def __cinit__(self,char* name):
TypeError: __cinit__() takes exactly 1 positional argument (2 given)
mike#computer:~/testing$
So I changed BaseClass.cinit to also take the "int n" parameter that DerClass.cinit does:
cdef class BaseClass:
def __cinit__(self, char * name, int n):
print "BaseClass __cinit__()"
#...
def __dealloc__(self):
print "BaseClass __dealloc__()"
#...
cdef class DerClass(BaseClass):
def __cinit__(self,char* name,int n):
print "DerClass __cinit__()"
#...
def __dealloc__(self):
print "DerClass __dealloc__()"
#...
And now it seems to work fine:
mike#computer:~/testing$ python runner.py
BaseClass __cinit__()
DerClass __cinit__()
DerClass __dealloc__()
BaseClass __dealloc__()
mike#computer:~/testing$
Here is my runner.py file:
from test import *
if __name__ == "__main__":
DerClass('Ciao', 1)
Related
I have a project with the following structure:
lst_viewer/
setup.py
extensions/
instrument.pxd
instrument.pyx
read_events.pyx
src/
lst_viewer/
extensions/
__init__.py
Here is my setup.py file:
import os
from Cython.Distutils import build_ext as cython_build_ext
from setuptools import find_packages, setup
from distutils.core import setup, Extension
EXTENSIONS = [
Extension('lst_viewer.extensions.instrument',sources = [os.path.join('extensions','instrument.pyx')]),
Extension('lst_viewer.extensions.read_events',sources = [os.path.join('extensions','read_events.pyx')]),
]
CMDCLASS = {'build_ext' : cython_build_ext}
setup(name="lst_viewer",
packages=find_packages('src'),
include_package_data=True,
package_dir={'': 'src'},
ext_modules=EXTENSIONS,
cmdclass=CMDCLASS)
Here is my instrument.pxd file:
cdef class Instrument:
cdef int nbdet
cdef class D11Instrument:
pass
cdef Instrument get_instrument(str name)
Here is my instrument.pyx file:
cdef class Instrument:
pass
cdef class D11Instrument(Instrument):
def __cinit__(self):
self.nbdet = 3
cdef Instrument get_instrument(str name):
if name == "D11":
return D11Instrument()
And here is my read_events.pyx file:
from instrument cimport Instrument, get_instrument
def read_events(str instrument_name):
cdef Instrument instr = get_instrument(instrument_name)
I have problems with importing the Instrument class and get_instrument function from the other pyx file of the project (read_events.pyx). Indeed, the code compiles but, when running it, I get a ModuleNotFoundError: No module named 'instrument' error. I tried to add an (empty) __init__.pxd to the lst_viewer/extensions directory but it did not help. Would you have any idea about what I am doing wrong ?
Here is my situation, what should I write in place of the comment?
Thank you in advance, and sorry if I asked something alredy answered.
I have alredy searched for an answer but without success.
#!/usr/bin/python3.4
class A(object):
def __init__(self):
print("A constructor")
class B(A):
def __init__(self):
super(B, self).__init__()
print("B constructor")
class C(A):
def __init__(self):
super(C, self).__init__()
print("C constructor")
class D(B,C):
def __init__(self):
""" what to put here in order to get printed:
B constructor
C constructor
A constructor
D constructor
or
C constructor
B constructor
A constructor
D constructor
?
(notice I would like to print once 'A constructor')
"""
print("D constructor")
if __name__ == "__main__":
d = D()
I found that changing a little the class constructors code does what I needed:
#!/usr/bin/python3.4
class A(object):
def __init__(self):
print("A constructor")
class B(A):
def __init__(self):
if self.__class__ == B:
A.__init__(self)
print("B constructor")
class C(A):
def __init__(self):
if self.__class__ == C:
A.__init__(self)
print("C constructor")
class D(B,C):
def __init__(self):
B.__init__(self) #
C.__init__(self) # if B constructor should be
A.__init__(self) # called before of C constructor
print("D constructor") #
# C.__init__(self) #
# B.__init__(self) # if C constructor should be
# A.__init__(self) # called before of B constructor
# print("D constructor") #
if __name__ == "__main__":
d = D()
Let's have an example.
cdef class Example:
attr2 = None
cdef attr3
cdef object attr4
def __init__(self):
self.attr1 = Obj()
self.attr2 = Obj()
self.attr3 = Obj()
self.attr4 = Obj()
The line with the assignment to self.attr1 will raise an AttributeError saying: "object has no attribute 'attr1'.
If try with the self.attr2 it raises also the exception but with the message: "object attribute 'attr2' is read-only".
And if uses the keyword cdef, an it doesn't have an explicit type, the compilation process will fail.
If this attribute is defined with the type object, it looks nice. But different instances of the Example class will have this attr4 like a singleton and any interaction with one of them will be visible for the other instances and, in this case, I want to have an Obj() instance unique for each of them.
You can try something like this :
class Obj(object):
# At first I define a class Obj() to match your example
def __init__(self):
self.abc = 32
self.xyz = "xyzxyz"
# Then I can define the Example class
cdef class Example:
cdef public:
object attr1, attr2, attr3, attr4
def __init__(self):
self.attr1 = Obj()
self.attr2 = Obj()
self.attr3 = Obj()
self.attr4 = Obj()
It seems to be cythonized/compiled without error and you have access to the attributes related to the Obj object :
In [11]:
a = Example()
a.attr1.abc
Out[11]:
32
Say I have the following:
def foo(arg1, arg2, arg3 = default, *args, *kwargs*):
"""This function is really cool."""
return
How can I define a new function functionprinter(f) so that functionprinter(f) would print
foo(arg1, arg2, arg3 = default, *args, *kwargs*)
This function is really cool.
or something of that nature? I already know foo.__name__ and foo.__doc__ and have seen the inspect module, specifically here: Getting method parameter names in python but can't seem to string together everything, in particular having the default arguments print properly. I am using Python 3.4.1.
Yup! You can with the inspect module:
import inspect
def foo(arg1, arg2, arg3=None , *args, **kwargs):
"""This function is really cool."""
return
def functionprinter(f):
print("{}{}".format(f.__name__, inspect.signature(f)))
print(inspect.getdoc(f))
functionprinter(foo)
Prints:
foo(arg1, arg2, arg3=None, *args, **kwargs)
This function is really cool.
Note that I changed your default argument to None just for this demonstration because I didn't have the variable default defined.
You can use inspect.signature (to represents the call signature of a callable object and its return annotation.) and inspect.getdoc :
>>> print(inspect.signature(foo))
(arg1, arg2, arg3=3, *args, **kwargs)
>>> inspect.getdoc(foo)
'This function is really cool.'
>>> print ('\n'.join((foo.__name__+str(inspect.signature(foo)),inspect.getdoc(foo))))
foo(arg1, arg2, arg3='', *args, **kwargs)
This function is really cool.
I have a little problem with a variable update.
I have my variable declared in my first function as such self.TestVar = 0
then if a certain count ==2 self.TestVar = 2
in a second function (in the same class) but called from within another class I want returning self.TestVar. no way.
AttributeError: 'ThndClass' object has no attribute 'TestVar'
I am most certainly not doing the good way, all I want is accessing self.TestVar = 2 from my other class that's it's but I can't find a proper way to do so in Python.
It looks like my issue is that I get my self.TestVar = 2 in a "if" statement which make it live in another scope (or I might be wrong).
import sys
from PIL import Image
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.initUI()
def initUI(self):
self.TestVar = 0
self.TheCount = 2
if self.TheCount ==2:
self.TestVar = 2
ThndClass()
def Getit(self):
print("called correctly")
print(self.TestVar)
return self.TestVar
def main():
app = QtGui.QApplication([])
mw = MainWindow()
sys.exit(app.exec_())
class ThndClass(QtGui.QWidget):
def __init__(self):
super(ThndClass, self).__init__()
self.initUI2()
def initUI2(self):
print("Class Called")
print(MainWindow.Getit(self))
if __name__ == '__main__':
main()
If I remove the 2nd Class call :
import sys
from PIL import Image
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.initUI()
def initUI(self):
self.TestVar = 0
self.TheCount = 2
if self.TheCount ==2:
self.TestVar = 2
self.Getit()
def Getit(self):
print("called correctly")
print(self.TestVar)
return self.TestVar
def main():
app = QtGui.QApplication([])
mw = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
This works correctly, but I want to be able to call def Getit() from another class and get my result. Or simply get a way to directly access self.TestVar from my other class.
When you call
MainWindow.Getit(self)
in ThndClass.initUI2, you are treating MainWindow and ThndClass interchangeably, when they do not have the same attributes. Here is an actual minimal example:
class Parent():
def __init__(self):
pass
class Child1(Parent):
def __init__(self):
super().__init__()
self.foo = "foo"
def method(self):
print(type(self))
print(self.foo)
class Child2(Parent):
def __init__(self):
super().__init__()
self.bar = "bar"
c1 = Child1()
Child1.method(c1) # pass Child1 instance to Child1 instance method
c2 = Child2()
Child1.method(c2) # pass Child2 instance to Child1 instance method
and full output:
<class '__main__.Child1'> # gets a Child1 instance
foo # first call succeeds
<class '__main__.Child2'> # gets a Child2 instance (which doesn't have 'foo')
Traceback (most recent call last):
File "C:/Python34/so.py", line 25, in <module>
Child1.method(c2)
File "C:/Python34/so.py", line 11, in method
print(self.foo)
AttributeError: 'Child2' object has no attribute 'foo' # second call fails
However, as it is not clear what exactly the code is supposed to be doing, I can't suggest a fix. I don't know why you create but don't assign a ThndClass instance in MainWindow.initUI, for example.
Here is one possible fix; pass a Child1 instance to Child2.__init__, then use it either as an argument to Child2.method:
class Child2(Parent):
def __init__(self, c1): # provide Child1 instance as parameter
super().__init__()
self.bar = "bar"
self.method(c1) # pass instance to Child2.method
def method(self, c1):
c1.method() # call Child1.method with c1 as self parameter
(Note that c1.method() is equivalent to Child1.method(c1).)
or make it an instance attribute:
class Child2(Parent):
def __init__(self, c1): # provide Child1 instance as parameter
super().__init__()
self.bar = "bar"
self.c1 = c1 # make Child1 instance a Child2 instance attribute
self.method() # now no argument needed
def method(self):
self.c1.method() # call Child1.method with c1 as self parameter
(Note that self.c1.method() is equivalent to Child1.method(self.c1).)
In use (either way):
>>> c1 = Child1()
>>> c2 = Child2(c1)
<class '__main__.Child1'> # Child1.method gets a Child1 instance
foo # and is called successfully
Thank's to your help jonrsharpe here's my working code :)
import sys
from PIL import Image
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.initUI()
def initUI(self):
self.TestVar = 0
self.TheCount = 2
if self.TheCount ==2:
self.TestVar = 2
Themain = self
ThndClass(Themain)
def Getit(self):
print("called correctly")
print(self.TestVar)
return self.TestVar
def main():
app = QtGui.QApplication([])
mw = MainWindow()
sys.exit(app.exec_())
class ThndClass(QtGui.QWidget):
def __init__(self, Themain):
super(ThndClass, self).__init__()
self.Themain = Themain
self.initUI2()
def initUI2(self):
print("Class Called")
print(self.Themain.Getit())
if __name__ == '__main__':
main()
All working good now : ) Thanks you very much !