I am trying to do something like this:
class SomeEnum(str, Enum):
STRING_A = 'This is a string A with variable ' + variable
STRING_B = 'This is a string B with variable ' + variable
and use it like a template, for instance:
some_list.append(SomeEnum.STRING_A(variable))
is this even possible in Enums since it defies the purpose of Enums a bit? Or what else would you suggest instead of Enums? Thanks a lot!
I'd say define a __call__ method along with some string formatting
class SomeEnum(str, Enum):
STRING_A = 'This is a string A with variable %s %s '
STRING_B = 'This is a string B with variable %s %s'
def __call__(self, *args):
return self % args
print(SomeEnum.STRING_A("a", "b")) # This is a string A with variable a b
print(SomeEnum.STRING_B("c", "d")) # This is a string B with variable c d
The only rule : provide the same amount of paramater, as the string expects
Dynamic formatting
class SomeEnum(str, Enum):
STRING_A = 'This is a string A with variable '
STRING_B = 'This is a string B with variable '
def __call__(self, *args):
if len(args) == 1:
return self + args[0]
return self + ', '.join(args[:-1]) + " and " + args[-1]
print(SomeEnum.STRING_A("a")) # This is a string A with variable a
print(SomeEnum.STRING_B("a", "b")) # This is a string B with variable a and b
print(SomeEnum.STRING_B("a", "b", "c")) # This is a string B with variable a, b and c
No!. You can't do like that. It is not practical. The code you're writing cannot see intellisense. If you want to see it in public, then you can use self.
class SomeEnum:
def __init__(self, enum):
self.Enum = enum
self.STRING_A = f'This is a string A with variable {enum}'
self.STRING_B = f'This is a string B with variable {enum}'
num = 6
p1 = SomeEnum(num)
print(p1.STRING_A)
print(p1.STRING_B)
I have two methods here that don't seem to want to talk to eachother. I think the way I use my dictionary is slightly wrong and I've probably confused myself a bit:
def load(self, msg):
loadState = {'foo1' { 'FirstObject':1, 'SecondObject':2 }, 'foo2' { 'FirstObject':3, 'SecondObject':4 }}
foo_objects = loadState.keys()
for name in foo_objects:
if name == 'foo1':
ValueTuple = loadState[foo_objects[0]]
elif name == 'foo2':
ValueTuple = loadState[foo_objects[1]]
self.program.supervisor.setI2c( ValueTuple, foo = name ) #This is where I think it goes wrong
Then to store these values, I pass them over to this method which was working previously, put it doesn't like the new method above:
def setI2c( self, ValueTuple, foo=None ) :
for name in foo :
object = self.objects[name]
for name in ValueTuple :
register = reg(name)
register.value = regNameValueTuple[name]
EDIT: Part where I went wrong:
self.program.supervisor.setI2c( ValueTuple, foo = [name] )
Your load message can be simplified to:
def load(self, msg):
loadState = {'foo1' { 'FirstObject':1, 'SecondObject':2 }, 'foo2' { 'FirstObject':3, 'SecondObject':4 }}
for name, value in foo_objects.iteritems():
self.program.supervisor.setI2c(value, foo=name)
Here, foo is a string, one of the keys in loadState.
You then loop over foo in setI2c, where foo is still as string. That means you are iterating over the individual characters:
>>> foo = 'foo1'
>>> for name in foo:
... print name
...
f
o
o
1
You don't need that loop at all, you most likely wanted this:
def setI2c(self, value_dict, foo=None):
object = self.objects[foo]
for name in value_dict:
register = reg(name)
register.value = regNameValueTuple[name]
but you don't actually use object anywhere in your code, so that line could be removed altogether.
If setI2c() always expects foo to be a list of names, then you should pass in a list in load:
self.program.supervisor.setI2c(value, foo=[name])
I would like a compact way to parse one-line strings that start with mandatory list-elements (unspecified number) and ends with dictionary-like definitions using =.
The element-separator should be , and spaces should become part of the element -- which rules out shlex, I think.
Spaces should/may be stripped at the start and end (quotes, too)
If an element would contain a , the user is required to quote with "
either "key=value,with,comma"
or key="value,with,comma" -- whatever is easier to implement
It's ok to have undefined behavior with wrong quoting or with elements containing a quote-char.
Behaviour with double keys is also undefined.
Slight variations of this are ok if it simplifies the implementation a lot.
Lets call the function opts and have it return a list and a dict,
Here are some input examples and desired results:
opts('dog,cat') # -> ["dog", "cat"], {}
opts('big fish,cat') # -> ["big fish", "cat"], {}
opts('"a dog, a cat",a fish') # -> ["a dog, a cat", "a fish"], {}
opts('key=value') # -> [] {'key':'value'}
opts('key=the value,x=y') # -> [] {'key':'the value', 'x':'y'}
opts('dog, big fish, eats="any, but peas", flies = no! '
# -> ['dog','big fish'], {'eats':'any, but peas', 'flies':'no!' }
I disregarded shlex, argparse, optparse and configparser, I can't see how I should do it with those. I am not sure if Regular Expressions crack this nut, though. json is a bit too strict with the syntax, I think. As is eval, if a bit more to my liking (because it parses python ;-))
My manual solution in macro is not very flexible and I would like to have its parameter handling be replaced by the more general opts(s) function described above:
def macro(s):
kw = { 'see':u"\\see", 'type':u"Chapter", 'title': u'??' }
params = s.split(",")
kw['label'] = params[0]
if len(params) > 1: # very inflexible
kw['title'] = params[1]
for param in params[2:]: # wrong if p[1] is already key=value
key, value = param.split("=",1) # doesn't handle anything, too simple
kw[key] = value
# ...rest of code...
The goal is to have the reusable function opts to be used here:
def macro_see(s):
ls, kw = opts(s)
# ...rest of code...
In this solution, opts is essentially the same as yuvi's (with the added strip). The splitter is a customization of shlex, using posix mode to handle quotes.
def mylex(x):
lex = shlex.shlex(x, posix=True)
lex.whitespace = ','
lex.whitespace_split = True
return list(lex)
def opts(x):
ll = []
dd = {}
items = mylex(x)
for item in items:
if '=' in item:
k, v = item.split('=',1)
dd[k.strip(' "')] = v.strip(' "')
else:
ll.append(item.strip(' "'))
return (ll,dd)
It passes:
trials = [
['dog,cat',(["dog", "cat"], {})],
['big fish,cat',(["big fish", "cat"], {})],
['"a dog, a cat",a fish',(["a dog, a cat", "a fish"], {})],
['key=value',([], {'key':'value'})],
['key=the value,x=y',([], {'key':'the value', 'x':'y'})],
['dog, big fish, eats="any, but peas", flies = no!',(['dog','big fish'], {'eats':'any, but peas', 'flies':'no!' })],
]
for (x,y) in trials:
print('%r'%x)
args = opts(x)
print(args)
if args != y:
print('error, %r'%y)
print('')
What you probably want is to create your own split function, with a flag that toggles when " are introduced. Something like this:
def my_split(string, deli):
res = []
flag = True
start = 0
for i, c in enumerate(string):
if c == '"':
if flag:
flag = False
else:
flag = True
if c == deli and flag:
res.append(string[start:i])
start = i+1
res.append(string[start:])
return res
From there, it's really easy to proceed:
def opts(s):
items = map(lambda x: x.strip(), my_split(s, ','))
# collect
ls = []
kw = {}
for item in items:
if '=' in item:
k, v = item.split('=', 1)
kw[k.strip()] = v.strip()
else:
ls.append(item)
return ls, kw
It's not perfect, there are still a few thing you might need to work on, but that's definetly a start.
Here's an approach where I massage the input so it matches the syntax requirements for python function arguments, then harness the python interpreter via eval to parse them.
import re
s = 'hog, "cog" , dog, bog, "big fish", eats="any, but peas", flies = "no!" '
# I think this will add quotes around any unquoted positional arguments
s = re.sub('(^|,)\ *([^\"\',\ ]+)\ *(?=,|$)', r'\1"\2"', s)
def f(*args, **kwargs):
return (args, kwargs)
print eval("f("+s+")", {'f':f})
output:
(('hog', 'cog', 'dog', 'bog', 'big fish'), {'flies': 'no!', 'eats': 'any, but peas'})
The following is a line in a method of a class in Django:
url = self.success_url % self.object.__dict__
Then I tried an example:
>>> "baby" % {"babe": "bebe"}
"baby"
How could this be useful?
% in that case is being used for String Formatting. Because there are no %s in the word "baby", the word is not modified at all.
In your example of the variable url, self.success_url may be something like "hello %s" and self.object.__dict__ may be {"test": "three"}. So simply, that will print:
hello {'test': 'three'}
Do note that if you ever plan on using something like this, you should be using .format():
>>> d = {'baby':'bebe'}
>>> "hello {[baby]}".format(d)
'hello bebe'
You can use Pythons string formatting like so:
print "%(foo)s is good" % {"foo": "bar"}
> bar is good
Your example is useless, but try:
"Hello, my name is %(babe)s" % { 'babe' : 'bebe'}
url can use any of object instance properties:
class X(object):
success_url = "http://goo.gl/%(x)s"
def __init__(self):
self.x = 13
def get_url(self):
return self.success_url % self.object.__dict__
>>> X().get_url()
'http://goo.gl/13'
One can modify these attributes
>>> x = X()
>>> x.x = 174
>>> X().get_url()
'http://goo.gl/174'
So this is useful when url depends on instance attributes (In my example) or instance object attributes (in your one) for example document fields or id, etc.
So I'm fairly new to Python but I have absolutely no idea why this strong oldUser is changing to current user after I make the parse call. Any help would be greatly appreciated.
while a < 20:
f = urllib.urlopen("SITE")
a = a+1
for i, line in enumerate(f):
if i == 187:
print line
myparser.parse(line)
if fCheck == 1:
result = oldUser[0] is oldUser[1]
print oldUser[0]
print oldUser[1]
else:
result = user is oldUser
fCheck = 1
print result
user = myparser.get_descriptions(firstCheck)
firstCheck = 1
print user
if result:
print "SAME"
array[index+1] = array[index+1] +0
else:
oldUser = user
elif i > 200:
break
myparser.reset()
I don't understand why result doesn't work either... I print out both values and when they're the same it's telling me they're not equal... Also, why does myparser.parse(line) turn oldUser into a size 2 array? Thanks!
** Here's the definition for myparse...
class MyParser(sgmllib.SGMLParser):
"A simple parser class."
def parse(self, s):
"Parse the given string 's'."
self.feed(s)
self.close()
def __init__(self, verbose=0):
"Initialise an object, passing 'verbose' to the superclass."
sgmllib.SGMLParser.__init__(self, verbose)
self.divs = []
self.descriptions = []
self.inside_div_element = 0
def start_div(self, attributes):
"Process a hyperlink and its 'attributes'."
for name, value in attributes:
if name == "id":
self.divs.append(value)
self.inside_div_element = 1
def end_div(self):
"Record the end of a hyperlink."
self.inside_div_element = 0
def handle_data(self, data):
"Handle the textual 'data'."
if self.inside_div_element:
self.descriptions.append(data)
def get_div(self):
"Return the list of hyperlinks."
return self.divs
def get_descriptions(self, check):
"Return a list of descriptions."
if check == 1:
self.descriptions.pop(0)
return self.descriptions
Don’t compare strings with is. That checks if they’re the same object, not two copies of the same string. See:
>>> string = raw_input()
hello
>>> string is 'hello'
False
>>> string == 'hello'
True
Also, the definition of myparser would be useful.
I'm not quite sure what your code is doing, but I suspect you want to use == instead of is. Using is compares object identity, which is not the same as string equality. Two different string objects may contain the same sequence of characters.
result = oldUser[0] == oldUser[1]
If you're curious, for more information on the behaviour of the is operator see Python “is” operator behaves unexpectedly with integers.