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
Related
I'm trying to get a set of python classes built to simplify the sending and receiving of information over a socket connection.
I've had success using a getter and setter via the #property.
I would like the code to be in a dot notation such as:
class dc_load_fake_socket:
#staticmethod
def sendall(msg):
print(msg)
#staticmethod
def recv(size):
return 'Dummy Info'
class test_equipment:
def __init__(self, TCP_IP, TCP_PORT=2101, BUFFER_SIZE=1024):
self.TCP_IP = str(TCP_IP)
self.TCP_PORT = TCP_PORT
self.BUFFER_SIZE = BUFFER_SIZE
self.dc_load_socket = dc_load_fake_socket
def sendall(self, message):
message = f'{message}\n'
self.dc_load_socket.sendall(message.encode())
def recv(self):
return self.dc_load_socket.recv(self.BUFFER_SIZE)
def query(self, message):
self.sendall(message)
return self.recv().strip('\n')
#property
def voltage(self):
return self.query("MEASure:VOLTage?")
dcl = test_equipment('192.168.0.2')
print(dcl.voltage)
While this works, the issue is the fact that this isn't the only 'subsystem' that uses voltage.
Ideally I would like it to act like this:
dcl.measure.voltage
dcl.fetch.voltage
dcl.spec.voltage
dcl.spec.voltage = 1.5
I've looked at using inner classes but I'm not able to use the recv(), sendall() and query() of the main class.
Originally this was done in a python file with only functions. But I ran into an issue were I actually needed two of them. I started turning this into a class as a way to make it easier to maintain, and at the same time had to update from python 2.7 to 3
I'm not the most experienced in python and any help with this would be extremely appreciated.
I would like some advice on how to best design a class and it's instance variables. I initialize the class with self.name. However, the main purpose of this class it to retrieve data from an API passing self.name as a parameter, and then parsing the data accordingly. I have a class method called fetch_data(self.name) that makes the API request and returns ALL data. I want to store this data into a class instance variable, and then call other methods on that variable. For example, get_emotions(json), get_personality_traits(json), and get_handle(json), all take the same dictionary as a parameter, assign it to their own local variables, and then manipulate it accordingly.
I know I can make fetch_data(self.name) return data, and then call fetch_data(self.name) within the other methods, assign the return value to a local variable, and manipulate that. The problem is then I will need to call the API 5 times rather than 1, which I can't do for time and money reasons.
So, how do I make the result of fetch_data(self.name) global so that all methods within the class have access to the main data object? I know this is traditionally done in an instance variable, but in this scenario I can't initiliaze the data since I don't have it until after I call fetch_data().
Thank you in advance!
It seems like you just need to do something like this:
class Foo(object):
def __init__(self, name):
self.name = name
self.data = None
def fetch_data(self):
if self.data is None:
# Only call the API once
self.data = self.really_fetch_data()
return self.data
def get_emotions(self):
emotions = self.fetch_data().get("emotions")
...
Why don't you just try to solve this as you described?
For example, you can take this as a starting point:
import json
class APIBundle(object):
def __init__(self, name):
self.name = name
self.data = None
self.update()
def update():
response = json.loads(API_request(self.name))
# Do some parsing on response
self.data = response
def get_emotions():
# Work through current data state
# and filter as desired
result = []
for message in self.data['messages']:
if message.find(':)') != -1:
result.append((message, 'positive'))
if message.find(':(') != -1:
result.append((message, 'negative'))
return result
if __name__ == '__main__':
ab = APIBundle('my-secret-name')
print(self.get_emotions())
Try to do it with self.data=None , or make an instance variable and call whenever you need. writing algorithm will make this thing more complex try to solve issue with inbuilt functions or with algorithm program vulnerability will affect alot.
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))
I am trying to give a slight amount of genericness to my code . Basically what I am looking for is this .
I wish to write an API interface MyAPI :
class MyAPI(object):
def __init__(self):
pass
def upload(self):
pass
def download(self):
pass
class MyAPIEx(object):
def upload(self):
#specific implementation
class MyAPIEx2(object):
def upload(self)
#specific implementation
#Actual usage ...
def use_api():
obj = MyAPI()
obj.upload()
SO what I want is that based on a configuration I should be able to call the upload function
of either MyAPIEx or MyAPIEx2 . What is the exact design pattern I am looking for and how do I implement it in python.
You are looking for Factory method (or any other implementation of a factory).
Its really hard to say what pattern you are using, without more info. The way to instantiate MyAPI is indeed a Factory like #Darhazer mentioned, but it sounds more like you're interested in knowing about the pattern used for the MyAPI class hierarchy, and without more info we cant say.
I made some code improvements below, look for the comments with the word IMPROVEMENT.
class MyAPI(object):
def __init__(self):
pass
def upload(self):
# IMPROVEMENT making this function abstract
# This is how I do it, but you can find other ways searching on google
raise NotImplementedError, "upload function not implemented"
def download(self):
# IMPROVEMENT making this function abstract
# This is how I do it, but you can find other ways searching on google
raise NotImplementedError, "download function not implemented"
# IMPROVEMENT Notice that I changed object to MyAPI to inherit from it
class MyAPIEx(MyAPI):
def upload(self):
#specific implementation
# IMPROVEMENT Notice that I changed object to MyAPI to inherit from it
class MyAPIEx2(MyAPI):
def upload(self)
#specific implementation
# IMPROVEMENT changed use_api() to get_api(), which is a factory,
# call it to get the MyAPI implementation
def get_api(configDict):
if 'MyAPIEx' in configDict:
return MyAPIEx()
elif 'MyAPIEx2' in configDict:
return MyAPIEx2()
else
# some sort of an error
# Actual usage ...
# IMPROVEMENT, create a config dictionary to be used in the factory
configDict = dict()
# fill in the config accordingly
obj = get_api(configDict)
obj.upload()
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
})