I would like to extend an object with new attributes and methods, but in run-time. Basically I would prefer to just inherit and extend a class, but new objects of the base class are not usually created using it's constructor but by using fairly complex function.
Instead of...
from win32com import client
excel = client.Dispatch("Excel.Application")
excel.Visible = 1
excel.Workbooks.Add()
print(excel.Range("A1").value)
...I need something like (obviously broken):
from win32com import client
class Excel(client.CDispatch):
def __init__(self):
self = client.Dispatch("Excel.Application")
def get(self, cell):
return self.Range(cell).value
def show(self):
self.Visible = 1
excel = Excel()
excel.show()
excel.Workbooks.Add() # I want this to be still working
print(excel.get("A1"))
I still would like to be able to use original methods and attributes, but also my new ones. I have trouble wrapping my head around the concept, I am even not sure how to call the principle. Any ideas?
Another way to get desired functionality is like this:
from win32com import client
class Excel():
def __init__(self):
self.excel = client.Dispatch("Excel.Application")
self.Workbooks = self.excel.Workbooks
# I do not really want to repeat all base class
# functionality here to bind it to my new class
def get(self, cell):
return self.excel.Range(cell).value
def show(self):
self.excel.Visible = 1
excel = Excel()
excel.show()
excel.Workbooks.Add()
print(excel.get("A1"))
That works, however requires me to do a lot of lines similar to self.Workbooks = self.excel.Workbooks.
Implementation inheritence is mostly a variant of the composition / delegation pattern. The good news is that Python makes delegation quite easy. I've not tried (not working on Windows) but the following snippet might just work:
from win32com import client
class Excel(object):
def __init__(self):
self._app = client.Dispatch("Excel.Application")
def get(self, cell):
return self._app.Range(cell).value
def show(self):
self._app.Visible = 1
def __getattr__(self, name):
try:
return getattr(self._app, name)
except AttributeError:
raise AttributeError(
"'%s' object has no attribute '%s'" % (type(self).__name__, name))
Related
I have a function in a class (TableManager) that get the item and a specific field ('body') in DynamoDB.
class TableManager:
def get_body_dynamo(self, item):
get_body = json.loads(item.get('txt_vlr_parm_requ').get('body')) ##dict
return get_body
I need to initialize this 'body' field in another class (S3Connection), but I'm having trouble calling this function inside init.
class S3Connection:
def __init__(self, file, logs):
self.file = file
self.logs = logs
self.versions = None
I need something like this, to use this body I got from Dynamodb and create functions.
class S3Connection:
def __init__(self, file, logs, body_dynamo: TableManager.get_body_dynamo()):
self.body_dynamo = body_dynamo
self.file = file
self.logs = logs
self.versions = None
This way, of course, is giving error (not recognizing what body_dynamo is).
I'm new in programming and Python, so I appreciate any help.
I use an external tool in my Python code. In order to initialize this tool, I have to create a couple of objects. The external tool in question provides two quite different APIs, and no one of these APIs is capable of creating all objects the tool needs. Let's say, the tool is trafic simulation tool, where car objects are created using API 1 and bikes are created using API 2.
I have played with inheritance, tried to pick an appropriate design pattern but all my solutions look ugly to me.
The most simple way to represent what I am trying to achieve is:
class ObjectHandler():
api_1_types = ('type1', 'foo')
api_2_types = ('type2', 'bar')
def __init__(self):
self.handler1 = ObjectHandler1()
self.handler2 = ObjectHandler2()
def create(self, obj_type):
if obj_type in self.api_1_types:
return self.handler1.create()
elif obj_type in self.api_2_types:
return self.handler2.create()
else:
raise NotImplementedError
class ObjectHandler1():
def __init__(self):
# load external module that defines API 1
def create(self):
# return an object created via API 1
class ObjectHandler2():
def __init__(self):
# load external module that defines API 2
def create(self):
# return an object created via API 2
if __name__ == '__main__':
handler = ObjectHandler()
object_1 = handler.create('type1') # must be created by ObjectHandler1
object_2 = handler.create('type2') # must be created by ObjectHandler2
I am now searching for a good OO and pythonic way to achieve this.
Your method looks ok. Should use sets for in tests but it doesn't really matter. An alternative could be the following but I don't know if it is better:
def __init__(self):
self.handlers = dict()
handler1 = ObjectHandler1()
for type in api_1_types:
# These won't be copied but simply be a reference to the object
self.handlers[type] = handler1
# Repeat for the other one
and
def create(self, obj_type):
try:
return self.handlers[obj_type].create()
except KeyError:
raise NotImplementedError
Context:
I developed a python script to be run on a remote linux server. Running using Python 3.6.1. The script worked but was very messy, and procedurally written as opposed to OO. So, I re-wrote this script into 2 different classes. One main class and a blueprint class for objects.
My script is a lot more complicated, i just simplified it for this question.
Desired Function:
Read values from CSV file. Create Objects from these values, 1 object per line. Do some calculations on the values on init'ing the object (in the objects class). Have these objects be accessible from the main class (Base class).
Problems:
I need some clarification on:
The main method is not running. Tried variants on the method call, like Base.main(), including the "if name" statement inside the Base class, and it complains about self not being defined
The "self" reference. Are my usages of this correct? For example: Adding the attribute "age" into the Person objects so you can access it with person.age for example. My method call "self.input_file_handling(Base.inputFilePath)" etc.
Script:
import csv
class Person:
def calculate_age(self):
self.age = 2017 - self.birthYear
def __init__(self, name, birthYear):
self.name = self.strip_characters(self, name)
self.birthYear = int(birthYear)
self.calculate_age()
class Base:
inputFilePath = "input.csv"
people = []
def main():
self.input_file_handling(Base.inputFilePath)
#More methods here
#staticmethod
def input_file_handling(input_file_path):
input_file_path = str(input_file_path)
with open(input_file_path, 'r') as csv_file:
csv_reader = csv.DictReader(csv_file)
for line in csv_reader:
name = line['Name']
age = line['age']
person = Person(name, age)
people.append(person)
if __name__ == '__main__':
main()
First the main method of Base class is not static because it use the self variable, so is necessary receive that.
If you want call the main method and use the self variable you need make something like that:
class Base:
def main(self):
pass
if __name__ == '__main__':
instance_of_base = Base()
instance_of_base.main()
You can call the input_file_handling method without using self, because it's static
Base.input_file_handling(Base.inputFilePath)
I think you need learn more about how python resolve static things and the class and object variables.
Python is not C. There is no main function that automagically executes.
The main method that you defined is inside Base class, but it doesn't accept an argument for the instance.
Either modify it so it accept it (ie self by the convention) or make it a static method.
Then in if __name__ == '__main__': either use Base().main() or Base.main(), depending on what approach you decided to take.
But you don't seem to need any of this, and only doing it for the sake of forcing Python to look/work as other languages (looking at you C++/Java). Python doesn't require you to have a class or a 'main' function/method to execute code.
Your code written in a Pythonic way would be: (Python3)
import csv
from time import time, gmtime
INPUT_FILE_PATH = "input.csv"
class Person:
def __init__(self, name, birth_year):
self.name = name.strip()
self.birth_year = birth_year
#property
def birth_year(self):
return self._birth_year
#setter.birth_year
def birth_year(self, value):
self._birth_year = value
self._age = gmtime(time()).tm_year - value
#property
def age(self):
return self._age
#setter.age
def age(self, value):
self._birth_year = gmtime(time()).tm_year - value
self._age = value
def input_file_handling(input_file_path):
people = []
with open(input_file_path, 'r') as csv_file:
csv_reader = csv.DictReader(csv_file)
for line in csv_reader:
people.append(Person(line['Name'], int(line['age'])))
return people
if __name__ == '__main__':
people = input_file_handling(INPUT_FILE_PATH)
You seem to come from a OOP-only language (C# maybe?).
Some tips:
Avoid globals when able for variables, use them for function definition, class definition and constants.
Do not use a new class to store functions that do not require it
Use lower case and '' for variable and function names, Use CamelCase for class names, use caps and '' for constants.
Use duck typing: do not check that a argument is of a given type, try to use it as if it was and handle throw exceptions if it isn't.
Properties ar your friends if you want to force a specific bahaviour at getting or setting a class attributes
If you do not understand somehting ask in the comments.
I have a Python class whose __init__ method raises a custom exception called WrongFileSpecified.
However, when I write a unit test, I want to assign the attributes of the instance object from a test fixture. So normally what I would be doing is reading data off a file and then working with the instance object.
But with the test, I cannot use any test files, so I basically need to hard code the data in the instance object in the setUp method of the unit test. Is there any way to get a instance created without __init__ complaining about the exception?
Sample code:
class A(object):
def __init__(self, folderPath):
#check folder path using os.isdir() otherwise raise exception
#...
self.folderPath = folderPath
#Call load record
self._load_records() #uses self.folderPath and raises exceptions as well
#Note i cannot avoid raising these exceptions, its required
class TestA(unittest.TestCase):
.......
obj = None
def setUp(self):
obj = A('fake folder path')
obj.val1 = "testparam1"
obj.param2 = "testparam2"
def test_1(self):
.....
You can create an empty object, bypassing __init__ by using __new__.
obj = obj_type.__new__(obj_type)
Note that obj_type is the appropriate type object. This is a little hacky but it works. You are reponsible for setting the object's members.
Edit: here is an example.
class Foo():
def __init__(self):
self.x = 1
self.y = 2
def say_hello(self):
print('Hello!')
r = Foo.__new__(Foo)
r.say_hello()
print(r.x)
Console output:
Hello!
Traceback (most recent call last):
File "C:\WinPython-64bit-3.3.5.7\python-
3.3.5.amd64\Scripts\projects\luc_utils\dev\test\
unit_test_serialization.py", line 29, in <module>
print(r.x)
AttributeError: 'Foo' object has no attribute 'x'
Here are two options:
Refactor the file loading out to a class method, which is the Pythonic method of providing an alternate constructor (see below); or
Provide an additional parameter to __init__ to suppress the exceptions when necessary (e.g. def __init__(self, folderPath, suppress=False), or validate=True, whichever makes more sense for your usage).
The latter is a bit awkward, in my opinion, but would mean that you don't have to refactor existing code creating A instances. The former would look like:
class A(object):
def __init__(self, ...):
"""Pass whatever is loaded from the file to __init__."""
...
#classmethod
def from_file(cls, folderPath):
"""Load the data from the file, or raise an exception."""
...
and you would replace e.g. a = A(whatever) with a = A.from_file(whatever).
There is a very useful module called mock, you can check it out later, I feel that in this case it will be too much. Instead, you should consider redesigning your class, like this, for example:
class A(object):
def __init__(self, folderPath):
self.folderPath = folderPath
def _load_records(self)
#check folder path using os.isdir() otherwise raise exception
...
#uses self.folderPath and raises exceptions as well
...
#classmethod
def load_records(cls, folderpath):
obj = cls(folderpath)
obj._load_records()
return obj
# Usage
records = A.load_records('/path/to/records')
Then you can do:
class TestA(unittest.TestCase):
.......
obj = None
def setUp(self):
self.obj = A('fake folder path')
self.obj.val1 = "testparam1"
self.obj.param2 = "testparam2"
def test_1(self):
self.assertRaises(self.obj._load_records, HorribleFailureError)
Also i highly recommend to check out pytest, it has wonderful facilities for test fixtures, including fixtures for files and folders.
I am updating some code from using libglade to GtkBuilder, which is supposed to be the way of the future.
With gtk.glade, you could call glade_xml.signal_autoconnect(...) repeatedly to connect signals onto objects of different classes corresponding to different windows in the program. However Builder.connect_signals seems to work only once, and (therefore) to give warnings about any handlers that aren't defined in the first class that's passed in.
I realize I can connect them manually but this seems a bit laborious. (Or for that matter I could use some getattr hackery to let it connect them through a proxy to all the objects...)
Is it a bug there's no function to hook up handlers across multiple objects? Or am I missing something?
Someone else has a similar problem http://www.gtkforums.com/about1514.html which I assume means this can't be done.
Here's what I currently have. Feel free to use it, or to suggest something better:
class HandlerFinder(object):
"""Searches for handler implementations across multiple objects.
"""
# See <http://stackoverflow.com/questions/4637792> for why this is
# necessary.
def __init__(self, backing_objects):
self.backing_objects = backing_objects
def __getattr__(self, name):
for o in self.backing_objects:
if hasattr(o, name):
return getattr(o, name)
else:
raise AttributeError("%r not found on any of %r"
% (name, self.backing_objects))
I have been looking for a solution to this for some time and found that it can be done by passing a dict of all the handlers to connect_signals.
The inspect module can extract methods using
inspect.getmembers(instance, predicate=inspect.ismethod
These can then be concatenated into a dictionary using d.update(d3), watching out for duplicate functions such as on_delete.
Example code:
import inspect
...
handlers = {}
for c in [win2, win3, win4, self]: # self is the main window
methods = inspect.getmembers(c, predicate=inspect.ismethod)
handlers.update(methods)
builder.connect_signals(handlers)
This will not pick up alias method names declared using #alias. For an example of how to do that, see the code for Builder.py, at def dict_from_callback_obj.
I'm only a novice but this is what I do, maybe it can inspire;-)
I instantiate the major components from a 'control' and pass the builder object so that the instantiated object can make use of any of the builder objects (mainwindow in example) or add to the builder (aboutDialog example). I also pass a dictionary (dic) where each component adds "signals" to it.
Then the 'connect_signals(dic)' is executed.
Of course I need to do some manual signal connecting when I need to pass user arguments to the callback method, but those are few.
#modules.control.py
class Control:
def __init__(self):
# Load the builder obj
guibuilder = gtk.Builder()
guibuilder.add_from_file("gui/mainwindow.ui")
# Create a dictionnary to store signal from loaded components
dic = {}
# Instanciate the components...
aboutdialog = modules.aboutdialog.AboutDialog(guibuilder, dic)
mainwin = modules.mainwindow.MainWindow(guibuilder, dic, self)
...
guibuilder.connect_signals(dic)
del dic
#modules/aboutdialog.py
class AboutDialog:
def __init__(self, builder, dic):
dic["on_OpenAboutWindow_activate"] = self.on_OpenAboutWindow_activate
self.builder = builder
def on_OpenAboutWindow_activate(self, menu_item):
self.builder.add_from_file("gui/aboutdialog.ui")
self.aboutdialog = self.builder.get_object("aboutdialog")
self.aboutdialog.run()
self.aboutdialog.destroy()
#modules/mainwindow.py
class MainWindow:
def __init__(self, builder, dic, controller):
self.control = controller
# get gui xml and/or signals
dic["on_file_new_activate"] = self.control.newFile
dic["on_file_open_activate"] = self.control.openFile
dic["on_file_save_activate"] = self.control.saveFile
dic["on_file_close_activate"] = self.control.closeFile
...
# get needed gui objects
self.mainWindow = builder.get_object("mainWindow")
...
Edit: alternative to auto attach signals to callbacks:
Untested code
def start_element(name, attrs):
if name == "signal":
if attrs["handler"]:
handler = attrs["handler"]
#Insert code to verify if handler is part of the collection
#we want.
self.handlerList.append(handler)
def extractSignals(uiFile)
import xml.parsers.expat
p = xml.parsers.expat.ParserCreate()
p.StartElementHandler = self.start_element
p.ParseFile(uiFile)
self.handlerList = []
extractSignals(uiFile)
for handler in handlerList:
dic[handler] = eval(''. join(["self.", handler, "_cb"]))
builder.connect_signals
({
"on_window_destroy" : gtk.main_quit,
"on_buttonQuit_clicked" : gtk.main_quit
})