I have a Python project where most business logic is in class methods. Now I would like to reuse some of the class methods in an independent project.
Is it possible to write a class method that 'exports' other class methods to a new Python file to create a script with a bunch of exported functions?
class MyObject:
def __init__(self, value):
self.value = value
def method1(self):
# the method I want to use in another project
def method2(self):
...
def method3(self):
...
def export_method(self, target_file):
# export the code of method1 to a new python file
When I run export_method('myfile.py') I would like to create a Python file that contains method1 as a function:
def method1():
...
Note: I understand that the software should be restructured and method1 should be in another module where it can be imported from other projects. I'm just curious if there is a simple way to access the code of a Python program from the code itself.
Use inspect:
Either directly:
import inspect
lines = inspect.getsource(MyObject.method1)
with open(target_file, 'w') as file:
file.write(lines)
Or if you prefer to get it as a class method and print all methods in the class:
import inspect
class MyObject:
def __init__(self, value):
self.value = value
def method1(self):
pass
def method2(self):
pass
def method3(self):
pass
#classmethod
def export_method(cls, target_file):
# export the code of method1 to a new python file
methods = inspect.getmembers(cls, predicate=inspect.ismethod)
with open(target_file, 'w') as f:
for method in methods:
lines = inspect.getsource(method[1])
f.write(lines)
Because of the #classmethod decorator the following is allowed:
MyObject.export_method('code.txt')
Related
I am experimenting with python object orientated programming. Of course I learned about inheritence and so on, but this question is very specific and I couldn't find the answer anywhere yet.
Let's say we have a class class mainClass:. In this class there is a function def func(self):. And within this function func() I want to use two custom classes. Can I and how can I use the first custom class within the second one? (Here's a example)
class custom1:
def func1(self):
#do something
class custom2:
def func2(self):
#call function func1 from class custom1 without creating another instance
class mainClass:
def func(self):
obj1 = custom1()
obj2 = custom2()
obj2.func2()
Like I said I don't want to create a second instance of custom1 within custom2. Only the one in mainClass.
Thanks for your answers :)
what about passing it via the constructor of the first class?
class custom1:
def func1(self):
#do something
class custom2:
def __init__(self, obj1):
self._obj1 = obj1
def func2(self):
self._obj1.func1()
class mainClass:
def func(self):
obj1 = custom1()
obj2 = custom2(obj1)
obj2.func2()
For the class I'm writing I want to implement methods to dump the data to a shelve file and also a classmethod that would create a new instance based on the values of the instance loaded from file. So for example if I have a class like that:
import shelve
class Foo:
def __init__(self, a):
self.a = a
def save(self, fname):
with shelve.open(fname, flag='c') as shlv:
shlv['data'] = self
At the moment I'm using an external function to load the shelve file and return a saved instance:
def load_data(filename) -> Foo:
with shelve.open(filename) as shlv:
return shlv['data']
And this works fine.
I was just trying to think of how I can implement a class method that would load the data and create a new instance.
I'm pretty sure that what I'm thinking is an ugly solution but I'm still interested out of pure curiosity.
My original idea was to do something like:
class Foo:
def __init__(self, a):
self.a = a
def save(self, fname):
with shelve.open(fname, flag='c') as shlv:
shlv['data'] = self
#classmethod
def from_saved_data(cls, data):
cls.__dict__ = data.__dict__
return cls
This doesn't work because I was trying to do dumb things to the metaclass and got this error:
AttributeError: attribute '__dict__' of 'type' objects is not writable
What are the other ways I can do this?
I have a class MyClass with a complex __init__ function.
This class had a method my_method(self) which I would like to test.
my_method only needs attribute my_attribute from the class instance.
Is there a way I can mock class instances without calling __init__ and by setting the attributes of each class instance instead?
What I have:
# my_class.py
from utils import do_something
class MyClass(object):
def __init__(self, *args, **kwargs):
# complicated function which I would like to bypass when initiating a mocked instance class
pass
def my_method(self):
return do_something(self.my_attribute)
What I tried
#mock.patch("my_class.MyClass")
def test_my_method(class_mock, attribute):
instance = class_mock.return_value
instance.my_attribute = attribute
example_instance = my_class.MyClass()
out_my_method = example_instance.my_method()
# then perform some assertions on `out_my_method`
however this still makes usage of __init__ which I hope we can by-pass or mock.
As I mentioned in the comments, one way to test a single method without having to create an instance is:
MyClass.my_method(any_object_with_my_attribute)
The problem with this, as with both options in quamrana's answer, is that we have now expanded the scope of any future change just because of the tests. If a change to my_method requires access to an additional attribute, we now have to change both the implementation and something else (the SuperClass, the MockMyClass, or in this case any_object_with_my_attribute_and_another_one).
Let's have a more concrete example:
import json
class MyClass:
def __init__(self, filename):
with open(filename) as f:
data = json.load(f)
self.foo = data.foo
self.bar = data.bar
self.baz = data.baz
def my_method(self):
return self.foo ** 2
Here any test that requires an instance of MyClass. is painful because of the file access in __init__. A more testable implementation would split apart the detail of how the data is accessed and the initialisation of a valid instance:
class MyClass:
def __init__(self, foo, bar, baz):
self.foo = foo
self.bar = bar
self.baz = baz
def my_method(self):
return self.foo ** 2
#classmethod
def from_json(cls, filename):
with open(filename) as f:
data = json.load(f)
return cls(data.foo, data.bar, data.baz)
You have to refactor MyClass("path/to/file") to MyClass.from_json("path/to/file"), but wherever you already have the data (e.g. in your tests) you can use e.g. MyClass(1, 2, 3) to create the instance without requiring a file (you only need to consider the file in the tests of from_json itself). This makes it clearer what the instance actually needs, and allows the introduction of other ways to construct an instance without changing the interface.
There are at least two options I can see:
Extract a super class:
class SuperClass:
def __init__(self, attribute):
self.my_attribute = attribute
def my_method(self):
return do_something(self.my_attribute)
class MyClass(SuperClass):
def __init__(self, *args, **kwargs):
super().__init__(attribute) # I don't know where attribute comes from
# complicated function which I would like to bypass when initiating a mocked instance class
Your tests can instantiate SuperClass and call my_method().
Inherit from MyClass as is and make your own simple __init__():
class MockMyClass(MyClass):
def __init__(self, attribute):
self.my_attribute = attribute
Now your test code can instantiate MockMyClass with the required attribute and call my_method()
For instance, you could write the test as follows
def test_my_method(attribute):
class MockMyClass(MyClass):
def __init__(self, attribute):
self.my_attribute = attribute
out_my_method = MockMyClass(attribute).my_method()
# perform assertions on out_my_method
Suppose I have backend.py file and inside is:
class Database():
def __init__(self):
pass
def printDatabase(self):
print('Printing test')
And suppose I have another fie called frontend.py
import backend
class Tester(backend.Database):
def __init__(self):
pass
def testInheritance(self):
self.printDatabase()
Is this the correct code to inherit a class from another file, and use one of its methods?
Let's say I have this code:
class class1(object):
def __init__(self):
#don't worry about this
def parse(self, array):
# do something with array
class class2(object):
def __init__(self):
#don't worry about this
def parse(self, array):
# do something else with array
I want to be able to call class1's parse from class2 and vice-versa. I know with c++ this can be done quite easily by doing
class1::parse(array)
How would I do the equivalent in python?
It sounds like you want a static method:
class class1(object):
#staticmethod
def parse(array):
...
Note that in such cases you leave off the usually-required self parameter, because parse is not a function called on a particular instance of class1.
On the other hand, if you want a method which is still tied to its owner class, you can write a class method, where the first argument is actually the class object:
class class1(object):
#classmethod
def parse(cls, array):
...