Perhatikan kode python2 berikut
In [5]: points = [ (1,2), (2,3)]
In [6]: min(points, key=lambda (x, y): (x*x + y*y))
Out[6]: (1, 2)
Ini tidak didukung di python3 dan saya harus melakukan hal berikut:
>>> min(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
(1, 2)
Ini sangat jelek. Jika lambda adalah sebuah fungsi, saya bisa melakukannya
def some_name_to_think_of(p):
x, y = p
return x*x + y*y
Menghapus fitur ini di python3 memaksa kode untuk melakukan cara yang buruk (dengan indeks ajaib) atau membuat fungsi yang tidak perlu (Bagian yang paling mengganggu adalah memikirkan nama yang baik untuk fungsi yang tidak perlu ini)
Saya pikir fitur tersebut harus ditambahkan kembali setidaknya ke lambda saja. Apakah ada alternatif yang bagus?
Pembaruan: Saya menggunakan pembantu berikut untuk memperluas ide dalam jawaban
def star(f):
return lambda args: f(*args)
min(points, key=star(lambda x,y: (x*x + y*y))
Pembaruan2: Versi yang lebih bersih untukstar
import functools
def star(f):
@functools.wraps(f):
def f_inner(args):
return f(*args)
return f_inner
python
python-3.x
balki
sumber
sumber
lambda
dihapus dari bahasa seluruhnya daripada membalikkan perubahan yang membuatnya lebih sulit untuk digunakan, tetapi Anda dapat mencoba memposting di python-ideas jika Anda ingin mengungkapkan keinginan untuk melihat fitur ditambahkan kembali.lambda
dengan semangat yang sama seperti yang dia lawanmap
,reduce
danfilter
.lambda
dijadwalkan untuk dihapus di py3k karena pada dasarnya ini adalah kerusakan pada bahasa. Tapi tidak ada yang bisa menyetujui alternatif yang tepat untuk mendefinisikan fungsi anonim, jadi akhirnya Guido angkat tangan karena kalah dan hanya itu.map
danfilter
paling baik diganti dengan pemahaman, saya sukareduce
)Jawaban:
Tidak, tidak ada cara lain. Anda menutupi semuanya. Cara yang harus dilakukan adalah mengangkat masalah ini di milis Ide Python , tetapi bersiaplah untuk banyak berdebat di sana untuk mendapatkan daya tarik.
Sebenarnya, hanya untuk tidak mengatakan "tidak ada jalan keluar", cara ketiga adalah dengan menerapkan satu tingkat panggilan lambda lagi hanya untuk membuka parameter - tetapi itu akan menjadi lebih tidak efisien dan lebih sulit untuk dibaca daripada dua saran Anda:
min(points, key=lambda p: (lambda x,y: (x*x + y*y))(*p))
perbarui Python 3.8
Saat ini, Python 3.8 alpha1 tersedia, dan ekspresi tugas PEP 572- diimplementasikan.
Jadi, jika seseorang menggunakan trik untuk mengeksekusi beberapa ekspresi di dalam lambda - saya biasanya melakukannya dengan membuat tupel dan hanya mengembalikan komponen terakhirnya, itu mungkin untuk dilakukan:
>>> a = lambda p:(x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1] >>> a((3,4)) 25
Perlu diingat bahwa kode semacam ini jarang lebih mudah dibaca atau praktis daripada memiliki fungsi penuh. Namun, ada kemungkinan penggunaan - jika ada berbagai satu-liner yang akan beroperasi pada ini
point
, mungkin ada baiknya untuk memiliki nametuple, dan menggunakan ekspresi assignment untuk secara efektif "mentransmisikan" urutan yang masuk ke namaiuple:>>> from collections import namedtuple >>> point = namedtuple("point", "x y") >>> b = lambda s: (p:=point(*s), p.x ** 2 + p.y ** 2)[-1]
sumber
def
yang disebutkan dalam pertanyaan di bawah nmesome_name_to_think-of
.key = lambda p: (x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
Menurut http://www.python.org/dev/peps/pep-3113/ tuple unpacking sudah tidak ada, dan
2to3
akan menerjemahkannya seperti ini:Yang sangat mirip dengan penerapan Anda.
sumber
Saya tidak tahu alternatif umum yang baik untuk perilaku membongkar argumen Python 2. Berikut beberapa saran yang mungkin berguna dalam beberapa kasus:
jika Anda tidak dapat memikirkan sebuah nama; gunakan nama parameter kata kunci:
def key(p): # more specific name would be better x, y = p return x**2 + y**3 result = min(points, key=key)
Anda dapat melihat apakah a
namedtuple
membuat kode Anda lebih mudah dibaca jika daftar digunakan di banyak tempat:from collections import namedtuple from itertools import starmap points = [ (1,2), (2,3)] Point = namedtuple('Point', 'x y') points = list(starmap(Point, points)) result = min(points, key=lambda p: p.x**2 + p.y**3)
sumber
lambda (x, y):
danlambda x, y:
tidak jelas pada pandangan pertama.Sementara argumen penghancur telah dihapus dengan Python3, itu tidak dihapus dari pemahaman. Dimungkinkan untuk menyalahgunakannya untuk mendapatkan perilaku yang serupa dengan Python 3. Intinya, kami memanfaatkan fakta bahwa rutinitas bersama memungkinkan kita untuk mengubah fungsi ke luar, dan hasil bukanlah pernyataan, dan karenanya diizinkan dalam lambda.
Sebagai contoh:
points = [(1,2), (2,3)] print(min(points, key=lambda y: next(x*x + y*y for x,y in (lambda a: (yield a))(y))))
Dibandingkan dengan jawaban yang diterima untuk menggunakan pembungkus, solusi ini dapat sepenuhnya merusak argumen sementara pembungkus hanya merusak tingkat pertama. Itu adalah,
values = [(('A',1),'a'), (('B',0),'b')] print(min(values, key=lambda y: next(b for (a,b),c in (lambda x: (yield x))(y))))
Dibandingkan dengan
values = [(('A',1),'a'), (('B',0),'b')] print(min(points, key=lambda p: (lambda a,b: (lambda x,y: (y))(*a))(*p)))
Alternatifnya juga bisa dilakukan
values = [(('A',1),'a'), (('B',0),'b')] print(min(points, key=lambda y: next(b for (a,b),c in [y])))
Atau sedikit lebih baik
print(min(values, key=lambda y: next(b for ((a,b),c) in (y,))))
Ini hanya untuk memberi kesan bahwa hal itu dapat dilakukan, dan tidak boleh dianggap sebagai rekomendasi.
sumber
Menurut saya sintaks yang lebih baik adalah
x * x + y * y let x, y = point
,let
kata kunci harus dipilih dengan lebih cermat.Lambda ganda adalah versi terdekat.
lambda point: (lambda x, y: x * x + y * y)(*point)
Fungsi pembantu tingkat tinggi akan berguna jika kita memberinya nama yang tepat.
def destruct_tuple(f): return lambda args: f(*args) destruct_tuple(lambda x, y: x * x + y * y)
sumber
Berdasarkan saran Cuadue dan komentar Anda tentang membongkar masih ada dalam pemahaman, Anda dapat menggunakan, menggunakan
numpy.argmin
:result = points[numpy.argmin(x*x + y*y for x, y in points)]
sumber
Pilihan lainnya adalah menuliskannya ke generator yang menghasilkan tupel di mana kuncinya adalah elemen pertama. Tupel dibandingkan mulai dari awal hingga akhir sehingga tupel dengan elemen pertama terkecil dikembalikan. Anda kemudian dapat mengindeks hasil untuk mendapatkan nilainya.
min((x * x + y * y, (x, y)) for x, y in points)[1]
sumber
Pertimbangkan apakah Anda perlu membongkar tupel terlebih dahulu:
min(points, key=lambda p: sum(x**2 for x in p))
atau apakah Anda perlu memberikan nama eksplisit saat membongkar:
min(points, key=lambda p: abs(complex(*p))
sumber