map()
ওভার তালিকা বোঝার বা তদ্বিপরীত ব্যবহার পছন্দ করার কোনও কারণ আছে কি ? এগুলির উভয়ই কি সাধারণভাবে বেশি দক্ষ বা অন্যের চেয়ে সাধারণভাবে বেশি পাইথোনিক হিসাবে বিবেচিত হয়?
map()
ওভার তালিকা বোঝার বা তদ্বিপরীত ব্যবহার পছন্দ করার কোনও কারণ আছে কি ? এগুলির উভয়ই কি সাধারণভাবে বেশি দক্ষ বা অন্যের চেয়ে সাধারণভাবে বেশি পাইথোনিক হিসাবে বিবেচিত হয়?
উত্তর:
map
কিছু ক্ষেত্রে মাইক্রোস্কোপিকভাবে দ্রুততর হতে পারে (যখন আপনি ল্যাম্বডাটি উদ্দেশ্যে তৈরি করছেন না, তবে মানচিত্র এবং একটি লিস্টকম্পে একই ফাংশন ব্যবহার করছেন)। তালিকার বোধগম্যতা অন্যান্য ক্ষেত্রে দ্রুত হতে পারে এবং বেশিরভাগ (সমস্ত নয়) পাইথনিস্টগুলি এগুলিকে আরও প্রত্যক্ষ এবং পরিষ্কার বলে বিবেচনা করে।
ঠিক একই ফাংশনটি ব্যবহার করার সময় মানচিত্রের ক্ষুদ্র গতির সুবিধার একটি উদাহরণ:
$ python -mtimeit -s'xs=range(10)' 'map(hex, xs)'
100000 loops, best of 3: 4.86 usec per loop
$ python -mtimeit -s'xs=range(10)' '[hex(x) for x in xs]'
100000 loops, best of 3: 5.58 usec per loop
যখন মানচিত্রে ল্যাম্বডা দরকার হয় তখন পারফরম্যান্স তুলনা কীভাবে সম্পূর্ণ বিপরীত হয়:
$ python -mtimeit -s'xs=range(10)' 'map(lambda x: x+2, xs)'
100000 loops, best of 3: 4.24 usec per loop
$ python -mtimeit -s'xs=range(10)' '[x+2 for x in xs]'
100000 loops, best of 3: 2.32 usec per loop
map(operator.attrgetter('foo'), objs)
এর চেয়ে পড়া সহজ [o.foo for o in objs]
?!
o
এখানে যেমন অপ্রয়োজনীয় নাম প্রবর্তন না করা পছন্দ করি এবং কেন আপনার উদাহরণগুলি দেখায়।
str()
উদাহরণ রয়েছে, যদিও তার উদাহরণ রয়েছে।
মামলা
map
তবে এটি ব্যবহার করা প্রায়শই যুক্তিসঙ্গত , যদিও এটি 'অপার্থিব' হিসাবে বিবেচিত হয়। উদাহরণস্বরূপ, map(sum, myLists)
তুলনায় আরও মার্জিত / নিবিড় [sum(x) for x in myLists]
। ডামি ভেরিয়েবল (যেমন sum(x) for x...
বা sum(_) for _...
বা sum(readableName) for readableName...
) তৈরি করতে না পারা আপনি কমনীয়তা অর্জন করেছেন যা কেবল পুনরাবৃত্তি করতে হবে। একই যুক্তি মডিউলটির জন্য filter
এবং reduce
কিছু হোল্ড করে itertools
: আপনার যদি ইতিমধ্যে কোনও কার্যকারিতা সহজ হয় তবে আপনি এগিয়ে যেতে পারেন এবং কিছু কার্যকরী প্রোগ্রামিং করতে পারেন। এটি কিছু পরিস্থিতিতে পঠনযোগ্যতা অর্জন করে এবং অন্যদের মধ্যে এটি হারাতে পারে (যেমন নভিশ প্রোগ্রামার, একাধিক যুক্তি) ... তবে আপনার কোডের পঠনযোগ্যতা যাইহোক আপনার মন্তব্যের উপর নির্ভর করে।map
ফাংশনাল প্রোগ্রামিং করার সময় ফাংশনটি খাঁটি বিমূর্ত ফাংশন হিসাবে ব্যবহার করতে চাইতে পারেন , যেখানে আপনি ম্যাপিং করছেন map
বা কারি করছেন map
, বা অন্যথায় map
কোনও ফাংশন হিসাবে কথা বলে উপকার পাবেন । উদাহরণস্বরূপ হাস্কেলের মধ্যে, কোনও ফান্টর ইন্টারফেস fmap
যেকোন ডেটা স্ট্রাকচারের উপরে ম্যাপিংকে জেনারেলাইজ করে। এটি অজগরটিতে খুব অস্বাভাবিক কারণ অজগর ব্যাকরণ আপনাকে পুনরাবৃত্তির বিষয়ে কথা বলতে জেনারেটর-স্টাইল ব্যবহার করতে বাধ্য করে; আপনি এটি সহজেই সাধারণ করতে পারবেন না can't (এটি কখনও কখনও ভাল এবং কখনও কখনও খারাপ হয়)) আপনি সম্ভবত বিরল অজগর উদাহরণ নিয়ে আসতে পারেন যেখানে map(f, *lists)
করণীয় যুক্তিযুক্ত। নিকটতম উদাহরণটি আমি সামনে আসতে পারি sumEach = partial(map,sum)
, এটি একটি ওয়ান-লাইনার যা মোটামুটি সমান:def sumEach(myLists):
return [sum(_) for _ in myLists]
for
লুপ ব্যবহার করুন : আপনি অবশ্যই একটি লুপ ব্যবহার করতে পারেন। ক্রিয়ামূলক-প্রোগ্রামিং দৃষ্টিকোণ থেকে মার্জিত না হলেও, কখনও কখনও অ-স্থানীয় ভেরিয়েবলগুলি অজগর হিসাবে প্রেরণামূলক প্রোগ্রামিং ভাষাগুলিতে কোড পরিষ্কার করে দেয়, কারণ মানুষ সেভাবে কোড পড়তে অভ্যস্ত। লুপগুলি এছাড়াও, সাধারণত, সবচেয়ে কার্যকর যখন আপনি কেবল কোনও জটিল ক্রিয়াকলাপ করছেন যা তালিকা-বোধগম্যতা এবং মানচিত্রের মতো তালিকা তৈরি করছে না তার জন্য অনুকূলিত করা হয়েছে (উদাহরণস্বরূপ সংক্ষেপণ, বা একটি গাছ তৈরি করা ইত্যাদি) - কমপক্ষে least মেমরির ক্ষেত্রে কার্যকর (সময়ের প্রয়োজনে অগত্যা নয়, যেখানে আমি দুর্লভ স্থিতিশীল ফ্যাক্টরটি আশা করতাম, কিছু বিরল রোগতাত্ত্বিক আবর্জনা-সংগ্রহ হিচকি বাদ দিয়ে)"Pythonism"
আমি "পাইথোনিক" শব্দটি অপছন্দ করি কারণ আমি পাই না যে পাইথোনিকটি আমার চোখে সর্বদা মার্জিত থাকে। তবুও, map
এবং filter
অন্যান্য অনুরূপ ফাংশন (খুব দরকারী itertools
মডিউলটির মতো) সম্ভবত শৈলীর দিক থেকে অযৌক্তিক হিসাবে বিবেচিত হয়।
আলস্য
দক্ষতার দিক থেকে, বেশিরভাগ কার্যকরী প্রোগ্রামিং কনস্ট্রাক্টের মতো, ম্যাপটি আলস্য হতে পারে এবং বাস্তবে অজগরটি অলস। তার মানে আপনি এটি করতে পারেন ( পাইথন 3 এ ) এবং আপনার কম্পিউটারের স্মৃতিশক্তি চলে না এবং আপনার সমস্ত সংরক্ষণ করা ডেটা হারাবে:
>>> map(str, range(10**100))
<map object at 0x2201d50>
একটি তালিকা বোঝার সাথে এটি করার চেষ্টা করুন:
>>> [str(n) for n in range(10**100)]
# DO NOT TRY THIS AT HOME OR YOU WILL BE SAD #
মনে রাখবেন যে তালিকা অনুধাবনগুলিও সহজাতভাবে অলস, তবে পাইথন সেগুলি অ-অলস হিসাবে প্রয়োগ করতে বেছে নিয়েছে । তবুও, পাইথন জেনারেটর এক্সপ্রেশন আকারে অলস তালিকা বোঝার জন্য সমর্থন করে:
>>> (str(n) for n in range(10**100))
<generator object <genexpr> at 0xacbdef>
আপনি মূলত [...]
সিনট্যাক্সটিকে লিস্টের কনস্ট্রাক্টরের মতো জেনারেটর এক্সপ্রেশন হিসাবে পাস হিসাবে ভাবতে পারেন list(x for x in range(5))
।
সংক্ষিপ্ত সংক্ষিপ্ত উদাহরণ
from operator import neg
print({x:x**2 for x in map(neg,range(5))})
print({x:x**2 for x in [-y for y in range(5)]})
print({x:x**2 for x in (-y for y in range(5))})
তালিকা বোধগম্য অলস, তাই আরও মেমরির প্রয়োজন হতে পারে (যদি না আপনি জেনারেটর বোঝাপড়া ব্যবহার করেন)। বর্গাকার বন্ধনীগুলি [...]
প্রায়শই জিনিসগুলিকে সুস্পষ্ট করে তোলে, বিশেষত যখন বন্ধনীগুলির জগাখিচুড়িতে। অন্যদিকে, কখনও কখনও আপনি টাইপ করার মতো ভার্বোজ হয়ে শেষ করেন [x for x in...
। যতক্ষণ আপনি আপনার পুনরাবৃত্তকারী ভেরিয়েবলগুলি সংক্ষিপ্ত রাখবেন ততক্ষণ আপনি নিজের কোডটি ইন্ডেন্ট না করলে তালিকা বোধগম্যতা সাধারণত পরিষ্কার হয়। তবে আপনি সর্বদা আপনার কোডটি প্রবেশ করতে পারেন।
print(
{x:x**2 for x in (-y for y in range(5))}
)
বা জিনিসগুলি ভেঙে দিন:
rangeNeg5 = (-y for y in range(5))
print(
{x:x**2 for x in rangeNeg5}
)
পাইথন 3 এর জন্য দক্ষতার তুলনা
map
এখন অলস:
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=map(f,xs)'
1000000 loops, best of 3: 0.336 usec per loop ^^^^^^^^^
অতএব আপনি যদি আপনার সমস্ত ডেটা ব্যবহার না করে থাকেন, বা আপনাকে কী পরিমাণ ডেটা প্রয়োজন তা সময়ের আগে জানা map
না গেলে পাইথন 3 (এবং পাইথন 2 বা পাইথন 3 তে জেনারেটর এক্সপ্রেশন) প্রয়োজনীয় মুহুর্ত পর্যন্ত তাদের মানগুলি গণনা করা এড়াতে পারে। সাধারণত এটি ব্যবহার থেকে কোনও ওভারহেড ছাড়িয়ে যায় map
। ক্ষয়ক্ষতিটি হ'ল এটি বেশিরভাগ কার্যকরী ভাষার বিপরীতে অজগরটিতে খুব সীমাবদ্ধ: আপনি কেবলমাত্র এই উপকারটি পাবেন যদি আপনি আপনার ডেটা বাম থেকে ডান "ক্রমে" অ্যাক্সেস করেন তবে পাইথন জেনারেটর এক্সপ্রেশনটি কেবলমাত্র আদেশটির মূল্যায়ন করা যেতে পারে x[0], x[1], x[2], ...
।
তবে আসুন আমরা বলি যে আমাদের একটি প্রাক-তৈরি ফাংশন রয়েছে যা f
আমরা চাই map
এবং আমরা map
সঙ্গে সঙ্গে মূল্যায়ন জোর করে অলসতা উপেক্ষা করি list(...)
। আমরা কিছু খুব আকর্ষণীয় ফলাফল পেয়েছি:
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=list(map(f,xs))'
10000 loops, best of 3: 165/124/135 usec per loop ^^^^^^^^^^^^^^^
for list(<map object>)
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=[f(x) for x in xs]'
10000 loops, best of 3: 181/118/123 usec per loop ^^^^^^^^^^^^^^^^^^
for list(<generator>), probably optimized
% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=list(f(x) for x in xs)'
1000 loops, best of 3: 215/150/150 usec per loop ^^^^^^^^^^^^^^^^^^^^^^
for list(<generator>)
ফলাফলগুলি এএএ / বিবিবি / সিসিসি আকারে রয়েছে যেখানে A একটি সার্কা -২০১০ এর সাথে একটি অজগর ৩.???, এবং বি এবং সি-এর একটি সার্কা -৩০ এএমডি ওয়ার্কস্টেশন দিয়ে অজগর ৩.২.১ সহ সঞ্চালিত হয়েছিল, অত্যন্ত ভিন্ন হার্ডওয়্যার সহ। ফলাফলটি মনে হয় যে মানচিত্র এবং তালিকার বোধগম্যতা পারফরম্যান্সের সাথে তুলনীয়, যা অন্যান্য এলোমেলো কারণগুলির দ্বারা সবচেয়ে দৃ strongly়ভাবে প্রভাবিত হয়। আমরা তালিকা comprehensions আশা যখন একমাত্র জিনিস আমরা বলতে পারেন, যে হবে, অদ্ভুত বলে মনে হয় [...]
জেনারেটরের এক্সপ্রেশন বেশী ভালো পারফর্ম করতে (...)
, map
যে জেনারেটরের এক্সপ্রেশন (আবার অভিমানী যে সব মান মূল্যায়ন / ব্যবহার করা হয়) আরও দক্ষ নয়।
এই পরীক্ষাগুলি একটি খুব সাধারণ ফাংশন (পরিচয় ফাংশন) ধরে নেয় তা উপলব্ধি করা গুরুত্বপূর্ণ; তবে এটি ঠিক আছে কারণ যদি ফাংশনটি জটিল হয়, তবে প্রোগ্রামের অন্যান্য বিষয়গুলির তুলনায় কর্মক্ষমতা ওভারহেড উপেক্ষিত হবে। (অন্যান্য সাধারণ বিষয়গুলির সাথে পরীক্ষা করা এখনও আকর্ষণীয় হতে পারে f=lambda x:x+x
)
আপনি যদি অজগর সমাবেশ পড়ার বিষয়ে দক্ষ হন তবে আপনি dis
মডিউলটি বাস্তবে পর্দার আড়ালে কী ঘটছে তা দেখতে ব্যবহার করতে পারেন :
>>> listComp = compile('[f(x) for x in xs]', 'listComp', 'eval')
>>> dis.dis(listComp)
1 0 LOAD_CONST 0 (<code object <listcomp> at 0x2511a48, file "listComp", line 1>)
3 MAKE_FUNCTION 0
6 LOAD_NAME 0 (xs)
9 GET_ITER
10 CALL_FUNCTION 1
13 RETURN_VALUE
>>> listComp.co_consts
(<code object <listcomp> at 0x2511a48, file "listComp", line 1>,)
>>> dis.dis(listComp.co_consts[0])
1 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 18 (to 27)
9 STORE_FAST 1 (x)
12 LOAD_GLOBAL 0 (f)
15 LOAD_FAST 1 (x)
18 CALL_FUNCTION 1
21 LIST_APPEND 2
24 JUMP_ABSOLUTE 6
>> 27 RETURN_VALUE
>>> listComp2 = compile('list(f(x) for x in xs)', 'listComp2', 'eval')
>>> dis.dis(listComp2)
1 0 LOAD_NAME 0 (list)
3 LOAD_CONST 0 (<code object <genexpr> at 0x255bc68, file "listComp2", line 1>)
6 MAKE_FUNCTION 0
9 LOAD_NAME 1 (xs)
12 GET_ITER
13 CALL_FUNCTION 1
16 CALL_FUNCTION 1
19 RETURN_VALUE
>>> listComp2.co_consts
(<code object <genexpr> at 0x255bc68, file "listComp2", line 1>,)
>>> dis.dis(listComp2.co_consts[0])
1 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 17 (to 23)
6 STORE_FAST 1 (x)
9 LOAD_GLOBAL 0 (f)
12 LOAD_FAST 1 (x)
15 CALL_FUNCTION 1
18 YIELD_VALUE
19 POP_TOP
20 JUMP_ABSOLUTE 3
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>> evalledMap = compile('list(map(f,xs))', 'evalledMap', 'eval')
>>> dis.dis(evalledMap)
1 0 LOAD_NAME 0 (list)
3 LOAD_NAME 1 (map)
6 LOAD_NAME 2 (f)
9 LOAD_NAME 3 (xs)
12 CALL_FUNCTION 2
15 CALL_FUNCTION 1
18 RETURN_VALUE
মনে হচ্ছে [...]
সিনট্যাক্স এর চেয়ে ব্যবহার করা ভাল list(...)
। দুর্ভাগ্যক্রমে map
ক্লাসটি বিযুক্ত করার জন্য কিছুটা অস্বচ্ছ, তবে আমরা আমাদের গতি পরীক্ষা দিয়ে উপযুক্ত করতে পারি।
map
এবং filter
স্ট্যান্ডার্ড লাইব্রেরির itertools
সাথে সহজাতভাবে খারাপ স্টাইল are জিভিআর আসলে না বলে যে তারা হয় ভয়াবহ ভুল বা কেবল পারফরম্যান্সের জন্য, কেবলমাত্র প্রাকৃতিক উপসংহার যদি "পাইথোনিকনেস" বলে তবে এটি এটিকে বোকা হিসাবে ভুলে যাওয়া ;-)
map
/ filter
পাইথন 3-এর পক্ষে একটি দুর্দান্ত ধারণা এবং অন্য পাইথনিস্টরা কেবলমাত্র বিদ্রোহই এগুলি বিল্ট-ইন নেমস্পেসে রেখেছিল ( reduce
স্থানান্তরিত হওয়ার সময় functools
)। আমি ব্যক্তিগতভাবে একমত নই ( map
এবং filter
পূর্বনির্ধারিত, বিশেষত অন্তর্নির্মিত, ফাংশনগুলির সাথে ভাল, যদি lambda
প্রয়োজন হয় তবে সেগুলি কখনই ব্যবহার করি না), তবে জিভিআর মূলত বছরের পর বছর ধরে এগুলিকে পাইথোনিক নয়।
itertools
? এই উত্তরটি থেকে আমি যে অংশটি উদ্ধৃত করছি তা হ'ল প্রধান দাবি যা আমাকে বিভ্রান্ত করে। আমি জানি না তার আদর্শ বিশ্বের কিনা, map
এবং filter
থেকে সরে আসবেন itertools
(অথবা functools
) অথবা সম্পূর্ণরূপে যান, কিন্তু যেটা ক্ষেত্রে দেখা যায়, একবার এক বলছেন যে itertools
তার সম্পূর্ণতা unPythonic হয়, তাহলে আমি সত্যিই জানি না কি "Pythonic" হয় বোঝাতে চাইলেও আমি মনে করি না এটি "জিভিআর লোকেরা ব্যবহারের পরামর্শ দেয়" এর মতো কিছু হতে পারে।
map
/ filter
, না itertools
। কার্যকরী প্রোগ্রামিং পুরোপুরি Pythonic আছে ( itertools
, functools
এবং operator
সব মনের মধ্যে কার্যকরী প্রোগ্রামিং রেখে বিশেষভাবে ডিজাইন করা হয়েছে, এবং আমি পাইথন সব সময় কার্মিক বাগধারার ব্যবহার করুন), এবং itertools
এর বিশেষভাবে বৈশিষ্ট্য ব্যাথা নিজেকে বাস্তবায়ন করতে হবে প্রদান করে, এটা map
এবং filter
জেনারেটরের এক্সপ্রেশন সঙ্গে হচ্ছে অপ্রয়োজনীয় যা গিডো তাদের ঘৃণা করেছিল। itertools
সবসময় ঠিক আছে।
map
এবং filter
তালিকা comprehensions পরিবর্তে।তারা "পাইথোনিক" না হওয়া সত্ত্বেও আপনি কেন তাদের পছন্দ করবেন এই উদ্দেশ্যগত কারণ:
তাদের আর্গুমেন্ট হিসাবে ফাংশন / ল্যাম্বডাস প্রয়োজন, যা একটি নতুন সুযোগ প্রবর্তন করে ।
আমি এটি একাধিকবার কামড়েছি:
for x, y in somePoints:
# (several lines of code here)
squared = [x ** 2 for x in numbers]
# Oops, x was silently overwritten!
তবে পরিবর্তে যদি আমি বলেছিলাম:
for x, y in somePoints:
# (several lines of code here)
squared = map(lambda x: x ** 2, numbers)
তাহলে সব ঠিক হয়ে যেত।
আপনি বলতে পারেন যে একই সুযোগে একই পরিবর্তনশীল নামটি ব্যবহার করার জন্য আমি বোকা ছিলাম।
আমি ছিলাম না। কোডটি মূলত ঠিক ছিল - দু'জন x
একই স্কোপে ছিল না।
আমি অভ্যন্তরীণ ব্লকটি কোডের একটি পৃথক বিভাগে স্থানান্তরিত করার পরেই সমস্যাটি উপস্থিত হয়েছিল (পড়ুন: রক্ষণাবেক্ষণের সময় সমস্যা, বিকাশ নয়), এবং আমি এটি আশা করি না।
হ্যাঁ, আপনি যদি কখনও এই ভুলটি না করেন তবে তালিকা উপলব্ধিগুলি আরও মার্জিত।
তবে ব্যক্তিগত অভিজ্ঞতা থেকে (এবং অন্যকেও একই ভুল করতে দেখে) আমি এটিকে পর্যাপ্ত সময়ে দেখেছি যে আমি মনে করি যে এই বাগগুলি আপনার কোডটিতে প্রবেশ করার সময় আপনার যে ব্যথা সহ্য করতে হবে তা লাভজনক নয়।
ব্যবহার করুন map
এবং filter
। তারা সূক্ষ্ম-থেকে-সনাক্তকরণের সুযোগ-সম্পর্কিত বাগগুলি প্রতিরোধ করে।
আপনার পরিস্থিতির জন্য উপযুক্ত হলে imap
এবং ifilter
(ইন itertools
) ব্যবহার বিবেচনা করতে ভুলবেন না !
map
এবং / বা স্যুইচ করার যৌক্তিক কারণ নয় filter
। যদি কিছু হয় map(lambda x: x ** 2, numbers)
তবে আপনার সমস্যা এড়ানোর জন্য সর্বাধিক প্রত্যক্ষ এবং যৌক্তিক অনুবাদ হ'ল জেনারেটর এক্সপ্রেশন নয় list(x ** 2 for x in numbers)
যা ফাঁস হয় না, যেমন জেরোজেজে ইতিমধ্যে উল্লেখ করেছেন। মেহরদাদ দেখুন, এতটা ব্যক্তিগতভাবে ডাউনটোট নেবেন না, আমি এখানে আপনার যুক্তির সাথে দৃ with়ভাবে একমত নই।
প্রকৃতপক্ষে map
এবং তালিকা অনুধাবন পাইথন 3 ভাষায় বেশ আলাদাভাবে আচরণ করে। নীচের পাইথন 3 প্রোগ্রামটি একবার দেখুন:
def square(x):
return x*x
squares = map(square, [1, 2, 3])
print(list(squares))
print(list(squares))
আপনি আশা করতে পারেন এটি "[1, 4, 9]" লাইনটি দু'বার মুদ্রণ করবে, তবে পরিবর্তে এটি "[1, 4, 9]" পরে "[]] প্রিন্ট করবে। প্রথমবার আপনি squares
এটি দেখলে মনে হয় তিনটি উপাদানের ক্রম হিসাবে আচরণ করা হয়েছে, তবে দ্বিতীয়বার খালি হিসাবে।
পাইথন 2 ভাষায় map
সরল পুরানো তালিকাটি দেয়, ঠিক তেমনি উভয় ভাষায় তালিকান বোধগম্যতা রয়েছে। কর্সটি হ'ল map
পাইথন 3 এর রিটার্ন মান (এবং imap
পাইথন 2 এ) কোনও তালিকা নয় - এটি একটি পুনরাবৃত্তিকারী!
আপনি যখন কোনও তালিকার পুনরাবৃত্তি করেন তার বিপরীতে আপনি যখন কোনও পুনরুক্তি দিয়ে পুনরাবৃত্তি করেন তখন উপাদানগুলি গ্রাস হয়ে যায়। এই কারণেই squares
শেষ print(list(squares))
লাইনে খালি দেখাচ্ছে ।
সংক্ষেপ:
map
কোনও ডাটা স্ট্রাকচার তৈরি করতে হয় , এটির পুনরুক্তিকারী নয়। তবে অলস ডাটা স্ট্রাকচারের চেয়ে অলস পুনরুক্তি করা সহজ। চিন্তার জন্য খাদ্য. ধন্যবাদ @ এমএনজেডকে
আমি দেখতে পাই যে তালিকার বোধগম্যতাগুলি আমি যা করার চেয়ে চেষ্টা করছি তার থেকে বেশি প্রকাশ করা হয় map
- তারা উভয়ই এটি সম্পন্ন করে, তবে প্রাক্তন কোনও জটিল lambda
প্রকাশ হতে পারে তা বোঝার চেষ্টা করার মানসিক বোঝা বাঁচায় ।
সেখানে কোথাও একটি সাক্ষাত্কারও পাওয়া গেছে (আমি এটি অফহ্যান্ডে খুঁজে পাচ্ছি না) যেখানে lambda
পাইডনকে গ্রহণ করার বিষয়ে গিডো তাঁর কাজ এবং কার্যকরী ফাংশনগুলির তালিকাভুক্ত করেছেন যা তিনি সবচেয়ে আফসোস করেন, তাই আপনি এই যুক্তিটি তৈরি করতে পারেন যে তারা গুণে অ-পাইথোনিক যে.
const
সি ++ এর মূল শব্দটি এই লাইনগুলি জুড়ে একটি দুর্দান্ত বিজয়।
lambda
এতটাই খোঁড়া (কোনও বিবৃতি নেই ..) তৈরি করা হয়েছে যে এগুলি যেভাবেই ব্যবহার করা কঠিন এবং সীমিত।
এখানে একটি সম্ভাব্য কেস রয়েছে:
map(lambda op1,op2: op1*op2, list1, list2)
বনাম:
[op1*op2 for op1,op2 in zip(list1,list2)]
আমি অনুমান করছি জিপ () হ'ল একটি দুর্ভাগ্যজনক এবং অপ্রয়োজনীয় ওভারহেড যদি আপনি মানচিত্রের পরিবর্তে তালিকার বোঝাপড়াগুলি ব্যবহার করার জন্য জোর করেন তবে আপনার তাতে লিপ্ত হওয়া দরকার। কেউ যদি ইতিবাচক বা নেতিবাচক দিক থেকে এটি স্পষ্ট করে তবে দুর্দান্ত হবে।
zip
অলস করতে পারেনitertools.izip
map(operator.mul, list1, list2)
। এটি খুব সাধারণ বাম দিকের অভিব্যক্তিগুলির উপর যা বোধগম্যতা আঠালো হয়ে যায়।
যদি আপনি কোনও অ্যাসিনক্রোনাস, সমান্তরাল বা বিতরণ কোড লেখার পরিকল্পনা করেন তবে আপনি সম্ভবত map
তালিকা বোঝার চেয়ে বেশি পছন্দ করবেন - বেশিরভাগ অ্যাসিনক্রোনাস, সমান্তরাল বা বিতরণকৃত প্যাকেজগুলি map
পাইথনের ওভারলোডের জন্য একটি ফাংশন সরবরাহ করে map
। তারপরে map
আপনার কোডের বাকী অংশে যথাযথ ফাংশনটি পাস করার মাধ্যমে, আপনাকে এটির সমান্তরাল (ইত্যাদি) চালানোর জন্য আপনার মূল সিরিয়াল কোডটি পরিবর্তন করতে হবে না।
পাইথন 3 যেহেতু map()
একটি পুনরুক্তিকারী, তাই আপনার যা প্রয়োজন তা মনে রাখতে হবে: একটি পুনরুক্তি বা list
বস্তু।
@ অ্যালেক্সমার্তেল্লি যেমন ইতিমধ্যে উল্লিখিত হয়েছে , map()
কেবলমাত্র আপনি যদি lambda
ফাংশন ব্যবহার না করেন তবে তালিকা বোঝার চেয়ে দ্রুত is
আমি আপনাকে কিছু সময়ের তুলনা উপস্থাপন করব।
পাইথন ৩.৩.২ এবং সিপথন
আমি বৃহস্পিটার নোটবুক এবং বিশেষত %timeit
অন্তর্নির্মিত যাদু কমান্ড
পরিমাপ ব্যবহার করেছি : s == 1000 এমএস == 1000 * 1000 µ এস = 1000 * 1000 * 1000 এনএস
সেটআপ:
x_list = [(i, i+1, i+2, i*2, i-9) for i in range(1000)]
i_list = list(range(1000))
অন্তর্নির্মিত ফাংশন:
%timeit map(sum, x_list) # creating iterator object
# Output: The slowest run took 9.91 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 277 ns per loop
%timeit list(map(sum, x_list)) # creating list with map
# Output: 1000 loops, best of 3: 214 µs per loop
%timeit [sum(x) for x in x_list] # creating list with list comprehension
# Output: 1000 loops, best of 3: 290 µs per loop
lambda
ফাংশন:
%timeit map(lambda i: i+1, i_list)
# Output: The slowest run took 8.64 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 325 ns per loop
%timeit list(map(lambda i: i+1, i_list))
# Output: 1000 loops, best of 3: 183 µs per loop
%timeit [i+1 for i in i_list]
# Output: 10000 loops, best of 3: 84.2 µs per loop
জেনারেটর এক্সপ্রেশনের মতো জিনিস রয়েছে, দেখুন পিইপি -0289 । সুতরাং আমি ভেবেছিলাম এটি তুলনার সাথে যুক্ত করা কার্যকর হবে
%timeit (sum(i) for i in x_list)
# Output: The slowest run took 6.66 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 495 ns per loop
%timeit list((sum(x) for x in x_list))
# Output: 1000 loops, best of 3: 319 µs per loop
%timeit (i+1 for i in i_list)
# Output: The slowest run took 6.83 times longer than the fastest.
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 506 ns per loop
%timeit list((i+1 for i in i_list))
# Output: 10000 loops, best of 3: 125 µs per loop
list
অবজেক্ট দরকার :এটি কাস্টম ফাংশন হলে তালিকা বোধগম্য ব্যবহার করুন, list(map())
বিল্টিন ফাংশন থাকলে ব্যবহার করুন
list
অবজেক্টের দরকার নেই , আপনার কেবল পুনরাবৃত্তিযোগ্য দরকার:সর্বদা ব্যবহার map()
!
আমি একটি অবজেক্টের পদ্ধতিটি আহ্বানের জন্য তিনটি পদ্ধতির তুলনায় একটি দ্রুত পরীক্ষা চালিয়েছি। সময়ের পার্থক্য, এক্ষেত্রে, নগণ্য এবং প্রশ্নে কার্যকরী বিষয় (@ অ্যালেক্স মার্তেলির প্রতিক্রিয়া দেখুন )। এখানে, আমি নিম্নলিখিত পদ্ধতিগুলির দিকে নজর রেখেছি:
# map_lambda
list(map(lambda x: x.add(), vals))
# map_operator
from operator import methodcaller
list(map(methodcaller("add"), vals))
# map_comprehension
[x.add() for x in vals]
তালিকার আকার বাড়ানোর জন্য আমি vals
উভয় পূর্ণসংখ্যার (পাইথন int
) এবং ভাসমান পয়েন্ট সংখ্যা (পাইথন float
) এর তালিকাগুলি (ভেরিয়েবলে সঞ্চিত ) দেখলাম । নিম্নলিখিত ডামি শ্রেণি DummyNum
বিবেচনা করা হয়:
class DummyNum(object):
"""Dummy class"""
__slots__ = 'n',
def __init__(self, n):
self.n = n
def add(self):
self.n += 5
বিশেষত, add
পদ্ধতি। __slots__
অ্যাট্রিবিউট পাইথন একটি সহজ অপ্টিমাইজেশান, মোট মেমরি শ্রেণী (বৈশিষ্ট্যাবলী) প্রয়োজনীয় সংজ্ঞায়িত করতে মেমরির আকার হ্রাস করুন। এখানে ফলস্বরূপ প্লটগুলি রয়েছে।
যেমন আগেই বলা হয়েছে, ব্যবহৃত কৌশলটি একটি ন্যূনতম পার্থক্য তৈরি করে এবং আপনার এমনভাবে কোড করা উচিত যা আপনার কাছে সবচেয়ে পাঠযোগ্য বা বিশেষ পরিস্থিতিতে। এই ক্ষেত্রে, তালিকা উপলব্ধি ( map_comprehension
কৌশল) কোনও বস্তুতে বিশেষত সংক্ষিপ্ত তালিকা সহ উভয় প্রকারের সংযোজনের জন্য দ্রুততম।
প্লট এবং ডেটা উত্পন্ন করতে উত্স হিসাবে ব্যবহৃত এই পেস্টবিনটি দেখুন ।
map
কেবল তখনই দ্রুত হয় যদি ফাংশনটিকে একইভাবে বলা হয় (যেমন [*map(f, vals)]
বনাম [f(x) for x in vals]
)। তাই list(map(methodcaller("add"), vals))
দ্রুত চেয়ে [methodcaller("add")(x) for x in vals]
। map
দ্রুত নাও হতে পারে যখন লুপিং সহযোগীর একটি ভিন্ন কলিং পদ্ধতি যে কিছু উপরি এড়াতে পারেন ব্যবহার (যেমন x.add()
এড়াতে methodcaller
বা ল্যামডা অভিব্যক্তি ওভারহেড)। এই নির্দিষ্ট পরীক্ষার ক্ষেত্রে [*map(DummyNum.add, vals)]
দ্রুত হবে (কারণ DummyNum.add(x)
এবং x.add()
মূলত একই পারফরম্যান্স রয়েছে)।
list()
কলগুলি তালিকা বোধের তুলনায় কিছুটা ধীর। ন্যায্য তুলনার জন্য আপনাকে লিখতে হবে [*map(...)]
।
list()
কলগুলি ওভারহেড বাড়িয়েছে। উত্তরগুলি পড়ার জন্য আরও বেশি সময় ব্যয় করা উচিত ছিল। আমি এই পরীক্ষাগুলি ন্যায্য তুলনার জন্য আবার চালাব, তবে তফাত কম হতে পারে।
আমি বিবেচনা যে সবচেয়ে Pythonic উপায় পরিবর্তে একটি তালিকা ধী ব্যবহার করা map
এবং filter
। কারণ তালিকা comprehensions চেয়ে পরিষ্কার হয় map
এবং filter
।
In [1]: odd_cubes = [x ** 3 for x in range(10) if x % 2 == 1] # using a list comprehension
In [2]: odd_cubes_alt = list(map(lambda x: x ** 3, filter(lambda x: x % 2 == 1, range(10)))) # using map and filter
In [3]: odd_cubes == odd_cubes_alt
Out[3]: True
আপনি দেখতে হিসাবে, একটি বোধগম্যতা lambda
হিসাবে অতিরিক্ত এক্সপ্রেশন প্রয়োজন হয় না map
। তদ্ব্যতীত, একটি বোধগম্যতা সহজেই ফিল্টারিং করতে দেয় , যখন ফিল্টারিংয়ের অনুমতি map
প্রয়োজন filter
।
আমি @ অ্যালেক্স-মার্তেলির মাধ্যমে কোডটি চেষ্টা করেছিলাম তবে কিছু ত্রুটি খুঁজে পেয়েছি
python -mtimeit -s "xs=range(123456)" "map(hex, xs)"
1000000 loops, best of 5: 218 nsec per loop
python -mtimeit -s "xs=range(123456)" "[hex(x) for x in xs]"
10 loops, best of 5: 19.4 msec per loop
আমার কোড থেকে স্পষ্ট যেমন তালিকা বোঝাপড়াটি ব্যবহার করা হয় তখন অনেক বড় ব্যাপ্তির জন্যও মানচিত্র একই পরিমাণে সময় নেয়। সুতরাং "অপার্থিব" হিসাবে বিবেচিত হওয়া ছাড়াও আমি মানচিত্রের ব্যবহার সম্পর্কিত কোনও পারফরম্যান্স সমস্যার মুখোমুখি হইনি।
map
একটি তালিকা ফিরে আসে। পাইথন 3-এ, map
অলসভাবে মূল্যায়ন করা হয়, তাই কেবল কল করা map
কোনও নতুন তালিকার উপাদানগুলির গণনা করে না, সুতরাং আপনি কেন এইরকম স্বল্প সময় পান।