Optimal way to apply a conditional If statement - python

I'm basically defining a set of parameters below in the Start() method. Most of the params will be the same except for the request.Continuation which can have a value of either 6 or 3. My thinking was to have a list of the symbols that would get the value 6 (in self.continuation) and just say something like "If in self.continuation, value=6, else 3".
I'm fairly new to python so this could be way off but I wasn't sure if this would be a good use case for a lambda expression.
class BarsRequestSample(CELEnvironment.CELSinkBase):
def __init__(self):
self.symbols = ['CLES12Z', 'HOE']
self.continuation=['ClES12Z', 'CLES6M']
def Start(self):
for symbol in self.symbols:
request.Symbol = symbol
request.RangeStart = 0
request.RangeEnd = -60
request.IntradayPeriod = 5
request.Continuation = 6
request.UpdatesEnabled = True
request.EqualizeCloses = True
request.SessionsFilter = 31
What I know I could do:
def Start(self):
for symbol in self.symbols:
request.Symbol = symbol
request.RangeStart = 0
request.RangeEnd = -60
request.IntradayPeriod = 5
#potential attempt
if symbol in self.continuation:
request.Continuation = 6
else:
request.Continuation = 3
request.UpdatesEnabled = True
request.EqualizeCloses = True
request.SessionsFilter = 31
I'm just getting an intuition that there may be a more concise way to do the same thing - would appreciate any thoughts!

I would make the list of symbols a set. Sets containment is an O(1) operation versus lists which are O(n). It doesn't matter for two elements, but it's a good habit to get into.
self.continuation = {'ClES12Z', 'CLES6M'}
You can use a conditional expression to condense the assignment to one line:
request.Continuation = 6 if symbol in self.continuation else 3

For lambda:
https://github.com/baruchel/continuation/blob/master/continuation/init.py
"""
A module for adding a call/cc feature to Python.
"""
__version__ = '0.1'
__internal_type_error__ = (
"Argument of a continuation must be a continuable function."
)
class _Continuation(Exception):
def __init__(self, f, args, kwargs):
self.func, self.args, self.kwargs = f, args, kwargs
class Continuation():
def __init__(self, calling_id):
self.calling_id = calling_id
def __callback__(self, f):
if isinstance(f, _Continuation):
f.uid = id(self)
raise f
raise TypeError(__internal_type_error__)
def __call__(self, f):
return lambda *args, **kwargs: self.__callback__(f(*args, **kwargs))
__lshift__ = __call__
def with_continuation(func):
def _w(*args, **kwargs):
return _Continuation(func, args, kwargs)
_w.__with_continuation_signature__ = True
return _w
class _with_CC():
def __call__(self, f):
try:
_ = f.__with_continuation_signature__
except AttributeError:
raise TypeError(__internal_type_error__)
return (
lambda *args, **kwargs:
_with_CC().__callback__(f(*args, **kwargs)))
__rshift__ = __call__
def __callback__(self, f):
k = Continuation(id(self))
i = id(k)
while True:
try:
return (f.func)(k)(*f.args, **f.kwargs)
except _Continuation as e:
if i == e.uid: f = e
else: raise e
with_CC = _with_CC()

Related

ANTLR4 Arith Expression visitor order operation

I am trying to understand how visitor context work in python version of ANTLR4
I am using the Python3 grammar and I trying to visit "arith_expr"
with this input example x = 10 + 50 - 50 I have this context in the visitor
len(ctx.term()) = 3 is the value of atom [10,50,50]
len(ctx.ADD()) = 1
len(ctx.MINUS()) = 1
What is the order of the operator?
arith_expr
: term (('+'|'-') term)*
;
class Arith_exprContext(ParserRuleContext):
def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1):
super().__init__(parent, invokingState)
self.parser = parser
def term(self, i:int=None):
if i is None:
return self.getTypedRuleContexts(MBIParser.TermContext)
else:
return self.getTypedRuleContext(MBIParser.TermContext,i)
def ADD(self, i:int=None):
if i is None:
return self.getTokens(MBIParser.ADD)
else:
return self.getToken(MBIParser.ADD, i)
def MINUS(self, i:int=None):
if i is None:
return self.getTokens(MBIParser.MINUS)
else:
return self.getToken(MBIParser.MINUS, i)
def getRuleIndex(self):
return MBIParser.RULE_arith_expr
def enterRule(self, listener:ParseTreeListener):
if hasattr( listener, "enterArith_expr" ):
listener.enterArith_expr(self)
def exitRule(self, listener:ParseTreeListener):
if hasattr( listener, "exitArith_expr" ):
listener.exitArith_expr(self)
def accept(self, visitor:ParseTreeVisitor):
if hasattr( visitor, "visitArith_expr" ):
return visitor.visitArith_expr(self)
else:
return visitor.visitChildren(self)
this is the override visitor def
def visitArith_expr(self, ctx:MBIParser.Arith_exprContext):
print(len(ctx.term())) #3
self.visit(ctx.term(0)) #10
self.visit(ctx.term(1)) #50
self.visit(ctx.term(2)) #50
print(len(ctx.ADD())) #1
print(len(ctx.MINUS())) #1
return self.visitChildren(ctx)
Thank you for your explanation
You could collect all operators inside a list like this:
arith_expr
: term (operators+=('+'|'-') term)*
;
The operators is a list and contains all operators. You can then do something like this in your visitor:
def visitArith_expr(self, ctx):
result = self.visit(ctx.term(0))
for i in range(len(ctx.operators)):
if ctx.operators[i].type == MBILexer.ADD:
result += self.visit(ctx.term(i + 1))
else:
result -= self.visit(ctx.term(i + 1))
return result
def visitTerm(self, ctx):
return int(ctx.getText())
Or better, do something like this:
expr
: expr ('+' | '-') expr #add_expr
| term #term_expr
;
in which case the visitor will get a lot easier:
# expr ('+' | '-') expr #add_expr
def visitAdd_expr(self, ctx):
if ctx.ADD() is not None:
return self.visit(ctx.expr(0)) + self.visit(ctx.expr(1))
return self.visit(ctx.expr(0)) - self.visit(ctx.expr(1))
# term #term_expr
def visitTerm_expr(self, ctx):
return self.visit(ctx.term())
def visitTerm(self, ctx):
return int(ctx.getText())

NameError: name '_length' is not defined

I'm using python3 and when trying to run the following code, I'm facing the error:
NameError: name '_length' is not defined
The code itself:
class OFPHELLO(GenericStruct):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._length = self.get_size()
_msg_type = OFPType.OFPT_HELLO
_build_order = ('header', 'x')
header = OFPHeader(type = _msg_type, length = _length)
x = UBInt8()
The problem is the _length variable that I'm passing in OFPHeader, the value of which is computed in GenericStruct. How can I compute the _length variable inside the OFPHELLO class and use it as parameter in the OFPHeader class?
Following the GenericStruct code:
class GenericStruct(object):
def __init__(self, **kwargs):
for a in kwargs:
try:
field = getattr(self, a)
field.value = kwargs[a]
except AttributeError:
raise OFPException("Attribute error: %s" % a)
def build(self):
hexa = ""
for field in self._build_order:
hexa += getattr(self, field).build()
return hexa
def parse(self, buff):
begin = 0
for field in self._build_order:
size = getattr(self, field).get_size()
getattr(self,field).parse(buff, offset=begin)
begin += size
def get_size(self):
tot = 0
for field in self._build_order:
tot += getattr(self, field).get_size()
return tot
- how have you defined (GenericStruct)
- header = OFPHeader(type = _msg_type, length = _lenght)
- correct the spelling to _length
-- and please post the entire code next time

Avoiding unnecessary key evaluations when sorting a list

I have a list which I want to sort by multiple keys, like:
L = [ ... ]
L.sort(key = lambda x: ( f(x), g(x) ))
This works fine. However, this results with unnecessary calls to g, which I would like to avoid (for being potentially slow). In other words, I want to partially and lazily evaluate the key.
For example, if f is unique over L (i.e. len(L) == len(set(map(f,L)))) no calls to g should be made.
What would be the most elegant/pythonic way to do this?
One way I can think of is to define a custom cmp function (L.sort(cmp=partial_cmp)), but IMO this is less elegant and more complicated than using the key parameter.
Another way would be to define a key-wrapper class which takes a generator expression to generate the different parts of the key, and override the comparison operators to compare one-by-one. However, I'm feeling there must be a simpler way...
EDIT: I'm interested in a solution for the general problem of sorting by multiple functions, not only two as in my example above.
You can try using itertools.groupby:
result = []
for groupKey, group in groupby(sorted(L, key=f), key=f):
sublist = [y for y in group]
if len(sublist) > 1:
result += sorted(sublist, key=g)
else:
result += sublist
Another possibility, even less elegant, but in place:
L.sort(key = f)
start = None
end = None
for i,x in enumerate(L):
if start == None:
start = i
elif f(x) == f(L[start]):
end = i
elif end == None:
start = i
else:
L[start:end+1] = sorted(L[start:end+1], key=g)
start = None
if start != None and end != None:
L[start:end+1] = sorted(L[start:end+1], key=g)
First version generalized to any number of functions:
def sortBy(l, keyChain):
if not keyChain:
return l
result = []
f = keyChain[0]
for groupKey, group in groupby(sorted(l, key=f), key=f):
sublist = [y for y in group]
if len(sublist) > 1:
result += sortBy(sublist, keyChain[1:])
else:
result += sublist
return result
The second version generalized to any number of functions (not fully in place though):
def subSort(l, start, end, keyChain):
part = l[start:end+1]
sortBy(part, keyChain[1:])
l[start:end+1] = part
def sortBy(l, keyChain):
if not keyChain:
return
f = keyChain[0]
l.sort(key = f)
start = None
end = None
for i,x in enumerate(l):
if start == None:
start = i
elif f(x) == f(l[start]):
end = i
elif end == None:
start = i
else:
subSort(l, start, end, keyChain)
start = i
end = None
if start != None and end != None:
subSort(l, start, end, keyChain)
Given a function, you could create a LazyComparer class like this:
def lazy_func(func):
class LazyComparer(object):
def __init__(self, x):
self.x = x
def __lt__(self, other):
return func(self.x) < func(other.x)
def __eq__(self, other):
return func(self.x) == func(other.x)
return lambda x: LazyComparer(x)
To make a lazy key function out of multiple functions, you could create a utility function:
def make_lazy(*funcs):
def wrapper(x):
return [lazy_func(f)(x) for f in funcs]
return wrapper
And together they could be used like this:
def countcalls(f):
"Decorator that makes the function count calls to it."
def _f(*args, **kwargs):
_f._count += 1
return f(*args, **kwargs)
_f._count = 0
return _f
#countcalls
def g(x): return x
#countcalls
def f1(x): return 0
#countcalls
def f2(x): return x
def report_calls(*funcs):
print(' | '.join(['{} calls to {}'.format(f._count, f.func_name)
for f in funcs]))
L = range(10)[::-1]
L.sort(key=make_lazy(f1, g))
report_calls(f1, g)
g._count = 0
L.sort(key=make_lazy(f2, g))
report_calls(f2, g)
which yields
18 calls to f1 | 36 calls to g
36 calls to f2 | 0 calls to g
The #countcalls decorator above is used to connfirm that when f1 returns a lot
of ties, g is called to break the ties, but when f2 returns distinct values,
g does not get called.
NPE's solution adds memoization within the Key class. With the solution above,
you could add memoization outside (independent of) the LazyComparer class:
def memo(f):
# Author: Peter Norvig
"""Decorator that caches the return value for each call to f(args).
Then when called again with same args, we can just look it up."""
cache = {}
def _f(*args):
try:
return cache[args]
except KeyError:
cache[args] = result = f(*args)
return result
except TypeError:
# some element of args can't be a dict key
return f(*args)
_f.cache = cache
return _f
L.sort(key=make_lazy(memo(f1), memo(g)))
report_calls(f1, g)
which results in fewer calls to g:
10 calls to f1 | 10 calls to g
You could use a key object that would lazily evaluate and cache g(x):
class Key(object):
def __init__(self, obj):
self.obj = obj
self.f = f(obj)
#property
def g(self):
if not hasattr(self, "_g"):
self._g = g(self.obj)
return self._g
def __cmp__(self, rhs):
return cmp(self.f, rhs.f) or cmp(self.g, rhs.g)
Here is an example of use:
def f(x):
f.count += 1
return x // 2
f.count = 0
def g(x):
g.count += 1
return x
g.count = 0
L = [1, 10, 2, 33, 45, 90, 3, 6, 1000, 1]
print sorted(L, key=Key)
print f.count, g.count

how to insert new variable in (*args,**kwargs) section?

i want to make a decoration method to assign the variable which the function would use but wouldn't be deliver by itself.
for example add new variable y in lambda r,i wrote code in this way but didn't work.
r = lambda x:x+y
def foo(func):
def wrapped(*args,**kwargs):
y = 3
return func(y=y,*args,**kwargs)
return wrapped
r = foo(r)
print(r(444))
this wouldn't work too
r = lambda x:x+y
def foo(func):
def wrapped(*args,**kwargs):
y = 3
return func(*args,**kwargs)
return wrapped
r = foo(r)
print(r(444))
kwargs is a casual python dict type, so you can just set the value of the y key to be 3
r = lambda x, y=0:x+y
def foo(func):
def wrapped(*args,**kwargs):
print type(kwargs) # will output <type 'dict'>
kwargs['y'] = 3
return func(*args,**kwargs)
return wrapped
In Understanding kwargs in Python this is explained in details.
Problem is that the function r can accept only one argument, you need to change its definition to accept more args:
r = lambda x, y=0, *args, **kwargs: x + y
def foo(func):
def wrapped(*args,**kwargs):
y = 3
return func(y=y, *args,**kwargs)
return wrapped
r = foo(r)
print(r(444))
#447

Python IRC bot /mode, /ban, /part, /join

Sooo I have an IRC bot based on Skybot (IRC bot). I've looked into its documentation but it's not stated how to do it. I'd like to make it join, quit, part, set mode and other irc commands, but typing them from chan. Simple example:
.part #hello ~ Parts the chan
.mode #hello +b Tom - Bans Tom
That's what it has in its documentation about events
#hook.event(irc_command)
Event hooks are called whenever a specific IRC command is issued. For
example, if you provide "*" as parameter, it will trigger on every
line. If you provide "PRIVMSG", it will only trigger on actual lines
of chat (not nick-changes).
The first argument in these cases will be a two-element list of the
form ["#channel", "text"].
That's how a simple command works.
from util import hook, http
#hook.command
def calc(inp,say=None):
'Does calculation'
h = http.get_html('http://www.google.com/search', q=inp)
m = h.xpath('//h2[#class="r"]/text()')
if not m:
say("I can't calculate " + inp + ".")
res = ' '.join(m[0].split())
say(res + ".")
hook.py
import inspect
import re
def _hook_add(func, add, name=''):
if not hasattr(func, '_hook'):
func._hook = []
func._hook.append(add)
if not hasattr(func, '_filename'):
func._filename = func.func_code.co_filename
if not hasattr(func, '_args'):
argspec = inspect.getargspec(func)
if name:
n_args = len(argspec.args)
if argspec.defaults:
n_args -= len(argspec.defaults)
if argspec.keywords:
n_args -= 1
if argspec.varargs:
n_args -= 1
if n_args != 1:
err = '%ss must take 1 non-keyword argument (%s)' % (name,
func.__name__)
raise ValueError(err)
args = []
if argspec.defaults:
end = bool(argspec.keywords) + bool(argspec.varargs)
args.extend(argspec.args[-len(argspec.defaults):
end if end else None])
if argspec.keywords:
args.append(0) # means kwargs present
func._args = args
if not hasattr(func, '_thread'): # does function run in its own thread?
func._thread = False
def sieve(func):
if func.func_code.co_argcount != 5:
raise ValueError(
'sieves must take 5 arguments: (bot, input, func, type, args)')
_hook_add(func, ['sieve', (func,)])
return func
def command(arg=None, **kwargs):
args = {}
def command_wrapper(func):
args.setdefault('name', func.func_name)
_hook_add(func, ['command', (func, args)], 'command')
return func
if kwargs or not inspect.isfunction(arg):
if arg is not None:
args['name'] = arg
args.update(kwargs)
return command_wrapper
else:
return command_wrapper(arg)
def event(arg=None, **kwargs):
args = kwargs
def event_wrapper(func):
args['name'] = func.func_name
args.setdefault('events', ['*'])
_hook_add(func, ['event', (func, args)], 'event')
return func
if inspect.isfunction(arg):
return event_wrapper(arg, kwargs)
else:
if arg is not None:
args['events'] = arg.split()
return event_wrapper
def singlethread(func):
func._thread = True
return func
def regex(regex, flags=0, **kwargs):
args = kwargs
def regex_wrapper(func):
args['name'] = func.func_name
args['regex'] = regex
args['re'] = re.compile(regex, flags)
_hook_add(func, ['regex', (func, args)], 'regex')
return func
if inspect.isfunction(regex):
raise ValueError("regex decorators require a regex to match against")
else:
return regex_wrapper
and misc.py, there's one hook.event command there:
#autorejoin channels
#hook.event('KICK')
def rejoin(paraml, conn=None):
if paraml[1] == conn.nick:
if paraml[0].lower() in conn.channels:
conn.join(paraml[0])
#join channels when invited
#hook.event('INVITE')
def invite(paraml, conn=None):
conn.join(paraml[-1])
#hook.event('004')
def onjoin(paraml, conn=None):
# identify to services
nickserv_password = conn.conf.get('nickserv_password', '')
nickserv_name = conn.conf.get('nickserv_name', 'nickserv')
nickserv_command = conn.conf.get('nickserv_command', 'IDENTIFY %s')
if nickserv_password:
conn.msg(nickserv_name, nickserv_command % nickserv_password)
time.sleep(1)
# set mode on self
mode = conn.conf.get('mode')
if mode:
conn.cmd('MODE', [conn.nick, mode])
# join channels
for channel in conn.channels:
conn.join(channel)
time.sleep(1) # don't flood JOINs
# set user-agent
ident, rev = get_version()
main.py, where conn things are defined.
class Input(dict):
def __init__(self, conn, raw, prefix, command, params,
nick, user, host, paraml, msg):
chan = paraml[0].lower()
if chan == conn.nick.lower(): # is a PM
chan = nick
def say(msg):
conn.msg(chan, msg)
def reply(msg):
if chan == nick: # PMs don't need prefixes
conn.msg(chan, msg)
else:
conn.msg(chan, nick + ': ' + msg)
def pm(msg):
conn.msg(nick, msg)
def set_nick(nick):
conn.set_nick(nick)
def me(msg):
conn.msg(chan, "\x01%s %s\x01" % ("ACTION", msg))
def notice(msg):
conn.cmd('NOTICE', [nick, msg])
dict.__init__(self, conn=conn, raw=raw, prefix=prefix, command=command,
params=params, nick=nick, user=user, host=host,
paraml=paraml, msg=msg, server=conn.server, chan=chan,
notice=notice, say=say, reply=reply, pm=pm, bot=bot,
me=me, set_nick=set_nick, lastparam=paraml[-1])
# make dict keys accessible as attributes
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
self[key] = value
I don't really get how can I do it. Thanks for your help!

Categories