Reputation: 135
I want to wrap the functionality of for loop so it would be more intuitive to use it. In my case, I have to parse xml file looks like this:
<instance id="line-n.w8_047:15696:">
<answer instance="line-n.w8_047:15696:" senseid="product" />
<context> context1 </context>
</instance>
<instance id="line-n.w8_088:12441:">
<answer instance="line-n.w8_088:12441:" senseid="product" />
<context> another context</context>
</instance>
I wrote a class for Instance
like this:
class Instance:
def __init__(self, id, answer, context):
self.id = id
self.answer = answer
self.context = context
I wrote the next function to enumerate the instances:
import xml.etree.ElementTree as ET
def enum_instances(file_path, action):
for instance_xml in ET.parse(file_path).getroot().find('lexelt'):
action(Instance(
instance_xml.attrib['id'],
instance_xml.find('answer').attrib['senseid'],
instance_xml.find('context').text)
)
The action
parameter is a callback to do some action with the Instance
, like this:
enum_instances('/path/to/xml', lambda instance: print(instance.context))
but it looks a bit odd, I would like it be more intuitive, like this:
for instance in enum_instances(file_path):
print(instance.context)
what is the best way to implement that 'iterable' function? Thanks
Upvotes: 0
Views: 804
Reputation: 142256
Instead of passing a callable to your function, make it yield an Instance
, then you can get the behaviour you want, eg:
def enum_instances(file_path, action=None):
for instance_xml in ET.parse(file_path).getroot().find('lexelt'):
instance = Instance(
instance_xml.attrib['id'],
instance_xml.find('answer').attrib['senseid'],
instance_xml.find('context').text)
if action is not None:
instance = action(instance)
yield instance
In this case - I've defaulted action
to None
, but it leaves you room to pass a function to mutate the instance
somehow before yield
ing it if required.
Then:
for instance in enum_instances('some_file_path'):
print(instance.context)
Upvotes: 1
Reputation: 19317
Generators for the win, in this case. Something like
def enum_instances(file_path):
for instance_xml in ET.parse(file_path).getroot().find('lexelt'):
yield Instance(
instance_xml.attrib['id'],
instance_xml.find('answer').attrib['senseid'],
instance_xml.find('context').text)
Then you can say exactly what you required:
for instance in enum_instances(file_path):
print(instance.context)
Upvotes: 3