I have two .py files, one for the main(main.py) module and the other containing a class and its subclass (sub.py). From the main file, I use the class as follows.
## (main.py)
# Import the superclass
from sub import Class1
# Import the subclass
from sub import Class2
# Assign the object (it gives an error as described below)
myVariable=Class2()
where I write the two classes in sub.py as
## (sub.py)
class Class1:
def __init__(self, nugget=0):
self.eigval=nugget
self.eigvec=nugget
self.explained=nugget
class Class2(Class1):
def __init__(self, nugget=0):
super().__init__(eigval, eigvec, explained)
self.ppc=nugget
self.vol=nugget
self.corr=nugget
self.cov=nugget
The error I'm getting is
NameError: name 'eigval' is not defined
although I an inheriting the variable eigval using the super() in the subclass.
Why would that be??
You don't need to pass anything other than nugget to Class2
class Class2(Class1):
def __init__(self, nugget=0):
super().__init__(nugget)
self.ppc=nugget
self.vol=nugget
self.corr=nugget
self.cov=nugget
You are otherwise correct that super().__init__ will call the __init__ from Class1 and therefore your Class2 instance will have eigval, eigvec, and explained members.
>>> c = Class2()
>>> c.eigval
0
Related
I have scenario where I am passing a file name and checking if it has argument start as constructor if it has then I have to create instance of that class.
Consider the example where I have a file named test.py which have three class namely A,B,C now only class A has start parameter others have other different parameter or extra parameter.
#test.py
class A:
def __init__(self, start=""):
pass
class B:
def __init__(self, randomKeyword, start=""):
pass
class C:
def __init__(self):
pass
Now I want to write a script which takes test.py as an argument and create instance of A. Till now my progress is
detail = importlib.util.spec_from_file_location('test.py', '/path/to/test.py')
module = importlib.util.module_from_spec(detail)
spec.loader.exec_module(mod)
Bacially I need to write a program which finds init argument of all class in file and create an instance of file with start as init argument.
As mentioned by #deceze it's not a good idea to instantiate a class on the basis of it's init parameter as we're not sure what is there. But it's possible to do it. So I am posting this answer just so that you know how it can be done.
#test.py
class A:
def __init__(self, start=""):
pass
class B:
def __init__(self, randomKeyword, start=""):
pass
class C:
def __init__(self):
pass
One of the possibility is
#init.py
import importlib.util
from inspect import getmembers, isclass, signature
detail = importlib.util.spec_from_file_location('test.py', '/path/to/test.py')
module = importlib.util.module_from_spec(detail)
spec.loader.exec_module(module)
for name, data in getmembers(mod, isclass):
cls = getattr(mod, name)
parameter = signature(cls.__init__).parameters.keys()
# parameter start
if len(parameter) == 2 and 'start' in parameter:
object = cls(start="Whatever you want")
Ofcourse it's not the best approach so more answer are welcome and if you are in this scenario consider #deceze comment and define a builder.
I have a script that I am currently working on, named exp1.py and it's located in
/project/exp1.py
In this script, I am trying to call a function named computelikelihood(), which is inside the class Class(), which is in script method.py, in a different directory:
/project/methods/c_CLASS/method.py
So, in my code in exp1.py, I do this:
import sys
sys.path.append('/project/methods/c_CLASS/')
Which gets me to the folder where method.py is located, but when I want to call the Class() from the method.py, so that I get the function computelikelihood(), that I actually want, I get error. I try this:
from method import Class
from Class import computelikelihood
But I get ImportError: No module named Class. Can anyone help?
EDIT
This is how the __init__ of my Class looks like:
class Class:
def __init__(self,e2wl,w2el,label_set):
self.e2wl = e2wl
self.w2el = w2el
self.workers = self.w2el.keys()
self.examples = self.e2wl.keys()
self.label_set = label_set
Since you are trying to use a method from a Class, you should do so via the class. Do not import the function alone as it isn't intended to be used as such:
from method import Class
Class.computelikelihood()
However, this only works if computelikelihood is a static/class method:
class Class:
#classmethod
def computelikelihood(cls):
...
# or
#staticmethod
def computelikelihood():
...
If it's an instance method:
class Class:
def computelikelihood(self):
...
You'll need to first instantiate an object of class Class:
from method import Class
classObject = Class()
classObject.computelikelihood()
I'm fairly new to python and currently attempting to write a unit test for a class, but am having some problems with mocking out dependencies. I have 2 classes, one of which (ClassB) is a dependency of the other (ClassC). The goal is to mock out ClassB and the ArgumentParser classes in the test case for ClassC. ClassB looks as follows:
# defined in a.b.b
class ClassB:
def doStuff(self) -> None:
# do stuff
pass
def doSomethingElse(self) -> None:
# do something else
pass
ClassC:
# defined in a.b.c
from .b import ClassB
from argparse import ArgumentParser
class ClassC:
b
def __init__(self) -> None:
arguments = self.parseArguments()
self.b = ClassB()
self.b.doStuff()
def close(self) -> None:
self.b.doSomethingElse()
def parseArguments(self) -> dict:
c = ArgumentParser()
return return parser.parse_args()
And finally, the test case for ClassC:
# inside a.b.test
from unittest import TestCase
from unittest.mock import patch, MagicMock
from a.b.c import ClassC
class ClassCTest(TestCase):
#patch('a.b.c.ClassB')
#patch('a.b.c.ArgumentParser')
def test__init__(self, mock_ArgumentParser, mock_ClassB):
c = ClassC()
print(isinstance(c.b, MagicMock)) # outputs False
# for reference
print(isinstance(mock_ClassB, MagicMock)) # outputs True
I read in the patch docs that it's important to mock the class in the namespace it is used not where it is defined. So that's what I did, I mocked: a.b.c.classB instead of a.b.b.classB, have tried both though. I also tried importing ClassC inside the test__init__ method body, but this also didn't work.
I prefer not mocking methods of ClassB but rather the entire class to keep the test as isolated as possible.
Environment info:
Python 3.6.1
Any help would be greatly appreciated!
Since i'm new to python i didn't know about class attributes. I had a class attribute in ClassC that held ClassB and an instance attribute in init that shadowed the class attribute.
I have an existing python (python v2.7) application that imports external py files on the fly which contain specifically named classes to processes data. The external py file loaded is chosen based on the type of post-processing of the data that is needed.
So I have this collection of classes, each in their own file. The files are named in a specific fashion based on the type of processing so that the main program knows what file to import from the upstream request.
Keep in mind that I and others are always tweaking these class files, but we can not change the code on the main application.
What I would like to do is to import a "template" of the common functions into the class scope which can provide the standard set of controls that the main program expects without needing to copy/paste them into each file. I hate it when I find a bug and make a correction in one of these main class i/o function which I then have to replicate in thirty-some other files.
Now, I understand from googling that my import here is bad... I get the message:
TestClassFile.py:5: SyntaxWarning: import * only allowed at module level
But this method is the only way I have found to import the functions so that they come into the namespace of the class itself. I have an example below...
What method (if any) is the appropriate way to do this in Python?
Example
main.py
import TestClassFile
print "New TestClass - Init"
oTest = TestClassFile.TestClass("foo")
print "Should run... Function A"
oTest.funcA()
print "Should run... Function b"
oTest.funcB()
TestClassFile.py
class TestClass:
from TestClassImport import *
def __init__(self, str):
print "INIT! and be ... ", str
def funcA(self):
print "Function A"
TestClassImport.py
def funcB(self):
print "Function B"
Much appreciated!
Update
Many thanks to everyone for the contributions. From researching MixIns, these appear to be the proper python way to extend a class.
TestClassImport.py
class ImportClass:
def funcB(self):
print "Function B"
TestClassFile.py
from TestClassImport import ImportClass
class TestClass(ImportClass):
def __init__(self, str):
print "INIT! and be ... ", str
def funcA(self):
print "Function A"
It sounds like you should make the imported functions into mixins, which you can inherit from. So:
TestClassImport.py
class ClassB(object):
def funcB(self):
print "Function B"
TestClassFile.py
from TestClassImport import ClassB
from OtherClassImport import ClassX
class TestClass(ClassB, ClassX):
...
This appears to work:
import types
from TestClassImport import funcB
class TestClass:
def __init__(self, str):
print "INIT! and be ... ", str
setattr(self, 'funcB', types.MethodType(funcB, self, TestClass))
def funcA(self):
print "Function A"
When I run it I get the following output:
INIT! and be ... foo
Should run... Function A
Function A
Should run... Function b
Function B
I don't know if this is by any means a good solution, but you can write a function to construct a metaclass to dynamically add properties to your classes.
def make_meta(*import_classes):
class TestMeta(type):
def __new__(meta, name, bases, dct):
new_class = super(TestMeta, meta).__new__(meta, name, bases, dct)
for import_class in import_classes:
for name in vars(import_class):
if not name.startswith('__'):
prop = getattr(import_class, name)
setattr(new_class, name, prop)
return new_class
return TestMeta
class TestClass:
import TestClassImport
__metaclass__ = make_meta(TestClassImport)
# other functions defined as normal...
This will add everything in the global scope of TestClassImport.py that doesn't start with '__' as a property on TestClass.
Or, you can use a class decorator to add properties dynamically in the same fashion.
def add_imports(*import_classes):
def augment_class(cls):
for import_class in import_classes:
for name in vars(import_class):
if not name.startswith('__'):
prop = getattr(import_class, name)
setattr(cls, name, prop)
return cls
return augment_class
import TestClassImport
#add_imports(TestClassImport)
class TestClass:
# normal class body
But mixins do seem like a better approach.
You can use importlib for this, e.g.:
import importlib
class TestClass:
def __init__(self, module_name):
_tmp = importlib.import_module(module_name)
for elem in _tmp.__dir__():
if not elem.startswith('_'):
prop = getattr(_tmp, elem)
setattr(self, elem, prop)
def funcA(self):
print("function A")
tc = TestClass('some_module')
tc.funcB()
>>> prints "function B"
With this approach, you can create function load_module(module_name) instead of __init__() to load modules independently of each other (e.g. to prevent names collision).
Suppose I have this snippet inside a module
def func(params):
class MyClass(object):
pass
How can I pickle an instance of the class MyClass ?
You can't, because picklable object's class definitions must reside in an imported module's scope. Just put your class inside module scope and you are good to go.
That said, in Python there is very little that can't be achieved with a bit of hacking the insides of the machinery (sys.modules in this case), but I wouldn't recommend that.
The MyClass definition is local variable for the func function. You cannot directly create an instance of it, but you can map it's functions to a new class, and then to use the new class as it is the original one. Here's an example:
def func(params):
class MyClass(object):
some_param = 100
def __init__(self, *args):
print "args:", args
def blabla(self):
self.x = 123
print self.some_param
def getme(self):
print self.x
func.func_code is the code of the func function, and func.func_code.co_consts[2] contains the bytecode of the MyClass definition:
In : func.func_code.co_consts
Out:
(None,
'MyClass',
<code object MyClass at 0x164dcb0, file "<ipython-input-35-f53bebe124be>", line 2>)
So we need the bytecode for the MyClass functions:
In : eval(func.func_code.co_consts[2])
Out:
{'blabla': <function blabla at 0x24689b0>,
'__module__': '__main__',
'getme': <function getme at 0x2468938>,
'some_param': 100,
'__init__': <function __init__ at 0x219e398>}
And finally we create a new class with metaclass, that assigns the MyClass functions to the new class:
def map_functions(name, bases, dict):
dict.update(eval(func.func_code.co_consts[2]))
return type(name, bases, dict)
class NewMyClass(object):
__metaclass__ = map_functions
n = NewMyClass(1, 2, 3, 4, 5)
>> args: (1, 2, 3, 4, 5)
n.blabla()
>> 100
n.getme()
>> 123
This is somewhat tough to do because the way Pickle does with objects from user defined classes by default is to create a new instance of the class - using the object's __class__.__name__ attribute to retrieve its type in the object's original module. Which means: pickling and unpickling only works (by default) for classes that have well defined names in the module they are defined.
When one defines a class inside a function, usulay there won't be a module level (i.e. global) variable holding the name of each class that was created inside the function.
The behavior for pickle and npickle can be customized through the __getstate__ and __setstate__ methods on the class - check the docs - but even them, doing it right for dynamic class can be tricky , but I managed to create a working implementation of it for another S.O. question - -check my answer here:
Pickle a dynamically parameterized sub-class
You can work around the pickle requirement that class definitions be importable by including the class definition as a string in the data pickled for the instance and exec()uting it yourself when unpickling by adding a __reduce__() method that passes the class definition to a callable. Here's a trivial example illustrating what I mean:
from textwrap import dedent
# Scaffolding
definition = dedent('''
class MyClass(object):
def __init__(self, attribute):
self.attribute = attribute
def __repr__(self):
return '{}({!r})'.format(self.__class__.__name__, self.attribute)
def __reduce__(self):
return instantiator, (definition, self.attribute)
''')
def instantiator(class_def, init_arg):
""" Create class and return an instance of it. """
exec(class_def)
TheClass = locals()['MyClass']
return TheClass(init_arg)
# Sample usage
import pickle
from io import BytesIO
stream = BytesIO() # use a memory-backed file for testing
obj = instantiator(definition, 'Foo') # create instance of class from definition
print('obj: {}'.format(obj))
pickle.dump(obj, stream)
stream.seek(0) # rewind
obj2 = pickle.load(stream)
print('obj2: {}'.format(obj2))
Output:
obj: MyClass('Foo')
obj2: MyClass('Foo')
Obviously it's inefficient to include the class definition string with every class instance pickled, so that redundancy may make it impractical, depending on the the number of class instances involved.