Bir koşulda görevlendirme yapmak mümkün mü?
Örn.
if (a=some_func()):
# Use a
Yanıtlar:
Neden denemiyorsunuz?
>>> def some_func():
... return 2
...
>>> a = 2
>>> if (a = some_func()):
File "<stdin>", line 1
if (a = some_func()):
^
SyntaxError: invalid syntax
>>>
Yani hayır.
Güncelleme: Bu, Python 3.8'de mümkündür (farklı sözdizimi ile)
x = x + 1iken ek arama süresi gerektirir x += 1biraz daha hızlı, ama eminim o yaptı bile yapıyor gibi o kadar. :-)
Python 3.8, PEP572'yi getirecek
Özet
Bu, NAME: = ifade gösterimini kullanarak bir ifade içindeki değişkenlere atamanın bir yolunu oluşturmak için bir öneridir. Yeni bir istisna olan TargetScopeError eklenir ve değerlendirme sırasında bir değişiklik yapılır.
https://lwn.net/Articles/757713/
"PEP 572 karmaşası", yaşam için hayırsever diktatör (BDFL) Guido van Rossum tarafından yönetilen 2018 Python Dil Zirvesi oturumunun konusuydu. PEP 572, dile atama ifadeleri (veya "satır içi atamalar") eklemeyi amaçlamaktadır, ancak python-dev posta listesindeki çok sayıda büyük iş parçacığı üzerinde uzun bir tartışma gördü - python fikirleri üzerine birçok turdan sonra bile. Bu konular genellikle tartışmalıydı ve birçoğunun muhtemelen onları ayarladığı noktaya kadar hacimliydi. Zirvede Van Rossum, kabul etmeye meyilli gibi göründüğü özellik önerisinin bir özetini verdi, ancak gelecekte bu tür bir iplik patlamasından nasıl kaçınılacağını tartışmak istedi.
https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library
Python standart kitaplığından örnekler
site.py env_base sadece bu satırlarda kullanılır ve if atamasını bloğun "başlığı" olarak taşır.
Akım:
env_base = os.environ.get("PYTHONUSERBASE", None) if env_base: return env_baseGelişmiş:
if env_base := os.environ.get("PYTHONUSERBASE", None): return env_base _pydecimal.pyİç içe geçmekten kaçının ve bir girinti seviyesini kaldırın.
Akım:
if self._is_special: ans = self._check_nans(context=context) if ans: return ansGelişmiş:
if self._is_special and (ans := self._check_nans(context=context)): return anscopy.py Kod daha düzenli görünüyor ve eğer birden çok iç içe geçmiş durumdan kaçının. (Bu örneğin kökeni için Ek A'ya bakın.)
Akım:
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)Gelişmiş:
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 yalnızca s + = tz için kullanılır, atamasını if içinde hareket ettirerek kapsamını gösterir.
Akım:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) tz = self._tzstr() if tz: s += tz return sGelişmiş:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) if tz := self._tzstr(): s += tz return ssysconfig.py while koşulunda fp.readline () öğesini çağırmak ve if satırlarında .match () öğesini çağırmak kodu olmadan daha kompakt hale getirir
anlaşılmasını zorlaştırıyor.
Akım:
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)] = 0Gelişmiş:
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)] = 0Liste anlamalarını basitleştirme Bir liste anlama, koşulu yakalayarak verimli bir şekilde eşleyebilir ve filtreleyebilir:
results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]Benzer şekilde, bir alt ifade, ilk kullanımda ona bir ad verilerek ana ifade içinde yeniden kullanılabilir:
stuff = [[y := f(x), x/y] for x in range(5)]Her iki durumda da y değişkeninin kapsama alanına bağlı olduğuna dikkat edin (yani sonuçlar veya malzemelerle aynı seviyede).
Koşul değerlerini yakalama Atama ifadeleri, if veya while ifadesinin başlığında iyi bir etki için kullanılabilir:
# 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)Özellikle while döngüsü ile bu, sonsuz bir döngü, bir atama ve bir koşula sahip olma ihtiyacını ortadan kaldırabilir. Ayrıca, koşulu olarak basitçe bir işlev çağrısı kullanan bir döngü ile bunu koşulu olarak kullanan ancak aynı zamanda gerçek değeri kullanan bir döngü arasında pürüzsüz bir paralel oluşturur.
Fork Düşük seviyeli UNIX dünyasından bir örnek:
if pid := os.fork(): # Parent code else: # Child code
http://docs.python.org/tutorial/datastructures.html
Python'da, C'den farklı olarak, ifadelerin içinde atama yapılamayacağını unutmayın. C programcıları bundan şikayet edebilir, ancak C programlarında karşılaşılan ortak bir sorun sınıfından kaçınır: == amaçlandığında bir ifadeye = yazmak.
ayrıca bakınız:
http://effbot.org/pyfaq/why-can-ti-use-an-assignment-in-an-expression.htm
if (foo = 'bar')kişinin değerini test etmek isterken bu hatayı yaptığını gördüm foo.
=
Hayır, BDFL bu özelliği beğenmedi.
Guido van Rossum, oturduğum yerden, "Yaşam İçin Hayırsever Diktatör", Python'u olabildiğince basit tutmak için çok mücadele etti. Verdiği kararların bazılarıyla tartışabiliriz - Ben onun "Hayır" demesini tercih ederdim Ancak Python'u tasarlayan bir komitenin olmadığı gerçeği, bunun yerine büyük ölçüde liyakate dayalı, bir tasarımcının duyarlılıklarını filtreleyen güvenilir bir "danışma kurulu" olması, harika bir dil, IMHO üretti.
if letbir if elif zincirim olduğunda, pas gibi bir şeye sahip olmayı gerçekten özlüyorum , ancak her durumda koşulun değerini saklamam ve kullanmam gerekiyor.
Bu eski tarifime göre doğrudan değil - ama tarifin dediği gibi semantik eşdeğeri oluşturmak kolaydır, örneğin doğrudan C kodlu bir referans algoritmasından transliterasyon yapmanız gerekiyorsa (daha deyimsel Python'a yeniden düzenleme yapmadan önce tabii ki; -). Yani:
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
Özel durumunuz için çok deyimsel bir Pythonic formu olan BTW, yanlış bir değer döndürdüğünde tam olarak hangi yanlış değerin dönebileceğini biliyorsanız somefunc(örneğin 0),
for a in iter(somefunc, 0):
# use a
yani bu özel durumda yeniden düzenleme oldukça kolay olacaktır ;-).
Dönüş olabilsem herhangi falsish değerin tür (0, None, '', ...), bir ihtimal:
import itertools
for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
# use a
ancak basit bir özel oluşturucu tercih edebilirsiniz:
def getwhile(func, *a, **k):
while True:
x = func(*a, **k)
if not x: break
yield x
for a in getwhile(somefunc):
# use a
Evet, ancak yalnızca Python 3.8 ve sonrasında.
PEP 572, Atama İfadeleri önerir ve zaten kabul edilmiştir.
Aktaran dizimi ve semantik PEP parçası:
# 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]
Özel durumunuzda yazabileceksiniz
if a := some_func():
# Use a
Hayır. Python'da atama bir ifade değil, bir ifadedir.
Sayesinde Python 3.8 yeni özellik onu kullanmıyor olsa, bu sürümden böyle bir şey yapmak mümkün olacaktır =fakat atama operatörü Ada benzeri :=. Dokümanlardan örnek:
# Handle a matched regex
if (match := pattern.search(data)) is not None:
# Do something with match
Atamayı sizin yerinize yapacak bir işlev tanımlayabilirsiniz:
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)
Koşullarda atamaların yasa dışı olmasının nedenlerinden biri, hata yapmanın ve Doğru veya Yanlış atamanın daha kolay olmasıdır:
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
Python 3'te True ve False anahtar kelimelerdir, bu yüzden artık risk yok.
== Trueyine de doğru tarafa geçtiğinden eminim .
Gayri resmi olarak deniz aygırı operatörü olarak da bilinen atama operatörü, 28 Şubat 2018'de PEP572'de oluşturuldu .
Eksiksizlik adına, 3.7 ile 3.8 arasındaki farkları karşılaştırabilmeniz için ilgili bölümleri yayınlayacağım:
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)*