开发者

Python equivalent of PHP's @

开发者 https://www.devze.com 2023-03-05 19:18 出处:网络
Is there a Python equivalen开发者_JAVA百科t of PHP\'s @? @function_which_is_doomed_to_fail(); I\'ve always used this block:

Is there a Python equivalen开发者_JAVA百科t of PHP's @?

@function_which_is_doomed_to_fail();

I've always used this block:

try:
  foo()
except:
  pass

But I know there has to be a better way.

Does anyone know how I can Pythonicify that code?


I think adding some context to that code would be appropriate:

for line in blkid:
  line = line.strip()
  partition = Partition()

  try:
    partition.identifier = re.search(r'^(/dev/[a-zA-Z0-9]+)', line).group(0)
  except:
    pass

  try:
    partition.label = re.search(r'LABEL="((?:[^"\\]|\\.)*)"', line).group(1)
  except:
    pass

  try:
    partition.uuid = re.search(r'UUID="((?:[^"\\]|\\.)*)"', line).group(1)
  except:
    pass

  try:
    partition.type = re.search(r'TYPE="((?:[^"\\]|\\.)*)"', line).group(1)
  except:
    pass

  partitions.add(partition)


What you are looking for is anti-pythonic, because:

The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

In your case, I would use something like this:

match = re.search(r'^(/dev/[a-zA-Z0-9]+)', line)
if match:
    partition.identifier = match.group(0)

And you have 3 lines instead of 4.


There is no better way. Silently ignoring error is bad practice in any language, so it's naturally not Pythonic.


Building upon Gabi Purcanu's answer and your desire to condense to one-liners, you could encapsulate his solution into a function and reduce your example:

def cond_match(regexp, line, grp):
    match = re.search(regexp, line)
    if match:
        return match.group(grp)
    else:
        return None

for line in blkid:
    line = line.strip()
    partition = Partition()
    partition.identifier = cond_match(r'^(/dev/[a-zA-Z0-9]+)', line, 0)
    partition.label = cond_match(r'LABEL="((?:[^"\\]|\\.)*)"', line, 1)
    partition.uuid = cond_match(r'UUID="((?:[^"\\]|\\.)*)"', line, 1)
    partition.type = cond_match(r'TYPE="((?:[^"\\]|\\.)*)"', line, 1)
    partitions.add(partition)


Please don't ask for Python to be like PHP. You should always explicitly trap the most specific error you can. Catching and ignoring all errors like that is not good best practice. This is because it can hide other problems and make bugs harder to find. But in the case of REs, you should really check for the None value that it returns. For example, your code:

label = re.search(r'LABEL="((?:[^"\\]|\.)*)"', line).group(1)

Raises an AttributeError if there is not match, because the re.search returns None if there is no match. But what if there was a match but you had a typo in your code:

label = re.search(r'LABEL="((?:[^"\\]|\.)*)"', line).roup(1)

This also raises an AttributeError, even if there was a match. But using the catchall exception and ignoring it would mask that error from you. You will never match a label in that case, and you would never know it until you found it some other way, such as by eventually noticing that your code never matches a label (but hopefully you have unit tests for that case...)

For REs, the usual pattern is this:

matchobj = re.search(r'LABEL="((?:[^"\\]|\.)*)"', line)
if matchobj:
    label = matchobj.group(1)

No need to try and catch an exception here since there would not be one. Except... when there was an exception caused by a similar typo.


Use data-driven design instead of repeating yourself. Naming the relevant group also makes it easier to avoid group indexing bugs:

_components = dict(
  identifier = re.compile(r'^(?P<value>/dev/[a-zA-Z0-9]+)'),
  label = re.compile(r'LABEL="(?P<value>(?:[^"\\]|\\.)*)"'),
  uuid = re.compile(r'UUID="(?P<value>(?:[^"\\]|\\.)*)"'),
  type = re.compile(r'TYPE="(?P<value>(?:[^"\\]|\\.)*)"'),
)

for line in blkid:
    line = line.strip()
    partition = Partition()

    for name, pattern in _components:
        match = pattern.search(line)
        value = match.group('value') if match else None
        setattr(partition, name, value)

    partitions.add(partition)


There is warnings control in Python - http://docs.python.org/library/warnings.html

After edit:

You probably want to check if it is not None before trying to get the groups. Also use len() on the groups to see how many groups you have got. "Pass"ing the error is definitely not the way to go.

0

精彩评论

暂无评论...
验证码 换一张
取 消