Có thể có sự phân công trong một điều kiện?
Đối với người yêu cũ.
if (a=some_func()):
# Use a
Câu trả lời:
Tại sao không thử nó ra?
>>> def some_func():
... return 2
...
>>> a = 2
>>> if (a = some_func()):
File "<stdin>", line 1
if (a = some_func()):
^
SyntaxError: invalid syntax
>>>
Vì vậy, không.
Cập nhật: Điều này có thể (với cú pháp khác) trong Python 3.8
x = x + 1yêu cầu thời gian tra cứu bổ sung trong khi x += 1nhanh hơn một chút, nhưng tôi chắc chắn rằng anh ấy thậm chí không thích làm điều đó nhiều. :-)
Python 3.8 sẽ mang đến PEP572
Tóm tắt
Đây là một đề xuất để tạo một cách để gán cho các biến trong một biểu thức bằng cách sử dụng ký hiệu NAME: = expr. Một ngoại lệ mới, TargetScopeError được thêm vào và có một thay đổi đối với thứ tự đánh giá.
https://lwn.net/Articles/757713/
"Vụ lộn xộn PEP 572" là chủ đề của phiên họp Hội nghị thượng đỉnh về ngôn ngữ Python năm 2018 do nhà độc tài nhân từ vì sự sống (BDFL) Guido van Rossum dẫn đầu. PEP 572 tìm cách thêm biểu thức gán (hoặc "phép gán nội tuyến") vào ngôn ngữ, nhưng nó đã chứng kiến một cuộc thảo luận kéo dài về nhiều chủ đề lớn trong danh sách gửi thư python-dev — ngay cả sau nhiều vòng về ý tưởng python. Những chủ đề đó thường gây tranh cãi và rõ ràng là đồ sộ đến mức nhiều người có thể chỉ chỉnh chúng ra. Tại hội nghị thượng đỉnh, Van Rossum đã đưa ra một cái nhìn tổng quan về đề xuất tính năng mà ông có vẻ có xu hướng chấp nhận, nhưng ông cũng muốn thảo luận về cách tránh sự bùng nổ chủ đề này trong tương lai.
https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library
Ví dụ từ thư viện chuẩn Python
site.py env_base chỉ được sử dụng trên những dòng này, việc gán nó vào if sẽ di chuyển nó làm "tiêu đề" của khối.
Hiện hành:
env_base = os.environ.get("PYTHONUSERBASE", None) if env_base: return env_baseCải thiện:
if env_base := os.environ.get("PYTHONUSERBASE", None): return env_base _pydecimal.pyTránh lồng ghép nếu và loại bỏ một mức thụt lề.
Hiện hành:
if self._is_special: ans = self._check_nans(context=context) if ans: return ansCải thiện:
if self._is_special and (ans := self._check_nans(context=context)): return anscopy.py Mã trông đều đặn hơn và tránh nhiều nếu. (Xem Phụ lục A về nguồn gốc của ví dụ này.)
Hiện hành:
reductor = dispatch_table.get(cls) if reductor: rv = reductor(x) else: reductor = getattr(x, "__reduce_ex__", None) if reductor: rv = reductor(4) else: reductor = getattr(x, "__reduce__", None) if reductor: rv = reductor() else: raise Error( "un(deep)copyable object of type %s" % cls)Cải thiện:
if reductor := dispatch_table.get(cls): rv = reductor(x) elif reductor := getattr(x, "__reduce_ex__", None): rv = reductor(4) elif reductor := getattr(x, "__reduce__", None): rv = reductor() else: raise Error("un(deep)copyable object of type %s" % cls) datetime.pytz chỉ được sử dụng cho s + = tz, việc di chuyển phép gán của nó vào bên trong if giúp hiển thị phạm vi của nó.
Hiện hành:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) tz = self._tzstr() if tz: s += tz return sCải thiện:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) if tz := self._tzstr(): s += tz return ssysconfig.py Gọi fp.readline () trong điều kiện while và gọi .match () trên các dòng if làm cho mã gọn gàng hơn mà không cần
làm cho nó khó hiểu hơn.
Hiện hành:
while True: line = fp.readline() if not line: break m = define_rx.match(line) if m: n, v = m.group(1, 2) try: v = int(v) except ValueError: pass vars[n] = v else: m = undef_rx.match(line) if m: vars[m.group(1)] = 0Cải thiện:
while line := fp.readline(): if m := define_rx.match(line): n, v = m.group(1, 2) try: v = int(v) except ValueError: pass vars[n] = v elif m := undef_rx.match(line): vars[m.group(1)] = 0Đơn giản hóa việc hiểu danh sách Việc hiểu danh sách có thể lập bản đồ và lọc hiệu quả bằng cách nắm bắt điều kiện:
results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]Tương tự, một biểu thức con có thể được sử dụng lại trong biểu thức chính, bằng cách đặt tên cho nó trong lần sử dụng đầu tiên:
stuff = [[y := f(x), x/y] for x in range(5)]Lưu ý rằng trong cả hai trường hợp, biến y bị ràng buộc trong phạm vi chứa (nghĩa là ở cùng cấp với kết quả hoặc nội dung).
Thu thập giá trị điều kiện Biểu thức gán có thể được sử dụng để tạo hiệu quả tốt trong tiêu đề của câu lệnh if hoặc while:
# Loop-and-a-half while (command := input("> ")) != "quit": print("You entered:", command) # Capturing regular expression match objects # See, for instance, Lib/pydoc.py, which uses a multiline spelling # of this effect if match := re.search(pat, text): print("Found:", match.group(0)) # The same syntax chains nicely into 'elif' statements, unlike the # equivalent using assignment statements. elif match := re.search(otherpat, text): print("Alternate found:", match.group(0)) elif match := re.search(third, text): print("Fallback found:", match.group(0)) # Reading socket data until an empty string is returned while data := sock.recv(8192): print("Received data:", data)Đặc biệt với vòng lặp while, điều này có thể loại bỏ sự cần thiết phải có một vòng lặp vô hạn, một phép gán và một điều kiện. Nó cũng tạo ra một sự song song mượt mà giữa một vòng lặp chỉ sử dụng một lệnh gọi hàm làm điều kiện của nó và một vòng lặp sử dụng điều kiện đó làm điều kiện nhưng cũng sử dụng giá trị thực tế.
Fork Một ví dụ từ thế giới UNIX cấp thấp:
if pid := os.fork(): # Parent code else: # Child code
http://docs.python.org/tutorial/datastructures.html
Lưu ý rằng trong Python, không giống như C, phép gán không thể xảy ra bên trong các biểu thức. Các lập trình viên C có thể càu nhàu về điều này, nhưng nó tránh được một lớp vấn đề phổ biến gặp phải trong các chương trình C: gõ = trong một biểu thức khi có ý định dùng ==.
cũng thấy:
http://effbot.org/pyfaq/why-can-ti-use-an-assignment-in-an-expression.htm
if (foo = 'bar')trong khi định kiểm tra giá trị của foo.
=
Không, BDFL không thích tính năng đó.
Từ chỗ tôi ngồi, Guido van Rossum, "Nhà độc tài nhân từ cho cuộc sống", đã chiến đấu hết mình để giữ cho Python đơn giản nhất có thể. Chúng ta có thể phân minh với một số quyết định của anh ấy - Tôi thích anh ấy nói 'Không Nhưng thực tế là không có một ủy ban nào thiết kế Python, mà thay vào đó là một "ban cố vấn" đáng tin cậy, phần lớn dựa trên thành tích, lọc qua sự nhạy cảm của một nhà thiết kế, đã tạo ra một ngôn ngữ tuyệt vời, IMHO.
if letkhi tôi có chuỗi if elif, nhưng cần phải lưu trữ và sử dụng giá trị của điều kiện trong từng trường hợp.
Không trực tiếp, theo công thức cũ này của tôi - nhưng như công thức cho biết rất dễ dàng để xây dựng ngữ nghĩa tương đương, ví dụ nếu bạn cần chuyển ngữ trực tiếp từ thuật toán tham chiếu được mã hóa C (tất nhiên là trước khi cấu trúc lại thành Python dễ hiểu hơn; -). I E:
class DataHolder(object):
def __init__(self, value=None): self.value = value
def set(self, value): self.value = value; return value
def get(self): return self.value
data = DataHolder()
while data.set(somefunc()):
a = data.get()
# use a
BTW, một dạng Pythonic rất thành ngữ cho trường hợp cụ thể của bạn, nếu bạn biết chính xác giá trị sai somefunccó thể trả về khi nó trả về giá trị giả (ví dụ 0), là
for a in iter(somefunc, 0):
# use a
vì vậy trong trường hợp cụ thể này, việc tái cấu trúc sẽ khá dễ dàng ;-).
Nếu sự trở lại có thể là bất kỳ loại giá trị falsish (0, None, '', ...), một trong những khả năng là:
import itertools
for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
# use a
nhưng bạn có thể thích một trình tạo tùy chỉnh đơn giản:
def getwhile(func, *a, **k):
while True:
x = func(*a, **k)
if not x: break
yield x
for a in getwhile(somefunc):
# use a
Có, nhưng chỉ từ Python 3.8 trở đi.
PEP 572 đề xuất Biểu thức Bài tập và đã được chấp nhận.
Trích dẫn phần Cú pháp và ngữ nghĩa của PEP:
# 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]
Trong trường hợp cụ thể của bạn, bạn sẽ có thể viết
if a := some_func():
# Use a
Không. Phép gán trong Python là một câu lệnh, không phải một biểu thức.
Nhờ tính năng mới của Python 3.8, có thể thực hiện điều đó từ phiên bản này, mặc dù không sử dụng =nhưng toán tử gán giống Ada :=. Ví dụ từ tài liệu:
# Handle a matched regex
if (match := pattern.search(data)) is not None:
# Do something with match
Bạn có thể xác định một hàm để thực hiện việc gán cho bạn:
def assign(name, value):
import inspect
frame = inspect.currentframe()
try:
locals_ = frame.f_back.f_locals
finally:
del frame
locals_[name] = value
return value
if assign('test', 0):
print("first", test)
elif assign('xyz', 123):
print("second", xyz)
Một trong những lý do tại sao việc chuyển nhượng là bất hợp pháp trong các điều kiện là bạn dễ mắc lỗi và gán Đúng hoặc Sai:
some_variable = 5
# This does not work
# if True = some_variable:
# do_something()
# This only works in Python 2.x
True = some_variable
print True # returns 5
Trong Python 3 True và False là các từ khóa, vì vậy không còn rủi ro nữa.
== Trueở bên phải.
Toán tử gán - còn được gọi là toán tử hải mã - được tạo vào ngày 28 tháng 2 năm 2018 trong PEP572 .
Để đầy đủ, tôi sẽ đăng các phần liên quan để bạn có thể so sánh sự khác biệt giữa 3.7 và 3.8:
3.7
---
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
test: or_test ['if' or_test 'else' test] | lambdef
test_nocond: or_test | lambdef_nocond
lambdef: 'lambda' [varargslist] ':' test
lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
or_test: and_test ('or' and_test)*
and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison
comparison: expr (comp_op expr)*
3.8
---
if_stmt: 'if' namedexpr_test ':' suite ('elif' namedexpr_test ':' suite)* ['else' ':' suite]
namedexpr_test: test [':=' test] <---- WALRUS OPERATOR!!!
test: or_test ['if' or_test 'else' test] | lambdef
or_test: and_test ('or' and_test)*
and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison
comparison: expr (comp_op expr)*