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
Related
In Python I'm using a class out of library. I only want to call certain functions if a certain parameter is set.
For example:
import pyserial
serialobj=serial.Serial()
parameter=0
#The part idk about
def serialobjpass()
if parameter=1:
pass Argument to serialobj.
serialobj might be serialobj.write() or serialobj.recieve()
I would be just like a man in the middle to siphone out calls when i dont want them
Something like this may work:
class Forwarder(object):
def __init__(self, target):
self.target = target
self.parameter = 1
def read(self, n):
print(('READ', n))
if self.parameter:
return self.target.read(n)
else:
return 0
def write(self, data):
print(('WRITE', data))
if self.parameter:
return self.target.write(data)
else:
return len(data)
import pyserial
serialobj = Forwarder(serial.Serial())
...
serialobj.write('HELLO\r\n')
print([serialobj.read(1)])
self.parameter = 0 # Prevent subsequent reads or writes.
serialobj.write('World\r\n') # Won't be written to the serial port.
In this setup the the Forwarder object intercepts all calls to the .read and .write methods, and calls the original .read and .write methods depending on how the parameter is set.
I'm new to Python and trying to use class inheritance, and haven't been able to wrap my head around sharing variables. I have two classes so far, Scan and Ping:
scan.py
class Scan(object):
""" Super class for scans """
identifier = str(random.getrandbits(128))
timestamp = int(time.time())
results_dir = "/tmp/{}/".format(identifier)
total_hosts = 0
def __init__(self, target_hosts=None, target_ports=None):
self.__target_hosts = target_hosts
self.__target_ports = target_ports
self.scan_string = "-sT -O --script auth,vuln"
#property
def target_hosts(self):
return self.__target_hosts
#target_hosts.setter
def target_hosts(self, hosts):
""" Sets target hosts for scan """
""" Nmap Expects to be single-spaced '1 2 3' separated """
self.__target_hosts = hosts.replace(", ", " ")
ping.py
import nmap
from .scan import Scan
class Ping(Scan):
""" Ping sweep """
def __init__(self, ping_string, hosts):
super(Scan, self).__init__()
self.ping_string = ping_string
self.hosts = hosts
In my script that pretty much calls everything, I'm attempting:
from models.scan import Scan
from models.ping import Ping
s = Scan()
hosts = "192.168.0.0/24"
s.target_hosts = hosts
pinger = Ping(ping_string, s.target_hosts)
This line doesn't make sense to me ... if Ping inherits from Scan, why does this only work when I call s.targets_hosts ? Shouldn't I be able to call target_hosts from my Ping class like Ping.target_hosts ?
What might be making this hard to understand is that it's an odd example. In your example, the correct input for the hosts parameter that is needed to make an instance of Ping needs to come from a property only accessible from an instance of Ping (or its parent Scan).
Any method (or property) that has self as a parameter relies on a specific instance of that class which needs to be created first. If there was a staticmethod or classmethod they would be callable directly from the class.
You can only get and set target_hosts from a specific instance of the class (in this case either Scan or Ping). If you call Scan.target_hosts or Ping.target_hosts, it will return something like <property at 0x51cd188>. This is basically returning an unusable function from the class. It's saying, "The class dictionary contains instructions here on how to return some useful stuff from AN INSTANCE of <class>."
If you make an instance of Ping or Scan, you now have access to your target_hosts property.
>>> scan = Scan()
>>> scan.target_hosts = 'host1, host2, host3'
>>> scan.target_hosts
'host1 host2 host3'
>>> ping = Ping('stuff', 'nonsense')
>>> ping.hosts
'nonsense'
>>> ping.target_hosts = 'host4, host5, host6'
>>> ping.target_hosts
'host4 host5 host6'
You could run your script with a dummy Ping instance. This should work.
from models.scan import Scan
from models.ping import Ping
dummy = Ping('ignore', 'this')
hosts = "192.168.0.0/24"
dummy.target_hosts = hosts
pinger = Ping(ping_string, dummy.target_hosts)
Or, if Scan had a staticmethod, Ping could use it as well.
class Scan(object):
""" Super class for scans """
identifier = str(random.getrandbits(128))
timestamp = int(time.time())
results_dir = "/tmp/{}/".format(identifier)
total_hosts = 0
def __init__(self, target_hosts=None, target_ports=None):
self.__target_hosts = target_hosts
self.__target_ports = target_ports
self.scan_string = "-sT -O --script auth,vuln"
#staticmethod
def prep_hosts(hosts):
return hosts.replace(", ", " ")
...
and then
from models.scan import Scan
from models.ping import Ping
hosts = "192.168.0.0/24"
input_hosts = Ping.prep_hosts(hosts) # or Scan.prep_hosts(hosts)
pinger = Ping(ping_string, input_hosts)
How do I overload __init__() in Python? I'm used to C/C++ where the compiler can see the difference in data type, but since there are no data types in Python, how can I make sure the third method gets called instead of the second when I give a string as parameter instead of an int?
class Handle:
def __init__(self):
self.pid = -1
def __init__(self, pid):
self.pid = pid
def __init__(self, procname):
print(procname)
self.pid = -1 # find pid by name
In C++ you can define multiple functions/methods with the same name and different signatures. In Python, everytime you define a new function with the same name of a previously defined function, you are replacing it.
To achieve what you want, you have to use optional arguments and/or explicit checks.
Here are a few possible solutions:
class Handle:
def __init__(self, pid=-1):
if isinstance(pid, str):
self.procname = pid
self.pid = -1
else:
self.procname = None
self.pid = pid
class Handle:
# Both pid and procname may be specified at the same time.
def __init__(self, pid=-1, procname=None):
self.procname = procname
self.pid = pid
class Handle:
# Either pid or procname, not both, may be specified.
def __init__(self, pid=-1, procname=None):
if pid >= 0 and procname is not None:
raise ValueError('you can specify either pid or procname, not both')
self.procname = procname
self.pid = pid
class Handle:
def __init__(self, pid=-1):
self.pid = pid
# A separate constructor, with a different name,
# because "explicit is better than implicit" and
# "sparse is better than dense" (cit. The Zen of
# Python).
# In my opinion, this is the most Pythonic solution.
#classmethod
def from_process_name(cls, procname):
pid = get_pid(procname)
return cls(pid)
By the way, I would not recommend using -1 for "not specified". I'd rather use None.
Couldn't the PEP 443 : Single-dispatch generic functions be useful in your case ?
With something like (very basic example) :
from functools import singledispatch
class Handle:
def __init__(self, arg=None):
self.pid = init_from_arg(arg)
#singledispatch
def init_from_arg(arg):
# If None or neither an integer nor a string, return None
return None
# If the argument is an integer (ie the pid)
#init_from_arg.register(int)
def _(arg):
return arg
# If the argument provided is a string (ie the procname)
#init_from_arg.register(str)
def _(arg):
return get_pid_from_procname(arg)
Edit : Following the advice in comments, these functions could probably be made staticmethods, although I had trouble with them so I reverted to the code of my original answer (see edit history if needed)
Use isinstance to check the type:
class Handle:
def __init__(self, arg):
if isinstance(arg, str):
self.pid = arg
else:
self.pid = -1
If you want to do one action or another you might be better setting the arg to None and using it based on whether it is set or not:
class Handle:
def __init__(self, by_name=None):
self.by_name = by_name
Then just check later if it is None:
if self.by_name is not None:
# find by name
else:
# by pid
Of if you want the user to have a choice to pass either a pid or name:
class Handle:
def __init__(self, by_name=None,by_pid=None):
self.by_name = by_name
self.by_pid = by_pid
The simplest solution would be to take a single arg and move the logic wherever you call it, just because something is not None does not make it an int or string so you should also check for that or your program will error:
class Handle:
def __init__(self, proc):
self.proc = proc
if not isinstance(self.proc, (int,str)):
raise ValueError("Must be process name or pid.")
def find_proc(self):
if isinstance(self.proc, str):
# find by name
else:
# by pid
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
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.