如何避免重复编写request.GET.get()以便打印它?

42
我来自于PHP背景,想知道在Python中是否有一种方法可以做到这一点。
在PHP中,您可以用一种方法做两件事情,就像这样:
而不是:
if(getData()){
    $data = getData();
    echo $data;
}

我可以做到这一点:

if($data = getData()){
    echo $data;
}

您检查getData()是否存在,如果存在,则在一条语句中将其赋值给一个变量。

我想知道Python是否有一种方法可以实现这一点?所以,而不是这样做:

if request.GET.get('q'):
    q = request.GET.get('q')
    print q

避免重复编写 request.GET.get('q')


你有收藏Python教程吗?哪一个? - S.Lott
1
只需官方文档:http://docs.python.org/tutorial/ - givp
2
Python幸运地没有C语言的这个问题,而且通常,在很多继承了该问题的C/C++相关语言中,由于可读性和清晰度等原因,它的使用受到不同程度的反对。 - Pavel Minaev
1
重复:https://dev59.com/QnRB5IYBdhLWcg3wtZMV - S.Lott
2
@S.Lott 这不是重复问题,因为另一个问题询问的是 while,这使得所有答案都集中在迭代上,从而完全绕过了流控制语句内部赋值的问题。 - Piotr Dobrogost
1
并不是什么“缺陷”,例如Clojure甚至有特殊的if-let宏。 - kolen
10个回答

26

查看我8年前的配方在这里,专门用于这项任务。

# In Python, you can't code "if x=foo():" -- assignment is a statement, thus
# you can't fit it into an expression, as needed for conditions of if and
# while statements, &c.  No problem, if you just structure your code around
# this.  But sometimes you're transliterating C, or Perl, or ..., and you'd
# like your transliteration to be structurally close to the original.
#
# No problem, again!  One tiny, simple utility class makes it easy...:

class DataHolder:
    def __init__(self, value=None): self.value = value
    def set(self, value): self.value = value; return value
    def get(self): return self.value
# optional but handy, if you use this a lot, either or both of:
setattr(__builtins__,'DataHolder',DataHolder)
setattr(__builtins__,'data',DataHolder())

# and now, assign-and-set to your heart's content: rather than Pythonic
while 1:
    line = file.readline()
    if not line: break
    process(line)
# or better in modern Python, but quite far from C-like idioms:
for line in file.xreadlines():
    process(line)
# you CAN have your C-like code-structure intact in transliteration:
while data.set(file.readline()):
    process(data.get())

31
你的八岁孩子非常聪明!;) - unutbu
3
@unutbu,呵呵 - 那应该是我的(年长的)猫,因为我的孩子们都有点大了... 我年轻的女儿刚开始攻读电信工程博士学位(主要是先进无线电系统)...;-) - Alex Martelli

24

可能不完全是您所想的,但是...

q = request.GET.get('q')
if q:
    print q

这个?


是的,没错。模式是仅在变量存在时使用它(也就是说,它提供有效值,即除了 False 之外的任何值)。 - user9903
谢谢,看起来这是最好的方法。正如@Adam所说,这在Python中是不可能的。谢谢。 - givp
9
这种解决方案的限制在于,如果你想在一系列 if-elif-elif-elif 等语句中使用它。例如,请查看这个 Stack Overflow 上的其他问题:https://dev59.com/1XVD5IYBdhLWcg3wAGiD - Craig McQueen
@Amber,这个问题是当q==0或者q==0.时,if条件会失败。if将其条件表达式转换为bool类型,而00.都被转换为False - hobs
@hobs 当然可以。如果你认为有时候可能会出现这种情况,你也可以使用更明确的条件语句(例如:if q is not None:)。 - Amber

10

这是对Alex答案的一种变化:

class DataHolder:
    def __init__(self, value=None, attr_name='value'):
        self._attr_name = attr_name
        self.set(value)
    def __call__(self, value):
        return self.set(value)
    def set(self, value):
        setattr(self, self._attr_name, value)
        return value
    def get(self):
        return getattr(self, self._attr_name)
save_data = DataHolder()

使用方法:

if save_data(get_input()):
    print save_data.value

或者如果你喜欢另一种界面:

if save_data.set(get_input()):
    print save_data.get()

我会认为在 if-elif-elif-elif 等结构中测试一系列正则表达式会很有帮助,就像这个SO问题中的例子:

import re

input = u'test bar 123'
save_match = DataHolder(attr_name='match')
if save_match(re.search('foo (\d+)', input)):
    print "Foo"
    print save_match.match.group(1)
elif save_match(re.search('bar (\d+)', input)):
    print "Bar"
    print save_match.match.group(1)
elif save_match(re.search('baz (\d+)', input)):
    print "Baz"
    print save_match.match.group(1)

1
我喜欢你在DataHolder中添加__call__()的功能,但是我不明白为什么指定attr_name很有用。如果DataHolder是一个单例或者其实例可以保存多个值,每个值存储在不同的属性中,那么我就会理解了,但似乎在这里并没有强烈的目的。 - Mr. Lance E Sloan
1
@LS:是的,我本来可以把它修复为 “value” 或者 “x”。但是好的变量命名可以提高可读性。这就是核心所在。 - Craig McQueen

2

PEP 572引入了赋值表达式。从Python 3.8开始,您可以编写:

if q := request.GET.get('q'):
    print q

以下是PEP中“语法和语义”部分的更多示例:

Syntax and semantics 部分提供了以下更多示例:

# Handle a matched regex
if (match := pattern.search(data)) is not None:
    # Do something with match

# A loop that can't be trivially rewritten using 2-arg iter()
while chunk := file.read(8192):
   process(chunk)

# Reuse a value that's expensive to compute
[y := f(x), y**2, y**3]

# Share a subexpression between a comprehension filter clause and its output
filtered_data = [y for x in data if (y := f(x)) is not None]

1
q = request.GET.get('q')
if q:
    print q
else:
    # q is None
    ...

无法同时进行赋值和条件判断...


显式优于隐式。可读性很重要。特殊情况并不足以打破规则。通过在Python中不写只有右括号的所有行,您可以节省大量垂直空间,那么为什么不追求清晰度呢?就我个人而言,我是从C开始入门的,现在已经写了12年的Python代码,我从来没有意识到这个功能缺失。你根本不需要这样做。 - Michael Dillon
@Michael:在几乎所有情况下,我都同意。只是在测试多个正则表达式的特定用例中,我觉得缺少了一些东西,就像在这个其他的SO问题中描述的那样:https://dev59.com/1XVD5IYBdhLWcg3wAGiD - Craig McQueen
@MichaelDillon 在你写 Python 的 12 年(如果你一直在坚持,现在已经是 24 年了),我想你肯定有过多次编写级联正则表达式匹配语句的经历,就像 Craig McQueen 引用的另一个问题中所提到的那样。当你有 10 个这样的语句时,你会如何编写它?嵌套并进一步缩进 10 次吗? - Don Hatch

0
如果在没有获取到值的情况下,get()方法抛出了异常,你可以这样做:
try:
   q = request.GET.get('q')
   print q
except :
   pass

0
一个可能的方法是这样做,无需在之前设置变量:
if (lambda x: globals().update({'q':x}) or True if x else False)(request.GET.get('q')):
    print q

这只是为了好玩 - 这种方法不应该被使用,因为它是丑陋的黑客方式,一眼很难理解,并且它会创建/覆盖全局变量(仅在条件满足时)


0
config_hash = {}
tmp_dir = ([config_hash[x]  for x in ["tmp_dir"] if config_hash.has_key(x)] or ["tmp"])[0]
print tmp_dir
config_hash["tmp_dir"] = "cat"
tmp_dir = ([config_hash[x]  for x in ["tmp_dir"] if config_hash.has_key(x)] or ["tmp"])[0]
print tmp_dir

-1

只需尝试:

print(request.GET.get('q', ''))

如果第一个参数不存在(请参见{{link1:dict.get}}),则基本上不会打印任何内容。


另一种解决方案是在Python中使用条件表达式:

<expression1> if <condition> else <expression2>

但你最终会重复两次变量,例如:

print(request.GET.get('q') if request.GET.get('q') else '')

关于循环中的变量赋值,请查看这里


-1

好的,这是一种方法

q = request.GET.get('q')
if q:
    print q

一种更简洁的方式(但由于打印无内容而不优越)是:
print request.GET.get('q') or '',

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接