class fileDetails :
def __init__(self,host,usr,pwd,database):
self.host=host
self.usr.usr
self.pwd=pwd
self.database=database
def __init__(self,connection,sql,path):
self.connection=mysql_connection()
self.sql=sql
self.path=path
If I use the constructor then it gives an error:
onnetction = fileDetails('localhost',"root","",'bulsorbit')
TypeError: __init__() takes exactly 4 arguments (5 given)
The overloading of the constructor (or any other function) is not allowed in python. So you cannot define two __init__ functions for your class.
You can have a look to this post or this one
The main ideas are to use default values or to create 'alternate constructors' or to check the number and the type of your args in order to choose which method to apply.
def __init__(self, **args):
Then args will be a dictionary containing all the parameters. So you will be able to make the difference between
connection = fileDetails(host='localhost',usr="root",pwd="",database='bulsorbit')
and
connection = fileDetails(connection="...",sql="...",path="...")
Define a single constructor with optional arguments.
def __init__(self,host='host',usr='user',pwd='pwd',database='db',connection=None,sql=None,path=None):
if connection:
# however you want to store your connection
self.sql=sql
self.path=path
else:
self.host=host
self.usr.usr
self.pwd=pwd
self.database=database
Or something of the sort.
maybe you can use len() to choose the right branch:
class Foo(object):
def __init__(self, *args):
if len(args) == 4: # network
self.host = args[0]
self.user = args[1]
self.pwd = args[2]
self.database = args[3]
elif len(args) == 3: # database
self.connection = mysql_connection() # maybe it's args[0]?
self.sql = args[1]
self.path = args[2]
def main():
foo = Foo('localhost',"root","",'bulsorbit')
print foo.host
if __name__ == "__main__":
main()
# output
# localhost
but, sine Explicit is better than implicit. maybe this is workable too:
class Foo(object):
def __init__(self, initdata):
if initdata['style'] == 'network':
self.host = initdata['host']
self.usr = initdata['usr']
self.pwd = initdata['pwd']
self.database = initdata['database']
elif initdata[style] == 'database':
self.connection = mysql_connection()
self.sql = initdata['sql']
self.path = initdata['path']
def main():
data = dict({'style': 'network',
'host': 'localhost',
'usr': 'root',
'pwd': '',
'database': 'database'})
foo = Foo(data)
print foo.host
if __name__ == "__main__":
main()
# output
# localhost
In Python the functions in a class are stored internally in a dictionary (remember that constructors are just regular functions), and so only one function of the same name can exist. Therefore, when defining more than one functions with the same name the last one will overwrite all the previously defined ones and you'll end up with only one function.
I suggest you look into keyword and default arguments to see the proper way of achieving what you want.
Here's one way to achieve this:
class FileDetails:
def __init__(self, *args, **kwargs):
if len(args) == 3:
self.conn, self.sql, self.path = args
elif len(args) == 4:
self.host, self.usr, self.pw, self.db = args
else:
# handle appropriately
fd1 = FileDetail('connstring', 'select * from foo', '/some/path')
print fd1.conn, fd1.sql, fd1.path
fd2 = FileDetail('host', 'user', 'pass', 'somedb')
print fd2.conn, fd2.usr, fd2.pw, fd2.db
Of course, you should do the appropriate type checking and error handling in the constructor.
On the side note: if you really, really, reallllllyyy must do JiP (Java in Python) then multiple dispatch methods are possible with some additional code eg. here and even beter: here by BDFL.
Personally I try to avoid using them.
Related
I have a class (which works [or appears to]) to run an sql query. Code is below. If I inherit from object and do not use super, it works fine.
I am learning about inserting methods from super classes and so I thought that I would make my class header look like this
class database_connector(Connection)
and incorporate a super call in init like this
super().__init__()
However, I get
TypeError: function() argument 1 must be code, not str
I tried
super(database_connector, self).__init__()
after reading some other stuff in StackOverFlow but I now still get
TypeError: function() argument 1 must be code, not str
I am anticipating that this work will allow me to call more methods from pymysql.Connection.
Here is my class
from pymysql import Connection
# set up default values for database connector
class database_connector(Connection):
def __init__(self, host=None, db=None, user=None, passwd=None):
super(database_connector, self).__init__()
if host is None:
self.host = "mysql_host_ip"
else:
self.host = host
if db is None:
self.db = "fred_db"
else:
self.db = db
if user is None:
self.user = "fred"
else:
self.user = user
if passwd is None:
self.passwd = "fredspasswd"
else:
self.passwd = passwd
self.this_database = (Connection(host=self.host,
user=self.user,
passwd=self.passwd,
db=self.db))
self.cur = self.this_database.cursor()
def my_sql_run_this_sql(self, sql_to_run=None):
if sql_to_run is None:
data = self.cur.execute("SELECT * FROM person")
else:
data = self.cur.execute(sql_to_run)
data = []
for row in self.cur.fetchall():
data.append(row)
self.this_database.close()
return data
I have a very long function func which takes a browser handle and performs a bunch of requests and reads a bunch of responses in a specific order:
def func(browser):
# make sure we are logged in otherwise log in
# make request to /search and check that the page has loaded
# fill form in /search and submit it
# read table of response and return the result as list of objects
Each operation require a large amount of code due to the complexity of the DOM and they tend to grow really fast.
What would be the best way to refactor this function into smaller components so that the following properties still hold:
the execution flow of the operations and/or their preconditions is guaranteed just like in the current version
the preconditions are not checked with asserts against the state, as this is a very costly operation
func can be called multiple times on the browser
?
Just wrap the three helper methods in a class, and track which methods are allowed to run in an instance.
class Helper(object):
def __init__(self):
self.a = True
self.b = False
self.c = False
def funcA(self):
if not self.A:
raise Error("Cannot run funcA now")
# do stuff here
self.a = False
self.b = True
return whatever
def funcB(self):
if not self.B:
raise Error("Cannot run funcB now")
# do stuff here
self.b = False
self.c = True
return whatever
def funcC(self):
if not self.C:
raise Error("Cannot run funcC now")
# do stuff here
self.c = False
self.a = True
return whatever
def func(...):
h = Helper()
h.funcA()
h.funcB()
h.funcC()
# etc
The only way to call a method is if its flag is true, and each method clears its own flag and sets the next method's flag before exiting. As long as you don't touch h.a et al. directly, this ensures that each method can only be called in the proper order.
Alternately, you can use a single flag that is a reference to the function currently allowed to run.
class Helper(object):
def __init__(self):
self.allowed = self.funcA
def funcA(self):
if self.allowed is not self.funcA:
raise Error("Cannot run funcA now")
# do stuff
self.allowed = self.funcB
return whatever
# etc
Here's the solution I came up with. I used a decorator (closely related to the one in this blog post) which only allows for a function to be called once.
def call_only_once(func):
def new_func(*args, **kwargs):
if not new_func._called:
try:
return func(*args, **kwargs)
finally:
new_func._called = True
else:
raise Exception("Already called this once.")
new_func._called = False
return new_func
#call_only_once
def stateA():
print 'Calling stateA only this time'
#call_only_once
def stateB():
print 'Calling stateB only this time'
#call_only_once
def stateC():
print 'Calling stateC only this time'
def state():
stateA()
stateB()
stateC()
if __name__ == "__main__":
state()
You'll see that if you re-call any of the functions, the function will throw an Exception stating that the functions have already been called.
The problem with this is that if you ever need to call state() again, you're hosed. Unless you implement these functions as private functions, I don't think you can do exactly what you want due to the nature of Python's scoping rules.
Edit
You can also remove the else in the decorator and your function will always return None.
Here a snippet I used once for my state machine
class StateMachine(object):
def __init__(self):
self.handlers = {}
self.start_state = None
self.end_states = []
def add_state(self, name, handler, end_state=0):
name = name.upper()
self.handlers[name] = handler
if end_state:
self.end_states.append(name)
def set_start(self, name):
# startup state
self.start_state = name
def run(self, **kw):
"""
Run
:param kw:
:return:
"""
# the first .run call call the first handler with kw keywords
# each registered handler should returns the following handler and the needed kw
try:
handler = self.handlers[self.start_state]
except:
raise InitializationError("must call .set_start() before .run()")
while True:
(new_state, kw) = handler(**kw)
if isinstance(new_state, str):
if new_state in self.end_states:
print("reached ", new_state)
break
else:
handler = self.handlers[new_state]
elif hasattr(new_state, "__call__"):
handler = new_state
else:
return
The use
class MyParser(StateMachine):
def __init__(self):
super().__init__()
# define handlers
# we can define many handler as we want
self.handlers["begin_parse"] = self.begin_parse
# define the startup handler
self.set_start("begin_parse")
def end(self, **kw):
logging.info("End of parsing ")
# no callable handler => end
return None, None
def second(self, **kw):
logging.info("second ")
# do something
# if condition is reach the call `self.end` handler
if ...:
return self.end, {}
def begin_parse(self, **kw):
logging.info("start of parsing ")
# long process until the condition is reach then call the `self.second` handler with kw new keywords
while True:
kw = {}
if ...:
return self.second, kw
# elif other cond:
# return self.other_handler, kw
# elif other cond 2:
# return self.other_handler 2, kw
else:
return self.end, kw
# start the state machine
MyParser().run()
will print
INFO:root:start of parsing
INFO:root:second
INFO:root:End of parsing
You could use local functions in your func function. Ok, they are still declared inside one single global function, but Python is nice enough to still give you access to them for tests.
Here is one example of one function declaring and executing 3 (supposedly heavy) subfunctions. It takes one optional parameter test that when set to TEST prevent actual execution but instead gives external access to individual sub-functions and to a local variable:
def func(test=None):
glob = []
def partA():
glob.append('A')
def partB():
glob.append('B')
def partC():
glob.append('C')
if (test == 'TEST'):
global testA, testB, testC, testCR
testA, testB, testC, testCR = partA, partB, partC, glob
return None
partA()
partB()
partC()
return glob
When you call func, the 3 parts are executed in sequence. But if you first call func('TEST'), you can then access the local glob variable as testCR, and the 3 subfunctions as testA, testB and testC. This way you can still test individually the 3 parts with well defined input and control their output.
I would insist on the suggestion given by #user3159253 in his comment on the original question:
If the sole purpose is readability I would split the func into three "private" > or "protected" ones (i.e. _func1 or __func1) and a private or protected property > which keeps the state shared between the functions.
This makes a lot of sense to me and seems more usual amongst object oriented programming than the other options. Consider this example as an alternative:
Your class (teste.py):
class Test:
def __init__(self):
self.__environment = {} # Protected information to be shared
self.public_stuff = 'public info' # Accessible to outside callers
def func(self):
print "Main function"
self.__func_a()
self.__func_b()
self.__func_c()
print self.__environment
def __func_a(self):
self.__environment['function a says'] = 'hi'
def __func_b(self):
self.__environment['function b says'] = 'hello'
def __func_c(self):
self.__environment['function c says'] = 'hey'
Other file:
from teste import Test
t = Test()
t.func()
This will output:
Main function says hey guys
{'function a says': 'hi', 'function b says': 'hello', 'function c says': 'hey'}
If you try to call one of the protected functions, an error occurs:
Traceback (most recent call last):
File "C:/Users/Lucas/PycharmProjects/testes/other.py", line 6, in <module>
t.__func_a()
AttributeError: Test instance has no attribute '__func_a'
Same thing if you try to access the protected environment variable:
Traceback (most recent call last):
File "C:/Users/Lucas/PycharmProjects/testes/other.py", line 5, in <module>
print t.__environment
AttributeError: Test instance has no attribute '__environment'
In my view this is the most elegant, simple and readable way to solve your problem, let me know if it fits your needs :)
When I create an object in some method, I can't use it in any other method. So the use of the object is limited just to that method. But I would like to create the object somehow, that could use it in my whole module.
Here is the code of the module in which I want to create the object so I could use it in every method. (It's not so important what it should do, but for those who cares, it'll be network configurator which using netlink socket to communicate with the kernel).
In the method configureBridge() (the 4th method from the beginning) I tried to create an object and use it (ip = IPRoute() ... ip.release()) and it worked, but I couldn't use the object variable ip in any other function apart from configureBridge(). Could someone help me with that?
class PyrouteTwo(Configurator):
def __init__(self, inRollback=False):
super(PyrouteTwo, self).__init__(ConfigApplier(), inRollback)
self.runningConfig = RunningConfig()
logging.debug("testmark.PyR2.init")
def begin(self):
if self.configApplier is None:
self.configApplier = ConfigApplier()
if self.runningConfig is None:
self.runningConfig = RunningConfig()
logging.debug("testmark.PyR2.begin")
def commit(self):
self.configApplier = None
self.runningConfig.save()
self.runningConfig = None
logging.debug("testmark.PyR2.commit")
def configureBridge(self, bridge, **opts):
self.configApplier.addBridge(bridge)
if bridge.port:
bridge.port.configure(**opts)
self.configApplier.addBridgePort(bridge)
self.configApplier.setIfaceConfigAndUp(bridge)
logging.debug("testmark.PyR2.confBridge..")
# I am using the object here:
ip = IPRoute(fork=True)
dev = ip.link_lookup(ifname='em1')[0]
logging.debug("pyroute2 link_lookup output: %d", dev)
ip.release()
# there are some similar functions like configureVAN etc. in which I want
# to use the object
class ConfigApplier(object):
def _setIpConfig(self, iface):
ipConfig = iface.ipConfig
logging.debug("testmark.PyR2.ConfApplier.setIpConf.")
if ipConfig.ipaddr:
self.removeIpConfig(iface)
ipwrapper.addrAdd(iface.name, ipConfig.ipaddr,
ipConfig.netmask)
if ipConfig.gateway and ipConfig.defaultRoute:
ipwrapper.routeAdd(['default', 'via', ipConfig.gateway])
def removeIpConfig(self, iface):
ipwrapper.addrFlush(iface.name)
def setIfaceMtu(self, iface, mtu):
ipwrapper.linkSet(iface, ['mtu', str(mtu)])
def ifup(self, iface):
ipwrapper.linkSet(iface.name, ['up'])
if iface.ipConfig.bootproto == 'dhcp':
dhclient = DhcpClient(iface.name)
dhclient.start(iface.ipConfig.async)
def ifdown(self, iface):
ipwrapper.linkSet(iface.name, ['down'])
dhclient = DhcpClient(iface.name)
dhclient.shutdown()
def setIfaceConfigAndUp(self, iface):
if iface.ip:
self._setIpConfig(iface)
if iface.mtu:
self.setIfaceMtu(iface.name, iface.mtu)
self.ifup(iface)
def addBridge(self, bridge):
rc, _, err = execCmd([EXT_BRCTL, 'addbr', bridge.name])
if rc != 0:
raise ConfigNetworkError(ERR_FAILED_IFUP, err)
def addBridgePort(self, bridge):
rc, _, err = execCmd([EXT_BRCTL, 'addif', bridge.name,
bridge.port.name])
if rc != 0:
raise ConfigNetworkError(ERR_FAILED_IFUP, err)
def removeBridge(self, bridge):
rc, _, err = execCmd([EXT_BRCTL, 'delbr', bridge.name])
if rc != 0:
raise ConfigNetworkError(ERR_FAILED_IFDOWN, err)
logging.debug("testmarkPyR2.ConfApplier.remBridge")
# ...
def createLibvirtNetwork(self, network, bridged, iface, qosInbound=None,
qosOutbound=None):
netXml = libvirtCfg.createNetworkDef(network, bridged, iface,
qosInbound, qosOutbound)
libvirtCfg.createNetwork(netXml)
logging.debug("testmarkPyR2.ConfApplier.createLibvirtNetwork")
def removeLibvirtNetwork(self, network):
libvirtCfg.removeNetwork(network)
logging.debug("testmarkPyR2.ConfApplier.remLibvirtNetwork")
You can either declare it as object specific attibute by doing -
self.ip = value # Now its a object specific variable
or make it a class veriable before assign it a value.
class PyrouteTwo(Configurator):
ip = None # Now its a class variable
table = set([])
class GlobeLearningTable(object):
def __init__(self,mac,port,dpid):
self.mac = mac
self.port = port
self.dpid = dpid
def add(self):
global table
if self not in table:
table.add(self)
class LearningSwitch(object):
def __init__ (self, connection, transparent):
self.connection = connection
self.transparent = transparent
self.macToPort = {}
connection.addListeners(self)
self.hold_down_expired = _flood_delay == 0
def _handle_PacketIn (self, event):
packet = event.parsed
self.macToPort[packet.src] = event.port # 1
packet_src = str(packet.src)
packet_mac = packet_src.upper()
entry = GlobeLearningTable(packet_mac, event.port, dpid_to_str(self.connection.dpid))
entry.add()
Problem : entry.add() method adds new object every time it is called and increments the items in the table.
This should not happen because
In the add method I am checking that is that object in the table or not , then I am adding that particular object.
Table is a set which is unordered list, which should not have duplicate objects.
Help: is there any way in this set up I can add the object only when it's not in the table.
You need to implement __eq__ and __hash__ methods to teach Python about how to recognise unique GlobeLearningTable instances.
class GlobeLearningTable(object):
def __init__(self,mac,port,dpid):
self.mac = mac
self.port = port
self.dpid = dpid
def __hash__(self):
return hash((self.mac, self.port, self.dpid))
def __eq__(self, other):
if not isinstance(other, type(self)): return NotImplemented
return self.mac == other.mac and self.port == other.port and self.dpid == other.dpid
Now your object is comparable, and equal objects will also return equal values for __hash__. This lets set and dict objects store your objects efficiently and detect if it is already present:
>>> demo = set([GlobeLearningTable('a', 10, 'b')])
>>> GlobeLearningTable('a', 10, 'b') in demo
True
On this sample code i want to use the variables on the function db_properties at the function connect_and_query. To accomplish that I choose the return. So, using that strategy the code works perfectly. But, in this example the db.properties files only has 4 variables. That said, if the properties file had 20+ variables, should I continue using return? Or is there a most elegant/cleaner/correct way to do that?
import psycopg2
import sys
from ConfigParser import SafeConfigParser
class Main:
def db_properties(self):
cfgFile='c:\test\db.properties'
parser = SafeConfigParser()
parser.read(cfgFile)
dbHost = parser.get('database','db_host')
dbName = parser.get('database','db_name')
dbUser = parser.get('database','db_login')
dbPass = parser.get('database','db_pass')
return dbHost,dbName,dbUser,dbPass
def connect_and_query(self):
try:
con = None
dbHost=self.db_properties()[0]
dbName=self.db_properties()[1]
dbUser=self.db_properties()[2]
dbPass=self.db_properties()[3]
con = None
qry=("select star from galaxy")
con = psycopg2.connect(host=dbHost,database=dbName, user=dbUser,
password=dbPass)
cur = con.cursor()
cur.execute(qry)
data = cur.fetchall()
for result in data:
qryResult = result[0]
print "the test result is : " +qryResult
except psycopg2.DatabaseError, e:
print 'Error %s' % e
sys.exit(1)
finally:
if con:
con.close()
operation=Main()
operation.connect_and_query()
Im using python 2.7
Regards
If there are a lot of variables, or if you want to easily change the variables being read, return a dictionary.
def db_properties(self, *variables):
cfgFile='c:\test\db.properties'
parser = SafeConfigParser()
parser.read(cfgFile)
return {
variable: parser.get('database', variable) for variable in variables
}
def connect_and_query(self):
try:
con = None
config = self.db_properties(
'db_host',
'db_name',
'db_login',
'db_pass',
)
#or you can use:
# variables = ['db_host','db_name','db_login','db_pass','db_whatever','db_whatever2',...]
# config = self.db_properties(*variables)
#now you can use any variable like: config['db_host']
# ---rest of the function here---
Edit: I refactored the code so you can specify the variables you want to load in the calling function itself.
You certainly don't want to call db_properties() 4 times; just call it once and store the result.
It's also almost certainly better to return a dict rather than a tuple, since as it is the caller needs to know what the method returns in order, rather than just having access to the values by their names. As the number of values getting passed around grows, this gets even harder to maintain.
e.g.:
class Main:
def db_properties(self):
cfgFile='c:\test\db.properties'
parser = SafeConfigParser()
parser.read(cfgFile)
configDict= dict()
configDict['dbHost'] = parser.get('database','db_host')
configDict['dbName'] = parser.get('database','db_name')
configDict['dbUser'] = parser.get('database','db_login')
configDict['dbPass'] = parser.get('database','db_pass')
return configDict
def connect_and_query(self):
try:
con = None
conf = self.db_properties()
con = None
qry=("select star from galaxy")
con = psycopg2.connect(host=conf['dbHost'],database=conf['dbName'],
user=conf['dbUser'],
password=conf['dbPass'])
NB: untested
You could change your db_properties to return a dict:
from functools import partial
# call as db_properties('db_host', 'db_name'...)
def db_properties(self, *args):
parser = SafeConfigParser()
parser.read('config file')
getter = partial(parser.get, 'database')
return dict(zip(args, map(getter, args)))
But otherwise it's probably best to keep the parser as an attribute of the instance, and provide a convenience method...
class whatever(object):
def init(self, *args, **kwargs):
# blah blah blah
cfgFile='c:\test\db.properties'
self._parser = SafeConfigParser()
self._parser.read(cfgFile)
#property
def db_config(self, key):
return self._parser.get('database', key)
Then use con = psycopg2.connect(host=self.db_config('db_host')...)
I'd suggest returning a namedtuple:
from collections import namedtuple
# in db_properties()
return namedtuple("dbconfig", "host name user password")(
parser.get('database','db_host'),
parser.get('database','db_name'),
parser.get('database','db_login'),
parser.get('database','db_pass'),
)
Now you have an object that you can access either by index or by attribute.
config = self.db_properties()
print config[0] # db_host
print config.host # same