Apakah mungkin memiliki penugasan dalam kondisi tertentu?
Misalnya.
if (a=some_func()):
# Use a
Apakah mungkin memiliki penugasan dalam kondisi tertentu?
Misalnya.
if (a=some_func()):
# Use a
Jawaban:
Mengapa tidak mencobanya?
>>> def some_func():
... return 2
...
>>> a = 2
>>> if (a = some_func()):
File "<stdin>", line 1
if (a = some_func()):
^
SyntaxError: invalid syntax
>>>
Jadi tidak.
Pembaruan: Ini dimungkinkan (dengan sintaks berbeda) dengan Python 3.8
x = x + 1membutuhkan waktu pencarian tambahan sementara x += 1itu agak lebih cepat, tapi saya yakin dia bahkan tidak suka melakukan itu . :-)
Python 3.8 akan membawa PEP572
Abstrak
Ini adalah proposal untuk membuat cara untuk menetapkan variabel dalam ekspresi menggunakan notasi NAME: = expr. Pengecualian baru, TargetScopeError ditambahkan, dan ada satu perubahan pada urutan evaluasi.
https://lwn.net/Articles/757713/
"Kekacauan PEP 572" adalah topik sesi KTT Bahasa Python 2018 yang dipimpin oleh diktator seumur hidup yang baik hati (BDFL) Guido van Rossum. PEP 572 berupaya untuk menambahkan ekspresi tugas (atau "tugas sebaris") ke bahasa, tetapi telah terjadi diskusi yang berkepanjangan atas beberapa utas besar di milis python-dev — bahkan setelah beberapa putaran pada ide-python. Utas-utas itu sering kali menimbulkan perdebatan dan jelas-jelas sangat banyak sampai-sampai banyak yang mungkin baru saja mengabaikannya. Di KTT tersebut, Van Rossum memberikan gambaran umum tentang proposal fitur, yang tampaknya cenderung dia terima, tetapi dia juga ingin mendiskusikan cara menghindari ledakan benang semacam ini di masa mendatang.
https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library
Contoh dari pustaka standar Python
site.py env_base hanya digunakan pada baris-baris ini, menempatkan tugasnya pada if memindahkannya sebagai "tajuk" dari blok tersebut.
Arus:
env_base = os.environ.get("PYTHONUSERBASE", None) if env_base: return env_basePeningkatan:
if env_base := os.environ.get("PYTHONUSERBASE", None): return env_base _pydecimal.pyHindari bersarang if dan hapus satu tingkat indentasi.
Arus:
if self._is_special: ans = self._check_nans(context=context) if ans: return ansPeningkatan:
if self._is_special and (ans := self._check_nans(context=context)): return anscopy.py Kode terlihat lebih teratur dan menghindari multiple nested if. (Lihat Lampiran A untuk asal contoh ini.)
Arus:
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)Peningkatan:
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 hanya digunakan untuk s + = tz, memindahkan tugasnya ke dalam if membantu untuk menunjukkan ruang lingkupnya.
Arus:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) tz = self._tzstr() if tz: s += tz return sPeningkatan:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) if tz := self._tzstr(): s += tz return ssysconfig.py Memanggil fp.readline () dalam kondisi while dan memanggil .match () pada baris if membuat kode lebih kompak tanpa
membuatnya lebih sulit untuk dipahami.
Arus:
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)] = 0Peningkatan:
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)] = 0Menyederhanakan pemahaman daftar Pemahaman daftar dapat memetakan dan memfilter secara efisien dengan menangkap kondisi:
results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]Demikian pula, subekspresi dapat digunakan kembali dalam ekspresi utama, dengan memberinya nama pada penggunaan pertama:
stuff = [[y := f(x), x/y] for x in range(5)]Perhatikan bahwa dalam kedua kasus variabel y terikat dalam ruang lingkup (yaitu pada tingkat yang sama sebagai hasil atau barang).
Menangkap nilai kondisi Ekspresi tugas dapat digunakan untuk memberikan efek yang baik di header pernyataan if atau 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)Khususnya dengan while loop, ini bisa menghilangkan kebutuhan untuk memiliki loop tak terbatas, tugas, dan kondisi. Ini juga membuat paralel mulus antara loop yang hanya menggunakan panggilan fungsi sebagai kondisinya, dan yang menggunakannya sebagai kondisinya tetapi juga menggunakan nilai sebenarnya.
Garpu Contoh dari dunia UNIX level rendah:
if pid := os.fork(): # Parent code else: # Child code
http://docs.python.org/tutorial/datastructures.html
Perhatikan bahwa di Python, tidak seperti C, penugasan tidak dapat terjadi di dalam ekspresi. Pemrogram C mungkin mengeluh tentang ini, tetapi ini menghindari kelas umum masalah yang dihadapi dalam program C: mengetik = dalam ekspresi saat == dimaksudkan.
lihat juga:
http://effbot.org/pyfaq/why-can-ti-use-an-assignment-in-an-expression.htm
if (foo = 'bar')saat bermaksud menguji nilai foo.
=
Tidak, BDFL tidak menyukai fitur itu.
Dari tempat saya duduk, Guido van Rossum, "Diktator Baik untuk Kehidupan”, telah berjuang keras untuk menjaga agar Python tetap sesederhana mungkin. Kita dapat berdalih dengan beberapa keputusan yang dia buat - saya lebih suka dia berkata 'Tidak 'lebih sering. Tetapi fakta bahwa belum ada komite yang merancang Python, melainkan "dewan penasihat" tepercaya, yang sebagian besar didasarkan pada prestasi, menyaring melalui kepekaan seorang desainer, telah menghasilkan bahasa yang sangat bagus, IMHO.
if letketika saya memiliki rantai if elif, tetapi perlu menyimpan dan menggunakan nilai kondisi di setiap kasus.
Tidak secara langsung, sesuai resep lama saya ini - tetapi seperti yang dikatakan resep itu mudah untuk membangun padanan semantik, misalnya jika Anda perlu mentransliterasi langsung dari algoritme referensi berkode-C (sebelum melakukan refactoring ke Python yang lebih idiomatik, tentu saja; -). Yaitu:
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, bentuk Pythonic yang sangat idiomatik untuk kasus spesifik Anda, jika Anda tahu persis apa nilai palsu yang somefuncdapat dikembalikan ketika mengembalikan nilai yang salah (misalnya 0), adalah
for a in iter(somefunc, 0):
# use a
jadi dalam kasus khusus ini refactoring akan sangat mudah ;-).
Jika pengembalian bisa menjadi salah jenis nilai falsish (0, None, '', ...), salah satu kemungkinan adalah:
import itertools
for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
# use a
tetapi Anda mungkin lebih suka generator khusus sederhana:
def getwhile(func, *a, **k):
while True:
x = func(*a, **k)
if not x: break
yield x
for a in getwhile(somefunc):
# use a
Ya, tetapi hanya dari Python 3.8 dan seterusnya.
PEP 572 mengusulkan Ekspresi Tugas dan telah diterima.
Mengutip bagian Sintaks dan semantik dari 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]
Dalam kasus khusus Anda, Anda akan bisa menulis
if a := some_func():
# Use a
Tidak. Tugas dengan Python adalah pernyataan, bukan ekspresi.
Berkat fitur baru Python 3.8, Anda dapat melakukan hal seperti itu dari versi ini, meskipun tidak menggunakan =tetapi operator penugasan seperti Ada :=. Contoh dari dokumen:
# Handle a matched regex
if (match := pattern.search(data)) is not None:
# Do something with match
Anda dapat menentukan fungsi untuk melakukan penugasan untuk Anda:
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)
Salah satu alasan mengapa penetapan ilegal dalam kondisi adalah karena lebih mudah membuat kesalahan dan menetapkan Benar atau Salah:
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
Di Python 3 True dan False adalah kata kunci, jadi tidak ada resiko lagi.
== Truedi sisi kanan.
Operator penugasan - juga dikenal secara informal sebagai operator walrus - dibuat pada 28-Feb-2018 di PEP572 .
Demi kelengkapan, saya akan memposting bagian-bagian yang relevan sehingga Anda dapat membandingkan perbedaan antara 3.7 dan 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)*