“අවම විස්මයන්” සහ විකෘති පෙරනිමි තර්කය


2606

පයිතන් සමඟ දිගින් දිගට කතා කරන ඕනෑම කෙනෙකුට පහත සඳහන් නිකුතුවෙන් දෂ්ට කර ඇත (හෝ කැබලිවලට ඉරා ඇත):

def foo(a=[]):
    a.append(5)
    return a

පයිතන් සාමනේරයන් මෙම ශ්‍රිතය සෑම විටම එක් මූලද්‍රව්‍යයක් සහිත ලැයිස්තුවක් නැවත ලබා දෙනු ඇතැයි අපේක්ෂා කරයි : [5]. ප්‍රති result ලය ඒ වෙනුවට බෙහෙවින් වෙනස් ය, පුදුම සහගත ය (නවකයකු සඳහා):

>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()

මගේ කළමණාකරුවෙක් වරක් මෙම අංගය සමඟ පළමු වරට මුණගැසුණු අතර එය භාෂාවේ “නාට්‍යමය නිර්මාණ දෝෂයක්” ලෙස හැඳින්වීය. මම පිළිතුරු දුන්නේ හැසිරීමට යටින් පැහැදිලි කිරීමක් ඇති අතර, ඔබ අභ්‍යන්තරය තේරුම් නොගන්නේ නම් එය ඇත්තෙන්ම ප්‍රහේලිකාවක් සහ අනපේක්ෂිත දෙයක් බවයි. කෙසේ වෙතත්, මට පහත සඳහන් ප්‍රශ්නයට පිළිතුරු දීමට නොහැකි විය: පෙරනිමි තර්කය ශ්‍රිත අර්ථ දැක්වීමේදී බන්ධනය කිරීමට හේතුව කුමක්ද? පළපුරුදු හැසිරීමට ප්‍රායෝගික භාවිතයක් ඇතැයි මට සැකයි (දෝෂ බෝ නොකර C හි ස්ථිතික විචල්‍යයන් සැබවින්ම භාවිතා කළේ කවුද?)

සංස්කරණය කරන්න :

බැක්සෙක් රසවත් උදාහරණයක් ඉදිරිපත් කළේය. ඔබගේ බොහෝ අදහස් සහ විශේෂයෙන් උටාල්ගේ අදහස් සමඟ මම තවදුරටත් විස්තර කළෙමි:

>>> def a():
...     print("a executed")
...     return []
... 
>>>            
>>> def b(x=a()):
...     x.append(5)
...     print(x)
... 
a executed
>>> b()
[5]
>>> b()
[5, 5]

මට නම්, සැලසුම් තීරණය පරාමිතීන්ගේ විෂය පථය තැබිය යුත්තේ කොතැනටද යන්නට සාපේක්ෂව බව පෙනේ: ශ්‍රිතය ඇතුළත හෝ ඒ සමඟ “එකට”?

ශ්‍රිතය තුළ බන්ධනය කිරීම යන්නෙන් අදහස් xවන්නේ ශ්‍රිතය හැඳින්වූ විට නිශ්චිත පෙරනිමියට effectively ලදායී ලෙස බැඳී ඇති බවයි def. ශ්‍රිත වස්තුව) අර්ථ දැක්වීමේදී සිදු වන අතර, කොටස (පෙරනිමි පරාමිතීන් පැවරීම) ශ්‍රිත ආයාචන වේලාවේදී සිදු වේ.

සත්‍ය හැසිරීම වඩාත් අනුකූල වේ: එම රේඛාව ක්‍රියාත්මක වන විට එම රේඛාවේ සෑම දෙයක්ම ඇගයීමට ලක් වේ.



4
විකෘති තර්ක සාමාන්‍ය පුද්ගලයෙකුට අවම වශයෙන් විශ්මය ජනක මූලධර්මය උල්ලං late නය කරන බවට මට කිසිදු සැකයක් නැත. ආරම්භකයින් එහි පියවර තබන අයුරු මම දුටුවෙමි. ඉන්පසු වීරයන් තැපැල් ලැයිස්තු වෙනුවට තැපැල් පටි සමඟ ආදේශ කරමි. කෙසේ වෙතත්, විකෘති තර්ක තවමත් පයිතන් සෙන් (පෙප් 20) සමඟ අනුකූල වන අතර එය “ලන්දේසීන්ට පැහැදිලිය” (දෘඩ හරිත පයිතන් ක්‍රමලේඛකයින් විසින් තේරුම් ගෙන / සූරාකනු ලැබේ) වගන්තියට වැටේ. ඩොක් ස්ට්‍රිං සමඟ නිර්දේශිත ක්‍රියාකාරීත්වය හොඳම, නමුත් ඩොක් නූල් සහ ඕනෑම (ලිඛිත) ලියකියවිලි වලට ප්‍රතිරෝධය වර්තමානයේ එතරම් සුලභ නොවේ. පුද්ගලිකව, මම සැරසිලි කරුවෙකුට කැමතියි (sayfixed_defaults කියන්න).
සර්ජ්

5
මට මෙය හමු වූ විට මගේ තර්කය නම්: "ඔබ ශ්‍රිතයට සම්මත කළ හැකි විකෘති විය හැකි විකෘතියක් නැවත ලබා දෙන ශ්‍රිතයක් නිර්මාණය කිරීමට ඔබට අවශ්‍ය ඇයි? එක්කෝ එය විකෘති වෙනස් කිරීම හෝ නව එකක් නිර්මාණය කිරීම. ඔබට අවශ්‍ය ඇයි? ඔබේ ශ්‍රිතයට පේළි තුනක් එකතු නොකර එය කිරීමට ඉඩ ලබා දීම සඳහා පරිවර්තකය නැවත ලිවිය යුත්තේ ඇයි? මන්ද අප මෙහි කතා කරන්නේ පරිවර්තකයා මෙහි ක්‍රියාකාරී අර්ථ දැක්වීම් සහ ඉවත් කිරීම් හසුරුවන ආකාරය නැවත ලිවීම ගැන ය. යන්තම් අත්‍යවශ්‍ය භාවිත නඩුවක් සඳහා එය කිරීමට බොහෝ දේ ඇත.
ඇලන් ලියුතර්ඩ්

12
"පයිතන් සාමනේරයන් මෙම ශ්‍රිතය සෑම විටම එක් මූලද්‍රව්‍යයක් සහිත ලැයිස්තුවක් නැවත ලබා දෙනු ඇතැයි අපේක්ෂා කරයි : [5]." මම පයිතන් සාමනේරයෙක්, මම මෙය බලාපොරොත්තු නොවෙමි, මන්ද පැහැදිලිවම foo([1])නැවත පැමිණෙනු ඇත [1, 5], නැත [5]. ඔබ කීමට අදහස් කළේ නවකයකු පරාමිතියක් නොමැතිව හැඳින්වූ ශ්‍රිතය සැමවිටම නැවත පැමිණෙනු ඇතැයි අපේක්ෂා කරන [5]බවයි.
symplectomorphic

2
මෙම ප්‍රශ්නය අසන්නේ "මෙය [වැරදි මාර්ගය] එසේ ක්‍රියාත්මක කළේ ඇයි?"එය "නිවැරදි මාර්ගය කුමක්ද?" , එය ආවරණය කරන්නේ [ arg = කිසිවක් භාවිතා කිරීමෙන් පයිතන්ගේ විකෘති පෙරනිමි තර්ක ගැටළුව විසඳන්නේ ඇයි? ] * ( stackoverflow.com/questions/10676729/… ). නව පරිශීලකයින් සෑම විටම පාහේ කලින් සිටි අය කෙරෙහි එතරම් උනන්දුවක් නොදක්වන අතර දෙවැන්න ගැන වැඩි යමක් දක්වයි, එබැවින් එය සමහර විට උපුටා දැක්වීමට ඉතා ප්‍රයෝජනවත් සබැඳියක් / ඩුප් එකක් වේ.
smci

Answers:


1617

ඇත්ත වශයෙන්ම, මෙය නිර්මාණ දෝෂයක් නොවන අතර එය අභ්‍යන්තර හෝ කාර්ය සාධනය නිසා නොවේ.
එය සරලවම පැමිණෙන්නේ පයිතන් හි කාර්යයන් පළමු පන්තියේ වස්තූන් වන අතර කේත කැබැල්ලක් පමණක් නොවේ.

ඔබ මේ ආකාරයෙන් සිතා බැලූ විගසම එය සම්පූර්ණයෙන්ම අර්ථවත් කරයි: ශ්‍රිතයක් යනු එහි අර්ථ දැක්වීම මත ඇගයීමට ලක් කරන වස්තුවකි; පෙරනිමි පරාමිතීන් "සාමාජික දත්ත" වර්ගයක් වන අතර එම නිසා ඒවායේ තත්වය එක් ඇමතුමක සිට අනෙක් ඇමතුම දක්වා වෙනස් විය හැකිය - වෙනත් ඕනෑම වස්තුවක හරියටම.

කෙසේ වෙතත්, පයිතන් හි පෙරනිමි පරාමිති අගයන්හි මෙම හැසිරීමට හේතු පිළිබඳ ඉතා හොඳ පැහැදිලි කිරීමක් එෆ්බොට් සතුව ඇත .
මම එය ඉතා පැහැදිලිව සොයා ගත් අතර, ක්‍රියාකාරී වස්තූන් ක්‍රියා කරන ආකාරය පිළිබඳ වඩා හොඳ දැනුමක් සඳහා එය කියවීමට මම යෝජනා කරමි.


80
ඉහත පිළිතුර කියවන ඕනෑම කෙනෙකුට, සම්බන්ධිත එෆ්බොට් ලිපිය කියවීමට කාලය ගන්නැයි මම තරයේ නිර්දේශ කරමි. අනෙක් සියලුම ප්‍රයෝජනවත් තොරතුරු මෙන්ම, ප්‍රති language ල හැඹිලි / මතක සටහන් සඳහා මෙම භාෂා අංගය භාවිතා කළ හැකි ආකාරය පිළිබඳ කොටස දැන ගැනීම ඉතා පහසුය!
කැම් ජැක්සන්

85
එය පළමු පන්තියේ වස්තුවක් වුවද, එක් එක් පෙරනිමි අගය සඳහා කේතය වස්තුව සමඟ ගබඩා කර ඇති අතර ශ්‍රිතය හැඳින්වෙන සෑම අවස්ථාවකම නැවත ඇගයීමට ලක් කරන මෝස්තරයක් යමෙකුට දැකගත හැකිය . එය වඩා හොඳ වනු ඇතැයි මම නොකියමි, පළමු පන්තියේ වස්තූන් වීම එය සම්පූර්ණයෙන් වළක්වන්නේ නැත.
ගෙරිට්

314
කණගාටුයි, නමුත් "පයිතන්හි විශාලතම WTF" ලෙස සලකන ඕනෑම දෙයක් නිසැකවම නිර්මාණ දෝෂයකි . මෙය සෑම කෙනෙකුටම යම්කිසි දෝෂ සඳහා ප්‍රභවයකි , මන්ද කිසිවෙකු මුලින් එම හැසිරීම අපේක්ෂා නොකරන හෙයිනි - එයින් අදහස් කරන්නේ එය ආරම්භ කිරීමට සැලසුම් කර නොතිබිය යුතු බවයි. පෙරනිමි තර්ක ස්ථිතික නොවන පරිදි ඔවුන් පයිතන් නිර්මාණය කළ යුතුව තිබුණි.
බ්ලූරාජා - ඩැනී ප්ලග්ගොෆ්ට්

192
එය නිර්මාණ දෝෂයක් වුවත් නැතත්, ඔබේ පිළිතුරෙන් ඇඟවෙන්නේ මෙම හැසිරීම කෙසේ හෝ අවශ්‍ය බවත්, කාර්යයන් පළමු පන්තියේ වස්තූන් බවත්, එය එසේ නොවන බවත් ය. පයිතන් වැසීම් ඇත. ඔබ පෙරනිමි තර්කය ශ්‍රිතයේ පළමු පේළියේ පැවරුමක් සමඟ ප්‍රතිස්ථාපනය කරන්නේ නම්, එය එක් එක් ඇමතුමේ ප්‍රකාශනය ඇගයීමට ලක් කරයි (සංවෘත විෂය පථයක ප්‍රකාශිත නම් භාවිතා කළ හැකිය). ශ්‍රිතය හරියටම එකම ආකාරයකින් කැඳවන සෑම අවස්ථාවකම පෙරනිමි තර්ක තක්සේරු කිරීම කළ නොහැකි හෝ සාධාරණ නොවන බවට කිසිදු හේතුවක් නැත.
මාර්ක් අමරි

24
සැලසුම කෙලින්ම අනුගමනය නොකරයි functions are objects. ඔබේ පරමාදර්ශය තුළ, යෝජනාව වනුයේ ශ්‍රිතවල පෙරනිමි අගයන් ගුණාංගවලට වඩා ගුණාංග ලෙස ක්‍රියාත්මක කිරීමයි.
bukzor

275

ඔබට පහත කේතය ඇතැයි සිතමු

fruits = ("apples", "bananas", "loganberries")

def eat(food=fruits):
    ...

ආහාර ගැනීමේ ප්‍රකාශය දුටු විට අවම විශ්මය ජනක දෙය නම් පළමු පරාමිතිය ලබා නොදුනහොත් එය ටුපල් එකට සමාන වනු ඇතැයි සිතීමයි. ("apples", "bananas", "loganberries")

කෙසේ වෙතත්, පසුව කේතයේ යැයි කියනු ලැබේ, මම එවැනි දෙයක් කරමි

def some_random_function():
    global fruits
    fruits = ("blueberries", "mangos")

ශ්‍රිත ප්‍රකාශනයට වඩා පෙරනිමි පරාමිතීන් ශ්‍රිතය ක්‍රියාත්මක කිරීමේදී බැඳී තිබේ නම්, පලතුරු වෙනස් කර ඇති බව දැනගැනීමෙන් මම පුදුමයට පත් වෙමි (ඉතා නරක ආකාරයකින්). මෙය ඔබගේ බව සොයා ගැනීමට වඩා IMO විශ්මය ජනක වනු ඇතfooඉහත ක්‍රියාකාරිත්වය ලැයිස්තුව විකෘති කරන .

සැබෑ ගැටළුව පවතින්නේ විකෘති විචල්‍යයන් සමඟ වන අතර, සියලු භාෂාවන්ට මෙම ගැටළුව යම් දුරකට තිබේ. මෙන්න ප්‍රශ්නයක්: ජාවා හි මට පහත කේතය ඇතැයි සිතමු:

StringBuffer s = new StringBuffer("Hello World!");
Map<StringBuffer,Integer> counts = new HashMap<StringBuffer,Integer>();
counts.put(s, 5);
s.append("!!!!");
System.out.println( counts.get(s) );  // does this work?

දැන්, මගේ සිතියම StringBufferයතුර සිතියමට ඇතුළත් කළ විට එහි වටිනාකම භාවිතා කරයිද, නැතහොත් එය යතුර යොමු කර ගබඩා කරන්නේද? කෙසේ හෝ යමෙකු මවිතයට පත් වේ; එක්කෝ වස්තුව ලබා ගැනීමට උත්සාහ කළ පුද්ගලයාMap ඔවුන් විසින් තැබූ වටිනාකමට සමාන අගයක් භාවිතා කරමින් කළ පුද්ගලයා හෝ ඔවුන් භාවිතා කරන යතුර වචනාර්ථයෙන් එකම වස්තුව වුවද ඔවුන්ගේ වස්තුව නැවත ලබා ගත නොහැකි බව පෙනේ. එය සිතියමට ඇතුළත් කිරීම සඳහා භාවිතා කරන ලදි (ඇත්ත වශයෙන්ම පයිතන් එහි විකෘති කළ දත්ත වර්ග ශබ්ද කෝෂ යතුරු ලෙස භාවිතා කිරීමට ඉඩ නොදේ).

ඔබේ උදාහරණය පයිතන් නවකයින් පුදුමයට හා සපා කෑමට ලක්වන හොඳ අවස්ථාවකි. නමුත් මම තර්ක කරන්නේ අපි මෙය "සවි" කළහොත්, එය වෙනස් තත්වයක් නිර්මාණය කරනු ඇත්තේ ඒ වෙනුවට ඔවුන් දෂ්ට කරනු ඇති බවත්, එය ඊටත් වඩා අඩු බුද්ධියක් ඇති බවත්ය. එපමණක් නොව, විකෘති විචල්‍යයන් සමඟ කටයුතු කිරීමේදී මෙය සැමවිටම සිදුවේ. ඔබ ලියන කේතය මත පදනම්ව යමෙකුට එක් හෝ ප්‍රතිවිරුද්ධ හැසිරීමක් සිතාමතාම අපේක්ෂා කළ හැකි අවස්ථාවන්ට ඔබ සැමවිටම යොමු වේ.

මම පුද්ගලිකව පයිතන්ගේ වර්තමාන ප්‍රවේශයට කැමතියි: ශ්‍රිතය අර්ථ දක්වන විට පෙරනිමි ශ්‍රිත තර්ක ඇගයීමට ලක් කරන අතර එම වස්තුව සැමවිටම පෙරනිමිය වේ. ඔවුන්ට හිස් ලැයිස්තුවක් භාවිතා කර විශේෂ අවස්ථා ලබා ගත හැකි යැයි මම සිතමි, නමුත් ඒ ආකාරයේ විශේෂ ආවරණයක් ඊටත් වඩා පුදුමයට හේතු වනු ඇත, පසුපසට නොගැලපෙන බව සඳහන් නොකල යුතුය.


30
මම හිතන්නේ එය විවාදයට තුඩු දෙන කාරණයක්. ඔබ ක්‍රියා කරන්නේ ගෝලීය විචල්‍යයක් මත ය. ඔබගේ ගෝලීය විචල්‍යය සම්බන්ධ ඔබේ කේතයේ ඕනෑම තැනක සිදුකරන ඕනෑම ඇගයීමක් දැන් (නිවැරදිව) යොමු වනු ඇත ("බ්ලූබෙරීස්", "අඹ"). පෙරනිමි පරාමිතිය වෙනත් ඕනෑම අවස්ථාවකට සමාන විය හැකිය.
ස්ටෙෆානෝ බෝරිනි

47
ඇත්තටම, මම හිතන්නේ නැහැ මම ඔබේ පළමු උදාහරණයට එකඟයි කියලා. මුලින් ආරම්භක යන්ත්‍රයක් වෙනස් කිරීමේ අදහසට මා කැමති බව මට විශ්වාස නැත, නමුත් මම එසේ කළහොත්, ඔබ විස්තර කරන ආකාරයටම එය හැසිරෙනු ඇතැයි මම අපේක්ෂා කරමි - පෙරනිමි අගය වෙනස් කිරීම ("blueberries", "mangos").
බෙන් බ්ලැන්ක්

12
පෙරනිමි පරාමිතිය වේ වෙනත් ඕනෑම අවස්ථාවක වගේ. අනපේක්ෂිත දෙය නම් පරාමිතිය ගෝලීය විචල්‍යයක් මිස දේශීය එකක් නොවේ. අනෙක් අතට, ඇමතුම නොව ක්‍රියාකාරී අර්ථ දැක්වීමේදී කේතය ක්‍රියාත්මක වන බැවිනි. ඔබ එය ලබා ගත් පසු, පංති සඳහාද එයම වේ, එය මනාව පැහැදිලිය.
ලෙනාට් රෙජෙබ්‍රෝ

17
උදාහරණය දීප්තිමත් නොව මුළා කරවනසුලුය. නම් some_random_function()කිරීමට appends fruitsවෙනුවට එය ද පවරා, හැසිරීම eat() ඇත වෙනස් කරන්න. වර්තමාන අපූරු නිර්මාණය සඳහා බොහෝ දේ. ඔබ වෙනත් තැනක යොමු කර ඇති පෙරනිමි තර්කයක් භාවිතා කර ශ්‍රිතයට පිටතින් යොමු කිරීම වෙනස් කරන්නේ නම්, ඔබ ඉල්ලන්නේ කරදරයකි. සැබෑ ඩබ්ලිව්ටීඑෆ් යනු මිනිසුන් නැවුම් පෙරනිමි තර්කයක් නිර්වචනය කරන විට (ලැයිස්තුවක් වචනානුසාරයෙන් හෝ ඉදිකිරීම්කරුවකුට ඇමතුමක්), සහ තවමත් ටිකක් ලබා ගනී.
ඇලෙක්සිස්

13
ඔබ පැහැදිලිවම ප්‍රකාශ globalකර නැවත පත් කර ඇත - eatඉන් පසුව වෙනස් ආකාරයකින් ක්‍රියා කරන්නේ නම් පුදුම වීමට දෙයක් නැත .
user3467349

241

ප්‍රලේඛනයේ අදාළ කොටස :

ශ්‍රිත අර්ථ දැක්වීම ක්‍රියාත්මක කරන විට පෙරනිමි පරාමිති අගයන් වමේ සිට දකුණට ඇගයීමට ලක් කෙරේ. මෙයින් අදහස් කරන්නේ ප්‍රකාශනය එක් වරක්, ශ්‍රිතය නිර්වචනය කළ විට ඇගයීමට ලක් කරන අතර එක් එක් ඇමතුම සඳහා එකම “පෙර ගණනය කළ” අගය භාවිතා කරන බවයි. පෙරනිමි පරාමිතියක් යනු ලැයිස්තුවක් හෝ ශබ්ද කෝෂයක් වැනි විකෘති වස්තුවක් වන විට මෙය තේරුම් ගැනීම විශේෂයෙන් වැදගත් වේ: ශ්‍රිතය වස්තුව වෙනස් කරන්නේ නම් (උදා: ලැයිස්තුවකට අයිතමයක් එකතු කිරීමෙන්), පෙරනිමි අගය වෙනස් වේ. මෙය සාමාන්‍යයෙන් අදහස් කළ දෙය නොවේ. මෙය වටා ඇති ක්‍රමයක් Noneනම් පෙරනිමිය ලෙස භාවිතා කිරීම සහ ශ්‍රිතයේ ශරීරය තුළ එය පැහැදිලිව පරීක්ෂා කිරීම, උදා:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

183
"මෙය සාමාන්‍යයෙන් අදහස් කළ දෙය නොවේ" සහ "මේ වටා ඇති මාර්ගයක්" යන වාක්‍ය ඛණ්ඩයන් නිර්මාණ දෝෂයක් ලේඛනගත කරනවා සේ දැනේ.
bukzor

4
Att මැතිව්: මම හොඳින් දනිමි, නමුත් එය වළක්වා ගැනීම වටී නැත. මෙම හේතුව නිසා විලාසිතාවේ මාර්ගෝපදේශ සහ ලින්ටර් කොන්දේසි විරහිතව විකෘති කළ හැකි පෙරනිමි අගයන් වැරදියි. එකම දේ කිරීමට පැහැදිලි ක්‍රමය නම් ( function.data = []) ශ්‍රිතයට ගුණාංගයක් පුරවා ගැනීම හෝ වඩා හොඳ, වස්තුවක් සෑදීමයි.
bukzor

7
uk බුක්සෝර්: අන්තරායන් සටහන් කර ලේඛනගත කළ යුතුය, මේ නිසා මෙම ප්‍රශ්නය හොඳ වන අතර බොහෝ ඉහළ නැංවීම් ලැබී ඇත. ඒ අතරම, අන්තරායන් ඉවත් කිරීම අවශ්‍ය නොවේ. පයිතන් ආරම්භකයින් කී දෙනෙක් එය වෙනස් කළ ශ්‍රිතයක් සඳහා ලැයිස්තුවක් සම්මත කර ඇති අතර, මුල් විචල්‍යයේ වෙනස්කම් දැකීමෙන් කම්පනයට පත් වූවාද? එහෙත් ඒවා භාවිතා කරන්නේ කෙසේදැයි ඔබ තේරුම් ගත් විට විකෘති වස්තු වර්ග අපූරු ය. මම හිතන්නේ එය මෙම සුවිශේෂී අනතුර පිළිබඳ මතයට තල්ලු කරයි.
මැතිව්

33
"මෙය සාමාන්‍යයෙන් අදහස් කළේ නොවේ" යන වාක්‍ය ඛණ්ඩයේ තේරුම "ක්‍රමලේඛකයාට ඇත්ත වශයෙන්ම සිදුවීමට අවශ්‍ය දේ නොව" පයිතන් විසින් කළ යුතු දේ නොවේ. "
holdenweb

4
@holdenweb වාව්, මම සාදයට මෙගා ප්‍රමාදයි. සන්දර්භය අනුව, බක්සෝර් සම්පූර්ණයෙන්ම නිවැරදියි: ඔවුන් විසින් හැසිරීම / ප්‍රතිවිපාක ලේඛනගත කරනුයේ භාෂාව විසින් ශ්‍රිතයේ අර්ථ දැක්වීම ක්‍රියාත්මක කළ යුතු යැයි ඔවුන් තීරණය කළ විට “අපේක්ෂිත” නොවේ. එය ඔවුන්ගේ නිර්මාණ තේරීමේ අනපේක්ෂිත ප්‍රති ence ලයක් බැවින් එය නිර්මාණ දෝෂයකි. එය නිර්මාණ දෝෂයක් නොවේ නම්, "මේ වටා මගක්" ඉදිරිපත් කිරීමට පවා අවශ්‍ය නොවනු ඇත.
code_dredd

118

පයිතන් පරිවර්තක අභ්‍යන්තර ක්‍රියාකාරකම් ගැන මම කිසිවක් නොදනිමි (මම සම්පාදකයින් සහ පරිවර්තකයන් පිළිබඳ විශේෂ expert යෙක් නොවෙමි) එබැවින් මම නොපෙනෙන හෝ කළ නොහැකි දෙයක් යෝජනා කළහොත් මට දොස් නොකියන්න.

පයිතන් වස්තූන් විකෘති වන බව සපයා ඇති අතර, පෙරනිමි තර්ක දේවල් සැලසුම් කිරීමේදී මෙය සැලකිල්ලට ගත යුතු යැයි මම සිතමි. ඔබ ලැයිස්තුවක් ස්ථාපනය කරන විට:

a = []

ඔබ විසින් යොමු කරන ලද නව ලැයිස්තුවක් ලබා ගැනීමට බලාපොරොත්තු වේ a.

දිය යුතු ඇයි a=[]දී

def x(a=[]):

ක්‍රියාකාරී අර්ථ දැක්වීම මත නව ලැයිස්තුවක් ස්ථාපනය කරන්න මිස ආයාචනය මත නොවේද? එය හරියට ඔබ "පරිශීලකයා තර්කය සපයන්නේ නැත්නම් නව ලැයිස්තුවක් ක්ෂණිකව සකසා එය අමතන්නා විසින් නිෂ්පාදනය කරන ලද්දක් ලෙස භාවිතා කරන්න" යනුවෙන් ඔබ අසයි. මම හිතන්නේ මේ වෙනුවට අපැහැදිලි ය:

def x(a=datetime.datetime.now()):

පරිශීලකයා, ඔබට අවශ්‍යද? a නිර්වචනය කරන විට හෝ ක්‍රියාත්මක කරන විට අනුරූප වන දිවා කාලයට පෙරනිමි වීමටx ? මෙම අවස්ථාවෙහිදී, පෙර පැවති ආකාරයටම, පෙරනිමි තර්කය "පැවරුම" යනු ශ්‍රිතයේ පළමු උපදෙස් ලෙස ( datetime.now()ක්‍රියාකාරී ආයාචනය ලෙස හැඳින්වේ) මම එම හැසිරීමම තබා ගනිමි . අනෙක් අතට, පරිශීලකයාට අර්ථ දැක්වීමේ කාල සිතියම් ගත කිරීමට අවශ්‍ය නම් ඔහුට ලිවිය හැකිය:

b = datetime.datetime.now()
def x(a=b):

මම දන්නවා, මම දන්නවා: එය වසා දැමීමක්. විකල්පයක් ලෙස, පයිතන් අර්ථ දැක්වීමේ-කාල බන්ධනයට බල කිරීම සඳහා යතුරු පදයක් සපයනු ඇත:

def x(static a=b):

11
ඔබට කළ හැකිය: def x (a = None): ඉන්පසු, කිසිවක් නොමැති නම්, a = datetime.datetime.now () සකසන්න
ඇනොන්

20
මේ සඳහා ස්තූතියි. මට කෙළවරක් නැති වීමට හේතුව මට ඇඟිල්ල දිගු කිරීමට නොහැකි විය. ඔබ එය අවම වශයෙන් ව්‍යාකූලත්වයකින් හා ව්‍යාකූලත්වයකින් යුතුව අලංකාර ලෙස කර ඇත. යමෙකු C ++ හි පද්ධති ක්‍රමලේඛන වලින් පැමිණෙන අතර සමහර විට අශෝභන ලෙස භාෂා විශේෂාංග “පරිවර්ථනය” කරන විට, මෙම ව්‍යාජ මිතුරා පන්ති ගුණාංග මෙන් ම විශාල වේලාවක දී මට පයින් ගැසීය. දේවල් මේ ආකාරයෙන් සිදුවන්නේ මන්දැයි මට වැටහී ඇත, නමුත් මට ධනාත්මකව කුමක් පැමිණියත් මට එයට උදව් කිරීමට හෝ අකමැති වීමට නොහැකිය. අවම වශයෙන් එය මගේ අත්දැකීමට කොතරම් පටහැනිද, මම එය කිසි විටෙකත් අමතක නොකරමි ...
ඇන්ඩ්‍රියාස්ට්

5
And ඇන්ඩ්‍රියාස් ඔබ පයිතන් දිගු කාලයක් භාවිතා කළ පසු, පන්තියේ ගුණාංග ලෙස එය අර්ථ නිරූපණය කිරීම පයිතන්ට කෙතරම් තාර්කිකදැයි ඔබ දැකීමට පටන් ගනී - එයට හේතුව C ++ (සහ ජාවා, සහ C # ...) එය ඇති අන්තර්ගතයන් සඳහා තේරුමක් ඇති class {}වාරණ වලට අයත් ලෙස අර්ථ දැක්වීමට අවස්ථා :) නමුත් පන්ති පළමු පන්තියේ වස්තූන් වන විට, සැබවින් ම ස්වභාවික දෙයක්, ඒවායේ අන්තර්ගතයන් සඳහා (මතකයේ) ඒවායේ අන්තර්ගතයන් පිළිබිඹු වේ (කේතයෙන්).
කාල් නෙක්ටෙල්

6
සාමාන්‍ය ව්‍යුහය මගේ පොතේ කිසිදු විකාරයක් හෝ සීමාවක් නොවේ. එය අවුල් සහගත හා කැත විය හැකි බව මම දනිමි, නමුත් ඔබට එය යම් දෙයක “අර්ථ දැක්වීමක්” ලෙස හැඳින්විය හැකිය. ගතික භාෂාවන් මට අරාජිකවාදීන් මෙන් පෙනේ: සෑම කෙනෙකුම නිදහස් බව සහතිකයි, නමුත් ඔබට කුණු කූඩය හිස් කර පාර සකස් කිරීමට යමෙකු අවශ්‍ය වේ. අනුමාන කරන්න මට වයසයි ... :)
ඇන්ඩ්‍රියාස්ට්

4
ශ්‍රිත අර්ථ දැක්වීම මොඩියුලය පැටවීමේ වේලාවේදී ක්‍රියාත්මක වේ. ක්‍රියාකාරී ශරීරය ක්‍රියාකාරී ඇමතුම් වේලාවේදී ක්‍රියාත්මක වේ. පෙරනිමි තර්කය යනු ශ්‍රිත අර්ථ දැක්වීමේ කොටසකි. (කැදැලි කාර්යයන් සඳහා එය වඩාත් සංකීර්ණ වේ.)
ලුට්ස් ප්‍රීචෙල්ට්

84

හොඳයි, හේතුව සරලවම කේතය ක්‍රියාත්මක කරන විට බන්ධන සිදු කිරීමත්, ශ්‍රිත අර්ථ දැක්වීම ක්‍රියාත්මක කිරීමත් හොඳයි ... කාර්යයන් අර්ථ දක්වන විට.

මෙය සසඳා බලන්න:

class BananaBunch:
    bananas = []

    def addBanana(self, banana):
        self.bananas.append(banana)

මෙම කේතය හරියටම අනපේක්ෂිත සිදුවීම් වලින් පීඩා විඳිති. කෙසෙල් යනු පන්ති ගුණාංගයක් වන අතර, එබැවින් ඔබ එයට දේවල් එකතු කළ විට එය එම පන්තියේ සියලුම අවස්ථාවන්ට එකතු වේ. හේතුව හරියටම සමාන ය.

එය හුදෙක් "එය ක්‍රියා කරන ආකාරය" වන අතර, එය ක්‍රියාකාරී අවස්ථාවෙහිදී වෙනස් ආකාරයකින් ක්‍රියා කිරීම බොහෝ විට සංකීර්ණ වනු ඇත, සහ පන්ති නඩුවේදී එය කළ නොහැකි විය හැකිය, නැතහොත් අවම වශයෙන් වස්තු ක්ෂණිකකරණය මන්දගාමී වේ, ඔබට පන්ති කේතය වටා තබා ගත යුතුය. වස්තූන් නිර්මාණය වූ විට එය ක්‍රියාත්මක කරන්න.

ඔව්, එය අනපේක්ෂිතයි. සතයක් පහත වැටුණු පසු, එය සාමාන්‍යයෙන් පයිතන් ක්‍රියා කරන ආකාරය සමඟ හොඳින් ගැලපේ. ඇත්ත වශයෙන්ම, එය හොඳ ඉගැන්වීමේ ආධාරකයක් වන අතර, මෙය සිදුවන්නේ මන්දැයි ඔබ තේරුම් ගත් පසු, ඔබ පයිතන් වඩා හොඳ වනු ඇත.

ඕනෑම හොඳ පයිතන් නිබන්ධනයක එය කැපී පෙනෙන ලෙස දැක්විය යුතු බව එයින් කියැවිණි. ඔබ සඳහන් කළ පරිදි, සෑම කෙනෙකුම ඉක්මනින් හෝ පසුව මෙම ගැටලුවට මුහුණ දෙයි.


පංතියක එක් එක් අවස්ථාව සඳහා වෙනස් වන පන්ති ලක්ෂණයක් ඔබ අර්ථ දක්වන්නේ කෙසේද?
කියෙව්ලි

19
එය එක් එක් අවස්ථාව සඳහා වෙනස් නම් එය පන්ති ලක්ෂණයක් නොවේ. පන්ති ගුණාංග යනු පන්තියේ ගුණාංග වේ. එබැවින් නම. එබැවින් ඒවා සියලු අවස්ථාවන් සඳහා එක හා සමාන වේ.
ලෙනාට් රෙජෙබ්‍රෝ

1
පංතියක එක් එක් අවස්ථාව සඳහා වෙනස් වන පන්තියක ලක්ෂණයක් ඔබ අර්ථ දක්වන්නේ කෙසේද? (පයිතන්ගේ නම් කිරීමේ සම්මුතීන් ගැන නොදන්නා අයෙකු පන්තියක සාමාන්‍ය සාමාජික විචල්‍යයන් ගැන විමසනු ඇතැයි තීරණය කළ නොහැකි අය සඳහා නැවත අර්ථ දක්වා ඇත).
කියෙව්ලි

Ie කීවීලි: ඔබ කතා කරන්නේ පන්තියක සාමාන්‍ය සාමාජික විචල්‍යයන් ගැන ය. :-) ඔබ ඕනෑම ක්‍රමයකින් self.attribute = අගය කියමින් නිදර්ශන ගුණාංග අර්ථ දක්වයි. උදාහරණයක් ලෙස __init __ ().
ලෙනාට් රෙජෙබ්‍රෝ

Ive කීවේලි: පිළිතුරු දෙකක්: ඔබට බැහැ, මන්ද ඔබ පන්ති මට්ටමින් අර්ථ දක්වන ඕනෑම දෙයක් පන්ති ලක්ෂණයක් වන අතර, එම ගුණාංගයට ප්‍රවේශ වන ඕනෑම අවස්ථාවක් එකම පන්තියේ ගුණාංගයට ප්‍රවේශ වේ; propertys භාවිතා කිරීමෙන් ඔබට / වර්ග කිරීම / කළ හැකිය - ඒවා ඇත්ත වශයෙන්ම පන්ති මට්ටමේ කාර්යයන් වන අතර එය සාමාන්‍ය ගුණාංග මෙන් ක්‍රියා කරන නමුත් පන්තිය වෙනුවට උදාහරණය තුළ ගුණාංගය සුරකින්න ( self.attribute = valueලෙනාට් පැවසූ පරිදි භාවිතා කිරීමෙන් ).
ඊතන් ෆුරමන්

68

ඇයි ඔබ ස්වයං විග්‍රහ කරන්නේ නැත්තේ?

මම ඇත්තටම පුදුම වෙනවා කවුරුත් පයිතන් ( 2සහ3 callables මත අදාළ).

funcඅර්ථ දක්වා ඇති සරල කුඩා ශ්‍රිතයක් :

>>> def func(a = []):
...    a.append(5)

පයිතන් එය හමු වූ විට, එය සිදු කරන පළමු දෙය codeමෙම ශ්‍රිතය සඳහා වස්තුවක් නිර්මාණය කිරීම සඳහා එය සම්පාදනය කිරීමයි . මෙම සම්පාදක පියවර සිදු කරන අතරතුර, පයිතන් * ඇගයීමට ලක් කර පසුව පෙරනිමි තර්ක (මෙහි හිස් ලැයිස්තුවක් ) ශ්‍රිත වස්තුව තුළම ගබඩා[] කරයි . ඉහළම පිළිතුර සඳහන් කළ පරිදි: ලැයිස්තුව aදැන් ශ්‍රිතයේ සාමාජිකයෙකු ලෙස සැලකිය හැකියfunc .

එබැවින්, ලැයිස්තුව පුළුල් වන්නේ කෙසේදැයි විමසා බැලීමට පෙර සහ පසුව යම් ස්වයං විග්‍රහයක් කරමු ක්‍රියාකාරී වස්තුව තුළ . මම මේ Python 3.xසඳහා භාවිතා කරමි , පයිතන් 2 සඳහා ද එය අදාළ වේ ( පයිතන් 2 භාවිතා කරන්න __defaults__හෝ භාවිතා කරන්න func_defaults; ඔව්, එකම දේ සඳහා නම් දෙකක්).

ක්‍රියාත්මක කිරීමට පෙර ක්‍රියාකාරිත්වය:

>>> def func(a = []):
...     a.append(5)
...     

පයිතන් මෙම අර්ථ දැක්වීම ක්‍රියාත්මක කිරීමෙන් පසු නිශ්චිතව දක්වා ඇති ඕනෑම පෙරනිමි පරාමිතියක් ගනු ඇත ( a = []මෙහි) සහ තුළ ඒවා එකේ හිර __defaults__උත්සවයට වස්තුව සන්තෝෂය (අදාළ කොටස: Callables):

>>> func.__defaults__
([],)

හරි, ඒ නිසා __defaults__අපේක්ෂිත පරිදි තනි පිවිසුමක් ලෙස හිස් ලැයිස්තුවක් .

ක්‍රියාත්මක කිරීමෙන් පසු ක්‍රියාකාරිත්වය:

දැන් අපි මෙම ශ්‍රිතය ක්‍රියාත්මක කරමු:

>>> func()

දැන් අපි ඒවා __defaults__නැවත බලමු :

>>> func.__defaults__
([5],)

පුදුමයට පත් වූවාද? වස්තුව තුළ වටිනාකම වෙනස් වේ! ශ්‍රිතයට අඛණ්ඩ ඇමතුම් දැන් කාවැද්දූ ඒවාට එකතු වේlist වස්තුවට :

>>> func(); func(); func()
>>> func.__defaults__
([5, 5, 5, 5],)

ඉතින්, එහි ඔබ සතුව ඇත, මෙය සිදුවීමට හේතුව 'දෝෂය' සිදුවීමට හේතුව, පෙරනිමි තර්ක ශ්‍රිත වස්තුවේ කොටසක් වන බැවිනි. මෙහි අමුතු දෙයක් සිදු නොවේ, ඒ සියල්ල මඳක් පුදුමයට කරුණකි.

මෙය වළක්වා ගැනීම සඳහා පොදු විසඳුම වන්නේ Noneපෙරනිමිය ලෙස භාවිතා කර ක්‍රියාකාරී ශරීරය තුළ ආරම්භ කිරීමයි:

def func(a = None):
    # or: a = [] if a is None else a
    if a is None:
        a = []

ක්‍රියාකාරී ශරීරය සෑම විටම අලුතින් ක්‍රියාත්මක වන බැවින්, කිසිදු තර්කයක් ඉදිරිපත් නොකළේ නම් ඔබට සෑම විටම නව හිස් ලැයිස්තුවක් ලැබෙනු ඇත a.


__defaults__ශ්‍රිතය තුළ භාවිතා කර ඇති ලැයිස්තුව සමාන බව තවදුරටත් තහවුරු කර ගැනීම සඳහා, ශ්‍රිත ශරීරය තුළ භාවිතා කළ ලැයිස්තුව funcනැවත ලබා දීම සඳහා ඔබේ ශ්‍රිතය වෙනස් කළ හැකිය . ඉන්පසු, එය (ස්ථානගතව ඇති ) ලැයිස්තුවට සංසන්දනය කරන්න, එවිට මේවා එකම ලැයිස්තු උදාහරණයකට සැබවින්ම යොමු වන්නේ කෙසේදැයි ඔබට පෙනෙනු ඇත:ida__defaults__[0]__defaults__

>>> def func(a = []): 
...     a.append(5)
...     return id(a)
>>>
>>> id(func.__defaults__[0]) == func()
True

සියල්ල ස්වයං විග්‍රහයේ බලයෙන්!


* ශ්‍රිතය සම්පාදනය කිරීමේදී පයිතන් පෙරනිමි තර්ක තක්සේරු කරන බව තහවුරු කර ගැනීම සඳහා, පහත සඳහන් දෑ ක්‍රියාත්මක කිරීමට උත්සාහ කරන්න:

def bar(a=input('Did you just see me without calling the function?')): 
    pass  # use raw_input in Py2

ඔබ දකින පරිදි, input()ශ්‍රිතය ගොඩනඟා එය නමට බැඳීමේ ක්‍රියාවලියට පෙර කැඳවනු barලැබේ.


1
ඇත id(...)පසුගිය සත්යාපනය සඳහා අවශ්ය, හෝ ඇත isක්රියාකරු එම ප්රශ්නයට පිළිතුරු?
das-g

1
as das-g isඉතා හොඳ වනු ඇත, මම එය භාවිතා id(val)කළේ එය වඩාත් බුද්ධිමත් විය හැකි යැයි මා සිතන බැවිනි.
ඩිමිට්‍රිස් ෆසරකිස් හිල්යාඩ්

Noneපෙරනිමිය ලෙස භාවිතා කිරීම __defaults__ස්වයං විග්‍රහයේ ප්‍රයෝජනය දැඩි ලෙස සීමා කරයි , එබැවින් එය කරන ආකාරයට වැඩ කිරීම ආරක්ෂා කිරීමක් ලෙස එය ක්‍රියා කරයි යැයි මම නොසිතමි __defaults__. කම්මැලි-ඇගයීම මඟින් ක්‍රියාකාරී පෙරනිමිති දෙපැත්තෙන්ම ප්‍රයෝජනවත් වේ.
බ්‍රිලියන්ඩ්

58

ධාවන වේලාවේදී වස්තූන් නිර්මාණය කිරීම වඩා හොඳ ප්‍රවේශය වනු ඇතැයි මම සිතුවෙමි. නවක ව්යාකූලත්වය වළක්වා ගැනීම සඳහා එය නොසලකා එය ප්රයෝජනවත් වනු ඇත. එසේ කිරීමේ අවාසි නම්:

1. කාර්ය සාධනය

def foo(arg=something_expensive_to_compute())):
    ...

ඇමතුම් කාල ඇගයීම භාවිතා කරන්නේ නම්, ඔබේ ශ්‍රිතය තර්කයක් නොමැතිව භාවිතා කරන සෑම අවස්ථාවකම මිල අධික ශ්‍රිතය හැඳින්වේ. එක් එක් ඇමතුම සඳහා ඔබ මිල අධික මිලක් ගෙවනු ඇත, නැතහොත් වටිනාකම බාහිරව අතින් හැඹිලිගත කිරීම, ඔබේ නාම අවකාශය දූෂණය කිරීම සහ වාචිකතාව එකතු කිරීම අවශ්‍ය වේ.

2. බැඳී ඇති පරාමිතීන් බල කිරීම

ප්‍රයෝජනවත් උපක්‍රමයක් නම් ලැම්බඩා නිර්මාණය කරන විට ලැම්බඩාවේ පරාමිතීන් විචල්‍යයක වත්මන් බන්ධනයට බන්ධනය කිරීමයි. උදාහරණයක් වශයෙන්:

funcs = [ lambda i=i: i for i in range(10)]

මෙය පිළිවෙලින් 0,1,2,3 ... ආපසු ලබා දෙන ශ්‍රිත ලැයිස්තුවක් ලබා දෙයි. හැසිරීම වෙනස් වුවහොත්, ඒ වෙනුවට ඒවා i iහි ඇමතුම් කාල අගයට බැඳී ඇත , එවිට ඔබට සියල්ල ආපසු ලබා දුන් කාර්යයන් ලැයිස්තුවක් ලැබෙනු ඇත 9.

වෙනත් ආකාරයකින් මෙය ක්‍රියාත්මක කිරීමට ඇති එකම ක්‍රමය වනුයේ මා බැඳී ඇති තවත් වසා දැමීමක් නිර්මාණය කිරීමයි, එනම්:

def make_func(i): return lambda: i
funcs = [make_func(i) for i in range(10)]

3. ස්වයං විමර්ශනය

කේතය සලකා බලන්න:

def foo(a='test', b=100, c=[]):
   print a,b,c

inspectමොඩියුලය භාවිතයෙන් අපට තර්ක සහ පෙරනිමි පිළිබඳ තොරතුරු ලබා ගත හැකිය

>>> inspect.getargspec(foo)
(['a', 'b', 'c'], None, None, ('test', 100, []))

ලේඛන ජනනය, මෙටප්‍රොග්‍රැමිං, සැරසිලි කරුවන් වැනි දේ සඳහා මෙම තොරතුරු ඉතා ප්‍රයෝජනවත් වේ.

දැන්, පෙරනිමි වල හැසිරීම වෙනස් කළ හැකි යැයි සිතමු, මෙය සමාන වන්නේ:

_undefined = object()  # sentinel value

def foo(a=_undefined, b=_undefined, c=_undefined)
    if a is _undefined: a='test'
    if b is _undefined: b=100
    if c is _undefined: c=[]

කෙසේ වෙතත්, අපට introspect කිරීමේ හැකියාව අහිමි, සහ පෙරනිමි තර්ක දේ බලන්න තියෙනවා වේ . වස්තූන් ඉදිකර නොමැති නිසා, ඇත්ත වශයෙන්ම ශ්‍රිතය ඇමතීමෙන් තොරව අපට ඒවා අල්ලා ගත නොහැක. අපට කළ හැකි හොඳම දෙය නම් ප්‍රභව කේතය ගබඩා කර එය නූලක් ලෙස ආපසු ලබා දීමයි.


1
සෑම එකක් සඳහාම අගයක් වෙනුවට පෙරනිමි තර්කය නිර්මාණය කිරීමේ ශ්‍රිතයක් තිබේ නම් ඔබට ස්වයං විග්‍රහයක් කළ හැකිය. පරීක්ෂණ මොඩියුලය එම ශ්‍රිතය අමතයි.
yairchu

Ile සයිලන්ට් හොස්ට්: මම කතා කරන්නේ එය ප්‍රතිනිර්මාණය කිරීම සඳහා හැසිරීම වෙනස් කර ඇත්ද යන්නයි - එය වරක් නිර්මාණය කිරීම වර්තමාන හැසිරීම වන අතර විකෘති පෙරනිමි ගැටළුව පවතින්නේ ඇයිද යන්න ගැන.
බ්‍රයන්

1
ayairchu: එමඟින් උපකල්පනය කරන්නේ ඉදිකිරීම් එතරම්ම ආරක්ෂිත බවයි (එනම් අතුරු ආබාධ නොමැත). මෙම args Introspecting නොකළ යුතුය කරන්න කිසිම දෙයක්, නමුත් අත්තනෝමතික කේතය ඇගයීමට ලක් හොඳින් බලපෑමක් සහිත අවසන් විය.
බ්‍රයන්

1
වෙනස් භාෂා නිර්මාණයක් බොහෝ විට අදහස් කරන්නේ වෙනස් ආකාරයකින් ලිවීමයි. ඔබේ පළමු උදාහරණය පහසුවෙන් මෙසේ ලිවිය හැකිය: _expensive = මිල අධික (); DEF foo (arg = _expensive), ඔබට විශේෂයෙන් නම් නැහැ අවශ්ය එය reevaluated.
ග්ලෙන් මේනාර්ඩ්

@ ග්ලෙන් - මා සඳහන් කළේ "විචල්යය බාහිරව හැඹිලිය" යන්නයි - එය තව ටිකක් වාචික වන අතර, ඔබ අවසන් වන්නේ ඔබේ නාම අවකාශයේ අමතර විචල්යයන් සමඟ ය.
බ්‍රයන්

55

පයිතන් ආරක්ෂා කිරීම සඳහා ලකුණු 5 ක්

  1. සරල බව : පහත දැක්වෙන අර්ථයෙන් හැසිරීම සරල ය: බොහෝ අය මෙම උගුලට වැටෙන්නේ එක් වරක් මිස කිහිප වතාවක් නොවේ.

  2. අනුකූලතාව : පයිතන් සෑම විටම වස්තූන් පසු කරයි, නම් නොවේ. පෙරනිමි පරාමිතිය, පැහැදිලිවම, ශ්‍රිත ශීර්ෂයේ කොටසකි (ක්‍රියාකාරී ශරීරය නොවේ). එබැවින් එය ඇගයීමට ලක් කළ යුත්තේ මොඩියුලය පැටවීමේ වේලාවේදී (සහ මොඩියුලය පැටවීමේ වේලාවේදී පමණි, කැදැල්ලකින් තොරව), ක්‍රියාකාරී ඇමතුම් වේලාවේදී නොවේ.

  3. ප්‍රයෝජනය : ෆ්‍රෙඩ්රික් ලුන්ඩ් “පයිතන්හි පෙරනිමි පරාමිති අගයන්” පිළිබඳ පැහැදිලි කිරීමෙහි පෙන්වා දෙන පරිදි , වර්තමාන හැසිරීම උසස් ක්‍රමලේඛනය සඳහා බෙහෙවින් ප්‍රයෝජනවත් වේ. (අරපිරිමැස්මෙන් භාවිතා කරන්න.)

  4. ප්‍රමාණවත් ලියකියවිලි : වඩාත් මූලික පයිතන් ප්‍රලේඛනය වන නිබන්ධනයේ දී, “කාර්යයන් නිර්වචනය කිරීම පිළිබඳ තවත්” කොටසේ පළමු උපවගන්තියේ දී “වැදගත් අනතුරු ඇඟවීමක්” ලෙස ප්‍රශ්නය ශබ්ද නඟා ප්‍රකාශයට පත් කෙරේ . අනතුරු ඇඟවීම තද අකුරු පවා භාවිතා කරයි, එය ශීර්ෂයන්ට පිටින් කලාතුරකින් යෙදේ. RTFM: සියුම් අත්පොත කියවන්න.

  5. මෙටා ඉගෙනීම : උගුලට වැටීම සැබවින්ම ඉතා ප්‍රයෝජනවත් මොහොතකි (අවම වශයෙන් ඔබ පරාවර්තක ඉගෙන ගන්නෙකු නම්), මන්ද ඔබ පසුව ඉහත “අනුකූලතාව” යන කාරණය වඩා හොඳින් වටහා ගනු ඇති අතර එය ඔබට පයිතන් ගැන බොහෝ දේ උගන්වනු ඇත.


18
මෙම හැසිරීම මගේ නිෂ්පාදනය පිළිබඳ කේතය අවුල් කරමින් සිටින බව සොයා ගැනීමට මට වසරක් ගත විය, මම අහම්බෙන් මෙම සැලසුම් දෝෂයට හසු වන තෙක් සම්පූර්ණ අංගයක් ඉවත් කර අවසන් විය. මම ජැන්ගෝ පාවිච්චි කරනවා. වේදිකා පරිසරය තුළ බොහෝ ඉල්ලීම් නොතිබූ බැවින්, මෙම දෝෂය කිසි විටෙකත් QA කෙරෙහි කිසිදු බලපෑමක් ඇති කළේ නැත. අපි සජීවීව ගොස් එකවර ඉල්ලීම් බොහොමයක් ලැබුණු විට - සමහර උපයෝගිතා කාර්යයන් එකිනෙකාගේ පරාමිතීන් නැවත ලිවීමට පටන් ගත්හ! ආරක්ෂක සිදුරු, දෝෂ සහ නොකළ යුතු දේ.
oriadam

7
ඕරියාඩම්, වරදක් නැත, නමුත් මම කල්පනා කරන්නේ ඔබ මීට පෙර මෙයට නොගොස් පයිතන් ඉගෙන ගත්තේ කෙසේද යන්නයි. මම දැන් පයිතන් ඉගෙන ගනිමින් සිටින අතර, සිදුවිය හැකි අන්තරාය නිල පයිතන් නිබන්ධනයේ සඳහන් කර ඇති අතර පෙරනිමි තර්ක පිළිබඳ පළමු සඳහන සමඟ. (මෙම පිළිතුරේ 4 වන කරුණෙහි සඳහන් කර ඇති පරිදි.) නිෂ්පාදන මෘදුකාංග නිර්මාණය කිරීම සඳහා ඔබ භාවිතා කරන භාෂාවේ නිල ලියකියවිලි කියවීම සදාචාරය අනුකම්පා විරහිත යැයි සිතමි .
වයිල්ඩ්කාඩ්

එසේම, මා කරන ශ්‍රිත ඇමතුමට අමතරව නොදන්නා සංකීර්ණතාවයේ ශ්‍රිතයක් කැඳවනු ලැබීම පුදුමයට කරුණකි.
Vatine

52

මෙම හැසිරීම පහසුවෙන් පැහැදිලි කළ හැක්කේ:

  1. ශ්‍රිතය (පංතිය ආදිය) ප්‍රකාශනය ක්‍රියාත්මක කරනු ලබන්නේ එක් වරක් පමණි, සියලු පෙරනිමි අගය වස්තු නිර්මාණය කරයි
  2. සියල්ල යොමු කර ඇත

නිසා:

def x(a=0, b=[], c=[], d=0):
    a = a + 1
    b = b + [1]
    c.append(1)
    print a, b, c
  1. a වෙනස් නොවේ - සෑම පැවරුම් ඇමතුමකින්ම නව int වස්තුවක් නිර්මාණය වේ - නව වස්තුව මුද්‍රණය වේ
  2. b වෙනස් නොවේ - නව අරාව පෙරනිමි අගයෙන් සාදා මුද්‍රණය කර ඇත
  3. c වෙනස්කම් - එකම වස්තුවක් මත ක්‍රියාත්මක වීම - එය මුද්‍රණය කෙරේ

(ඇත්ත වශයෙන්ම, එකතු කිරීම නරක උදාහරණයකි, නමුත් නිඛිල තවමත් වෙනස් නොවීම මගේ ප්‍රධාන
කරුණයි

B [[ලෙස සකසා ඇති විට, b .__ __ ([1]) ප්‍රතිලාභ එකතු කරන්න [1] පමණක් නොව, ලැයිස්තු විකෘති වුවද, b තවමත් ඉතිරි වේ. මගේ නරක.
ඇනොන්

@ANon: ඇත __iadd__, නමුත් එය int සමඟ ක්‍රියා නොකරයි. ඇත්ත වශයෙන්. :-)
Veky

35

ඔබ අසන්නේ මෙය ඇයි:

def func(a=[], b = 2):
    pass

අභ්‍යන්තරව මෙයට සමාන නොවේ:

def func(a=None, b = None):
    a_default = lambda: []
    b_default = lambda: 2
    def actual_func(a=None, b=None):
        if a is None: a = a_default()
        if b is None: b = b_default()
    return actual_func
func = func()

අපි නොසලකා හරින ෆන්ක් (කිසිවක් නැත, කිසිවක් නැත) යනුවෙන් පැහැදිලිව ඇමතීම හැර.

වෙනත් වචන වලින් කිවහොත්, පෙරනිමි පරාමිතීන් ඇගයීම වෙනුවට, ඒවා එක් එක් ගබඩා නොකරන්නේ ඇයි සහ ශ්‍රිතය හැඳින්වූ විට ඒවා ඇගයීමට ලක් කරන්න.

එක් පිළිතුරක් බොහෝ විට එහි තිබේ - එය පෙරනිමි පරාමිතීන් සහිත සෑම ශ්‍රිතයක්ම වසා දැමීමක් බවට පත් කරයි. එය සියල්ල පරිවර්තකයා තුළ සඟවා තබා ඇති අතර එය සම්පූර්ණයෙන් වසා දැමීමක් නොවුවද, දත්ත කොතැනක හෝ ගබඩා කළ යුතුය. එය මන්දගාමී වන අතර වැඩි මතකයක් භාවිතා කරයි.


6
එය වසා දැමීමක් වීමට අවශ්‍ය නොවනු ඇත - එය සිතීමට වඩා හොඳ ක්‍රමයක් වන්නේ බයිට් කේතය නිර්මාණය කිරීම පෙරනිමි කේතයේ පළමු පේළිය බවට පත් කිරීමයි - සියල්ලට පසු ඔබ එම අවස්ථාවේදීම ශරීරය සම්පාදනය කරයි - කේතය අතර සැබෑ වෙනසක් නැත ශරීරයේ තර්ක සහ කේත තුළ.
බ්‍රයන්

10
ඇත්ත, නමුත් එය තවමත් පයිතන් මන්දගාමී වනු ඇති අතර, පන්ති අර්ථ දැක්වීම් සඳහා ඔබ එයම නොකරන්නේ නම් එය ඇත්තෙන්ම පුදුමයට කරුණක් වනු ඇත, එමඟින් ඔබ මෝඩ ලෙස මන්දගාමී වනු ඇත, ඔබ ක්ෂණිකව ක්‍රියාත්මක වන සෑම අවස්ථාවකම මුළු පන්ති අර්ථ දැක්වීම නැවත ක්‍රියාත්මක කිරීමට සිදුවනු ඇත. පන්තිය. සඳහන් කළ පරිදි, නිවැරදි කිරීම ගැටලුවට වඩා පුදුම සහගත වනු ඇත.
ලෙනාට් රෙජෙබ්‍රෝ

ලෙනාට් සමඟ එකඟ විය. ගයිඩෝ කීමට කැමති බැවින්, සෑම භාෂා අංගයක් හෝ සම්මත පුස්තකාලයක් සඳහාම, එය භාවිතා කරන කෙනෙකු එහි සිටී.
ජේසන් බේකර්

6
දැන් එය වෙනස් කිරීම උමතුවක් වනු ඇත - අපි ගවේෂණය කරන්නේ එය එසේ වන්නේ මන්ද යන්නයි. එය ආරම්භ කිරීම සඳහා ප්‍රමාද වූ පෙරනිමි ඇගයීමක් කළේ නම්, එය පුදුමයට කරුණක් නොවේ. එවැනි හරයක් විග්‍රහ කිරීමේ වෙනස විශාල වශයෙන් හා බොහෝ අපැහැදිලි, සමස්තයක් ලෙස භාෂාවට බලපාන බව නියත වශයෙන්ම සත්‍යයකි.
ග්ලෙන් මේනාර්ඩ්

35

1) "විකෘති පෙරනිමි තර්කයේ" ඊනියා ගැටළුව පොදුවේ පෙන්නුම් කරන විශේෂ උදාහරණයකි:
"මෙම ගැටළුව සමඟ ඇති සියලුම කාර්යයන් සත්‍ය පරාමිතියෙහි සමාන අතුරු ආබාධ ගැටලුවකින් ද පීඩා විඳිති ."
එය ක්‍රියාකාරී වැඩසටහන්කරණ නීතිවලට පටහැනි ය, සාමාන්‍යයෙන් අවිනිශ්චිත වන අතර ඒවා දෙකම එකට සවි කළ යුතුය.

උදාහරණයක්:

def foo(a=[]):                 # the same problematic function
    a.append(5)
    return a

>>> somevar = [1, 2]           # an example without a default parameter
>>> foo(somevar)
[1, 2, 5]
>>> somevar
[1, 2, 5]                      # usually expected [1, 2]

විසඳුමක් : a පිටපතක්
පරම ආරක්ෂිත විසඳුමක් ලබා copyහෝ deepcopyආදාන වස්තුව මුල්ම හා පිටපත සමඟ ඕනෑම දෙයක් කිරීමට.

def foo(a=[]):
    a = a[:]     # a copy
    a.append(5)
    return a     # or everything safe by one line: "return a + [5]"

බොහෝ builtin mutable වර්ග වැනි පිටපතක් ක්රමයක් some_dict.copy()හෝ some_set.copy()හෝ වැනි පහසු පිටපත් කළ හැකි somelist[:]හෝ list(some_list). සෑම වස්තුවක්ම පිටපත් කිරීමෙන් copy.copy(any_object)හෝ වඩාත් ගැඹුරින් පිටපත් කළ හැකිය copy.deepcopy()(විකෘති වස්තුව විකෘති වස්තූන්ගෙන් සෑදී ඇත්නම් එය ප්‍රයෝජනවත් වේ). සමහර වස්තූන් මූලික වශයෙන් පදනම් වී ඇත්තේ "ගොනු" වස්තුව වැනි අතුරු ආබාධ මත වන අතර ඒවා පිටපත් මගින් අර්ථවත් ලෙස ප්‍රතිනිෂ්පාදනය කළ නොහැක. පිටපත් කිරීම

සමාන SO ප්‍රශ්නයක් සඳහා උදාහරණ ගැටළුව

class Test(object):            # the original problematic class
  def __init__(self, var1=[]):
    self._var1 = var1

somevar = [1, 2]               # an example without a default parameter
t1 = Test(somevar)
t2 = Test(somevar)
t1._var1.append([1])
print somevar                  # [1, 2, [1]] but usually expected [1, 2]
print t2._var1                 # [1, 2, [1]] but usually expected [1, 2]

මෙම ශ්‍රිතය මඟින් ආපසු ලබා දුන් උදාහරණයක කිසිදු පොදු ගුණාංගයක එය සුරැකිය යුතු නොවේ . ( නිදසුනක් ලෙස පුද්ගලික ගුණාංග මෙම පන්තියට පිටතින් හෝ උප පංති සම්මුතියෙන් වෙනස් නොකළ යුතු යැයි උපකල්පනය කිරීම ._var1 පුද්ගලික ගුණාංගයකි)

නිගමනය:
ආදාන පරාමිති වස්තු තැනින් තැන වෙනස් නොකළ යුතුය (විකෘති) හෝ ශ්‍රිතය මඟින් ආපසු ලබා දෙන වස්තුවකට ඒවා බැඳ නොගත යුතුය. (දැඩි ලෙස නිර්දේශ කර ඇති අතුරු ආබාධ නොමැතිව වැඩසටහන්කරණයට අපි කැමති නම්. "අතුරු ආබාධ" ගැන විකිය බලන්න. (පළමු ඡේද දෙක මෙම සන්දර්භය තුළ අදාළ වේ.).)

2)
සත්‍ය පරාමිතිය සඳහා අතුරු ආබාධයක් අවශ්‍ය නමුත් පෙරනිමි පරාමිතිය මත අනවශ්‍ය නම් පමණක් ප්‍රයෝජනවත් විසඳුම def ...(var1=None): if var1 is None: var1 = [] තවත් ..

3) සමහර අවස්ථාවල පෙරනිමි පරාමිතීන්ගේ විකෘති හැසිරීම ප්‍රයෝජනවත් වේ .


5
පයිතන් ක්‍රියාකාරී ක්‍රමලේඛන භාෂාවක් නොවන බව ඔබ දන්නා බව මම විශ්වාස කරමි .
වේකි

6
ඔව්, පයිතන් යනු සමහර ක්‍රියාකාරී ලක්ෂණ සහිත බහු-පරමාදර්ශී භාෂාවකි. ("ඔබට මිටියක් ඇති බැවින් සෑම ගැටලුවක්ම නියපොත්තක් මෙන් නොපෙන්වන්න.") ඒවායින් බොහොමයක් පයිතන්හි හොඳම පුහුණුවීම්වල ඇත. පයිතන්ට සිත්ගන්නාසුළු HOWTO ක්‍රියාකාරී ක්‍රමලේඛයක් ඇත. මෙහි සඳහන් කර නොමැති වසා දැමීම් සහ ව්‍යංජන වේ.
හයිනෙකර්

1
අවශ්‍ය අවස්ථාවන්හිදී දත්ත පිටපත් කිරීම වළක්වා ගැනීම සඳහා පයිතන්ගේ පැවරුම් අර්ථ නිරූපණය පැහැදිලිවම නිර්මාණය කර ඇති බවත්, එබැවින් පිටපත් නිර්මාණය කිරීම (සහ විශේෂයෙන් ගැඹුරු පිටපත්) ධාවන කාලය සහ මතක භාවිතය යන දෙකටම අහිතකර ලෙස බලපානු ඇති බවත් මම කියමි. එබැවින් ඒවා භාවිතා කළ යුත්තේ අවශ්‍ය විටෙක පමණි, නමුත් නවකයන්ට එය තේරුම් ගැනීමට අපහසු වේ.
holdenweb

1
@holdenweb මම එකඟයි. තාවකාලික පිටපතක් යනු වඩාත් සුපුරුදු ක්‍රමය වන අතර සමහර විට මුල් විකෘති දත්ත බාහිර ශ්‍රිතයකින් ආරක්ෂා කර ගත හැකි එකම ක්‍රමය ඒවා වෙනස් කළ හැකි ය. වාසනාවකට මෙන් දත්ත අසාධාරණ ලෙස වෙනස් කරන ශ්‍රිතයක් දෝෂයක් ලෙස සලකනු ලබන අතර එබැවින් එය සාමාන්‍ය දෙයකි.
හයිනෙකර්

මම මෙම පිළිතුර සමඟ එකඟ වෙමි. def f( a = None )ඔබ වෙනත් දෙයක් අදහස් කරන විට ඉදිකිරීම් නිර්දේශ කරන්නේ ඇයිදැයි මට තේරෙන්නේ නැත . පිටපත් කිරීම හරි, මන්ද ඔබ තර්ක විකෘති නොකළ යුතුය. ඔබ එසේ කළ විට if a is None: a = [1, 2, 3], ඔබ කෙසේ හෝ ලැයිස්තුව පිටපත් කරයි.
කොඩ්ඩෝ

30

මෙය ඇත්ත වශයෙන්ම පෙරනිමි අගයන් සමඟ කිසිදු සම්බන්ධයක් නැත, හැරෙන්නට ඔබ බොහෝ විට විකෘති පෙරනිමි අගයන් සමඟ කාර්යයන් ලියන විට එය අනපේක්ෂිත හැසිරීමක් ලෙස පෙනේ.

>>> def foo(a):
    a.append(5)
    print a

>>> a  = [5]
>>> foo(a)
[5, 5]
>>> foo(a)
[5, 5, 5]
>>> foo(a)
[5, 5, 5, 5]
>>> foo(a)
[5, 5, 5, 5, 5]

මෙම කේතය තුළ පෙරනිමි අගයන් නොපෙනේ, නමුත් ඔබට හරියටම එකම ගැටළුවකි.

නමුත් ප්රශ්නය නම් fooවේ , සංශෝධනය අමතන්නා මෙම බලාපොරොත්තු නොවන විට, දුරකථන ඇමතුම සිට සම්මත mutable විචල්ය. ශ්‍රිතය මෙවැනි දෙයක් ලෙස හැඳින්වුවහොත් මේ වගේ කේතය හොඳයිappend_5 ; එවිට අමතන්නා විසින් ඔවුන් විසින් ලබා දෙන අගය වෙනස් කිරීම සඳහා ශ්‍රිතය අමතනු ඇති අතර හැසිරීම අපේක්ෂා කෙරේ. නමුත් එවැනි ශ්‍රිතයක් පෙරනිමි තර්කයක් ගැනීමට බොහෝ දුරට ඉඩ ඇති අතර බොහෝ විට ලැයිස්තුව ආපසු නොදෙනු ඇත (අමතන්නාට දැනටමත් එම ලැයිස්තුවට සඳහනක් ඇති බැවින්; එය සම්මත වූ එක).

fooසුපුරුදු තර්කයක් සහිත ඔබේ මුල් පිටපත වෙනස් නොකළ යුතුයa එය පැහැදිලිව සම්මත වී තිබේද නැතහොත් පෙරනිමි අගය ලබාගෙන තිබේද යන්න . තර්ක වෙනස් කළ යුතු යැයි සන්දර්භය / නම / ලියකියවිලි වලින් පැහැදිලි නොවන්නේ නම් ඔබේ කේතය විකෘති තර්ක පමණක් තැබිය යුතුය. දේශීය තාවකාලිකයන් ලෙස තර්ක ලෙස සම්මත කළ හැකි විකෘති අගයන් භාවිතා කිරීම අතිශයින්ම නරක අදහසකි, අප පයිතන්හි සිටියත් නැතත් සහ පෙරනිමි තර්ක තිබේද නැද්ද යන්න.

යමක් ගණනය කිරීමේදී දේශීය තාවකාලික දෙයක් විනාශකාරී ලෙස හැසිරවීමට ඔබට අවශ්‍ය නම්, සහ ඔබේ හැසිරවීම තර්ක අගයකින් ආරම්භ කිරීමට අවශ්‍ය නම්, ඔබ පිටපතක් සෑදිය යුතුය.


7
සම්බන්ධ වුවත්, මම සිතන්නේ මෙය වෙනස් හැසිරීමකි (අප "ස්ථානය" appendවෙනස් කිරීමට අපේක්ෂා කරන පරිදි a). සෑම ඇමතුමකම පෙරනිමි විකෘති නැවත ස්ථාපනය නොකිරීම "අනපේක්ෂිත" බිට් එකයි ... අවම වශයෙන් මට. :)
ඇන්ඩි හේඩන්

2
Nd ඇන්ඩිහෙයිඩන් ශ්‍රිතය තර්කය වෙනස් කිරීමට අපේක්ෂා කරන්නේ නම්, පෙරනිමියක් තිබීම අර්ථවත් වන්නේ ඇයි?
මාර්ක් රැන්සම්

Ark මාක් රැන්සම් මට සිතිය හැකි එකම උදාහරණයයි cache={}. කෙසේ වෙතත්, මෙම "අවම විශ්මය" පැමිණෙන්නේ ඔබ තර්කය විකෘති කිරීමට කැඳවන කාර්යය අපේක්ෂා නොකරන විට (හෝ අවශ්‍ය නොවන) විට යැයි මම සැක කරමි .
ඇන්ඩි හේඩන්

1
Nd ඇන්ඩි හේඩන් එම හැඟීම පුළුල් කිරීමත් සමඟ මම මගේම පිළිතුර මෙහි තැබුවෙමි. ඔබ සිතන්නේ කුමක්දැයි මට දන්වන්න. සම්පූර්ණත්වය සඳහා මම ඔබේ උදාහරණය එයට එකතු කරමි cache={}.
මාර්ක් රැන්සම්

1
Nd ඇන්ඩිහෙයිඩන් මගේ පිළිතුරේ කාරණය නම්, තර්කයේ පෙරනිමි අගය අහම්බෙන් විකෘති කිරීමෙන් ඔබ කවදා හෝ මවිතයට පත් වී ඇත්නම්, ඔබට තවත් දෝෂයක් තිබේ, එනම් පෙරනිමිය භාවිතා නොකළ විට ඔබේ කේතයට අහම්බෙන් අමතන්නාගේ වටිනාකම විකෘති කළ හැකිය . Noneආර්ග් නම් None එම ගැටළුව විසඳන්නේ නැතිනම් සැබෑ පෙරනිමිය භාවිතා කිරීම සහ පැවරීම සැලකිල්ලට ගන්න (එම හේතුව නිසා එය ප්‍රති-රටාවක් ලෙස මම සලකමි). විගණන තර්ක අගයන් පෙරනිමි තිබේද නැද්ද යන්න වළක්වා ගැනීමෙන් ඔබ අනෙක් දෝෂය නිවැරදි කරන්නේ නම්, ඔබ කිසි විටෙකත් මෙම "විශ්මය ජනක" හැසිරීම නොසලකයි.
බෙන්

27

දැනටමත් කාර්යබහුල මාතෘකාවකි, නමුත් මා මෙහි කියවූ දෙයින්, එය අභ්‍යන්තරව ක්‍රියා කරන ආකාරය අවබෝධ කර ගැනීමට පහත සඳහන් දෑ මට උපකාර විය:

def bar(a=[]):
     print id(a)
     a = a + [1]
     print id(a)
     return a

>>> bar()
4484370232
4484524224
[1]
>>> bar()
4484370232
4484524152
[1]
>>> bar()
4484370232 # Never change, this is 'class property' of the function
4484523720 # Always a new object 
[1]
>>> id(bar.func_defaults[0])
4484370232

2
ඇත්ත වශයෙන්ම මෙය නවකයන්ට a = a + [1]අධික බරක් ලෙස තරමක් ව්‍යාකූල විය හැකිය a... එය වෙනස් කර b = a + [1] ; print id(b)රේඛාවක් එක් කරන්න a.append(2). +ලැයිස්තු දෙකකින් සෑම විටම නව ලැයිස්තුවක් (පවරා ඇති b) නිර්මාණය කරන අතර, නවීකරණය කරන ලද ඒවාට aතවමත් සමාන id(a)විය හැකි බව එමඟින් වඩාත් පැහැදිලි වනු ඇත .
ජෝර්න් හීස්

25

එය කාර්ය සාධන ප්‍රශස්තිකරණයකි. මෙම ක්‍රියාකාරීත්වයේ ප්‍රති result ලයක් ලෙස, මෙම ක්‍රියාකාරී ඇමතුම් දෙකෙන් වේගවත් යැයි ඔබ සිතන්නේ කුමක්ද?

def print_tuple(some_tuple=(1,2,3)):
    print some_tuple

print_tuple()        #1
print_tuple((1,2,3)) #2

මම ඔබට ඉඟියක් දෙන්නම්. විසුරුවා හැරීම මෙන්න ( http://docs.python.org/library/dis.html බලන්න ):

#1

0 LOAD_GLOBAL              0 (print_tuple)
3 CALL_FUNCTION            0
6 POP_TOP
7 LOAD_CONST               0 (None)
10 RETURN_VALUE

#2

 0 LOAD_GLOBAL              0 (print_tuple)
 3 LOAD_CONST               4 ((1, 2, 3))
 6 CALL_FUNCTION            1
 9 POP_TOP
10 LOAD_CONST               0 (None)
13 RETURN_VALUE

පළපුරුදු හැසිරීමට ප්‍රායෝගික භාවිතයක් ඇතැයි මට සැකයි (දෝෂ බෝ නොකර C හි ස්ථිතික විචල්‍යයන් සැබවින්ම භාවිතා කළේ කවුද?)

ඔබ දැක ගැනීමට හැකි වන පරිදි, එහි වන කාර්ය සාධන ප්රතිලාභ හා අණුවල පැවැත්ම පෙරනිමි තර්ක භාවිතා කරන විට. මෙය නිතර හඳුන්වන ශ්‍රිතයක් නම් හෝ පෙරනිමි තර්කය සෑදීම සඳහා බොහෝ කාලයක් ගත වුවහොත් මෙය වෙනසක් කළ හැකිය. පයිතන් සී නොවන බව මතක තබා ගන්න. සී හි ඔබට නියතයන් තිබේ. පයිතන්හි ඔබට මෙම ප්‍රතිලාභය නොමැත.


24

පයිතන්: විකෘති පෙරනිමි තර්කය

ශ්‍රිතය ශ්‍රිත වස්තුවකට සම්පාදනය කරන අවස්ථාවේදී පෙරනිමි තර්ක ඇගයීමට ලක් වේ. ශ්‍රිතය භාවිතා කරන විට, එම ශ්‍රිතය මඟින් කිහිප වතාවක්, ඒවා එකම වස්තුවක් ලෙස පවතී.

ඒවා විකෘති වූ විට, විකෘති වූ විට (නිදසුනක් ලෙස එයට මූලද්‍රව්‍යයක් එකතු කිරීමෙන්) අඛණ්ඩ ඇමතුම් වලදී ඒවා විකෘති වී පවතී.

සෑම විටම එකම වස්තුවක් වන නිසා ඒවා විකෘති වී ඇත.

සමාන කේතය:

ශ්‍රිත වස්තුව සම්පාදනය කර ක්ෂණිකව ක්‍රියාත්මක වන විට ලැයිස්තුව ශ්‍රිතයට බැඳී ඇති හෙයින්, මෙය:

def foo(mutable_default_argument=[]): # make a list the default argument
    """function that uses a list"""

මෙය හරියටම පාහේ සමාන වේ:

_a_list = [] # create a list in the globals

def foo(mutable_default_argument=_a_list): # make it the default argument
    """function that uses a list"""

del _a_list # remove globals name binding

නිරූපණය

මෙන්න නිරූපණයක් - ඒවා යොමු කරන සෑම අවස්ථාවකම ඒවා එකම වස්තුවක් බව ඔබට තහවුරු කර ගත හැකිය

  • ශ්‍රිතය ශ්‍රිත වස්තුවකට සම්පාදනය කිරීමට පෙර ලැයිස්තුව නිර්මාණය වී ඇති බව දැකීම,
  • ලැයිස්තුව සඳහන් කරන සෑම අවස්ථාවකම හැඳුනුම්පත සමාන බව නිරීක්ෂණය කරමින්,
  • එය භාවිතා කරන ශ්‍රිතය දෙවන වරට හැඳින්වූ විට ලැයිස්තුව වෙනස් වන බව නිරීක්ෂණය කිරීම,
  • ප්‍රභවයෙන් ප්‍රතිදානය මුද්‍රණය කර ඇති අනුපිළිවෙල නිරීක්ෂණය කිරීම (මම ඔබට පහසුවෙන්ම අංකනය කර ඇති):

example.py

print('1. Global scope being evaluated')

def create_list():
    '''noisily create a list for usage as a kwarg'''
    l = []
    print('3. list being created and returned, id: ' + str(id(l)))
    return l

print('2. example_function about to be compiled to an object')

def example_function(default_kwarg1=create_list()):
    print('appending "a" in default default_kwarg1')
    default_kwarg1.append("a")
    print('list with id: ' + str(id(default_kwarg1)) + 
          ' - is now: ' + repr(default_kwarg1))

print('4. example_function compiled: ' + repr(example_function))


if __name__ == '__main__':
    print('5. calling example_function twice!:')
    example_function()
    example_function()

සහ එය සමඟ ධාවනය python example.py:

1. Global scope being evaluated
2. example_function about to be compiled to an object
3. list being created and returned, id: 140502758808032
4. example_function compiled: <function example_function at 0x7fc9590905f0>
5. calling example_function twice!:
appending "a" in default default_kwarg1
list with id: 140502758808032 - is now: ['a']
appending "a" in default default_kwarg1
list with id: 140502758808032 - is now: ['a', 'a']

මෙය "අවම විශ්මය" යන මූලධර්මය උල්ලං does නය කරනවාද?

මෙම ක්‍රියාත්මක කිරීමේ අනුපිළිවෙල පයිතන් හි නව පරිශීලකයින්ට නිතරම ව්‍යාකූල වේ. ඔබ පයිතන් ක්‍රියාත්මක කිරීමේ ආකෘතිය තේරුම් ගන්නේ නම්, එය තරමක් බලාපොරොත්තු වේ.

නව පයිතන් භාවිතා කරන්නන්ට සුපුරුදු උපදෙස්:

නව පරිශීලකයින්ට සුපුරුදු උපදෙස් වන්නේ ඒ වෙනුවට ඔවුන්ගේ පෙරනිමි තර්ක නිර්මාණය කිරීමයි.

def example_function_2(default_kwarg=None):
    if default_kwarg is None:
        default_kwarg = []

පෙරනිමිය හැර වෙනත් තර්කයක් අප සතුව තිබේද නැද්ද යන්න ශ්‍රිතයට පැවසීමට මෙය කිසිවක් සිංගල්ටන් සෙන්ඩිනල් වස්තුවක් ලෙස භාවිතා කරයි. අපට තර්කයක් නොලැබුනේ නම්, ඇත්ත වශයෙන්ම අපට []පෙරනිමියෙන් නව හිස් ලැයිස්තුවක් භාවිතා කිරීමට අවශ්‍යය .

ලෙස පාලනය ගලනය මත නිබන්ධනය කොටස පවසයි:

පෙරනිමි ඇමතුම් අතර පෙරනිමිය බෙදා ගැනීමට ඔබට අවශ්‍ය නැතිනම්, ඒ වෙනුවට ඔබට ශ්‍රිතය ලිවිය හැකිය:

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

24

කෙටිම පිළිතුර බොහෝ විට "අර්ථ දැක්වීම ක්‍රියාත්මක කිරීම" විය හැකිය, එබැවින් සමස්ත තර්කයම දැඩි අර්ථයක් නොදක්වයි. වඩාත් සංක්ෂිප්ත උදාහරණයක් ලෙස, ඔබට මෙය උපුටා දැක්විය හැකිය:

def a(): return []

def b(x=a()):
    print x

ප්‍රකාශය ක්‍රියාත්මක කරන අවස්ථාවේදී පෙරනිමි තර්ක ප්‍රකාශන ක්‍රියාත්මක defනොකිරීම පහසු හෝ තේරුමක් නැති බව පෙන්වීමට ප්‍රමාණවත් යැයි සිතමු .

ඔබ සුපුරුදු ඉදිකිරීම්කරුවන් භාවිතා කිරීමට උත්සාහ කරන විට එය ගොචා බව මම එකඟ වෙමි.


20

කිසිවක් භාවිතා නොකරන සරල විසඳුමක්

>>> def bar(b, data=None):
...     data = data or []
...     data.append(b)
...     return data
... 
>>> bar(3)
[3]
>>> bar(3)
[3]
>>> bar(3)
[3]
>>> bar(3, [34])
[34, 3]
>>> bar(3, [34])
[34, 3]

19

ඔබ පහත සඳහන් කරුණු සැලකිල්ලට ගන්නේ නම් මෙම හැසිරීම පුදුමයක් නොවේ:

  1. පැවරුම් උත්සාහයන් මත කියවීමට-පමණක් පන්තියේ ගුණාංගවල හැසිරීම, සහ
  2. කාර්යයන් යනු වස්තූන්ය (පිළිගත් පිළිතුරෙන් හොඳින් පැහැදිලි කර ඇත).

(2) හි කාර්යභාරය මෙම ත්‍රෙඩ් එකේ පුළුල් ලෙස ආවරණය කර ඇත. (1) වෙනත් භාෂාවලින් පැමිණෙන විට මෙම හැසිරීම “බුද්ධිමත්” නොවන බැවින් පුදුමයට හේතු වන සාධකය විය හැකිය.

(1) පන්ති පිළිබඳ පයිතන් නිබන්ධනයේ විස්තර කර ඇත . කියවීමට පමණක් ඇති පන්ති ගුණාංගයකට අගයක් පැවරීමේ උත්සාහයකදී:

... අභ්‍යන්තර විෂය පථයෙන් පිටත සොයාගත හැකි සියලුම විචල්‍යයන් කියවීමට පමණි ( එවැනි විචල්‍යයකට ලිවීමට උත්සාහ කිරීම සරලවම අභ්‍යන්තර විෂය පථය තුළ නව දේශීය විචල්‍යයක් නිර්මාණය කරනු ඇත .

මුල් උදාහරණය වෙත ආපසු හැරී ඉහත කරුණු සලකා බලන්න:

def foo(a=[]):
    a.append(5)
    return a

මෙන්න fooවස්තුවක් වන අතර aඑය foo(ලබා ගත හැකි foo.func_defs[0]) ගුණාංගයකි . aලැයිස්තුවක් බැවින් , aවිකෘති වන අතර එය කියවීමේ-ලිවීමේ ගුණාංගයකි foo. ශ්‍රිතය ක්ෂණිකව ක්‍රියාත්මක වන විට අත්සන මගින් නියම කර ඇති පරිදි එය හිස් ලැයිස්තුවට ආරම්භ කරනු ලබන අතර, ක්‍රියාකාරී වස්තුව පවතින තාක් කල් කියවීමට හා ලිවීමට හැකිය.

ඇමතුම් fooපෙරනිමි වටිනාකම පැහැර භාවිතා ආධිපත්යධාරී තොරව foo.func_defs. මේ අවස්ථාවේ දී, foo.func_defs[0]සඳහා භාවිතා කරනු ඇත aකාර්යය වස්තුවක් කේතය විෂය පථය තුල. වෙනස් කිරීම සඳහා වන aවෙනස්කම් foo.func_defs[0], එය fooවස්තුවේ කොටසක් වන අතර කේතය ක්‍රියාත්මක කිරීම අතර පවතී foo.

දැන්, මෙය වෙනත් භාෂාවල පෙරනිමි තර්ක හැසිරීම අනුකරණය කිරීමේ ප්‍රලේඛනයේ උදාහරණය සමඟ සසඳන්න , එනම් ශ්‍රිතය ක්‍රියාත්මක වන සෑම අවස්ථාවකම ශ්‍රිත අත්සන පෙරනිමි භාවිතා කරනු ලැබේ:

def foo(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

ගනිමින් (1) සහ (2) මේ අපේක්ෂිත හැසිරීම ඉටු ඇයි සැලකිල්ලට, විය හැකි:

  • fooශ්‍රිත වස්තුව ක්ෂණිකව ක්‍රියාත්මක කළ විට , වෙනස් කළ නොහැකි වස්තුවකට foo.func_defs[0]සකසා ඇත None.
  • පෙරනිමිය සමඟ ශ්‍රිතය ක්‍රියාත්මක වන විට ( Lශ්‍රිත ඇමතුමෙහි කිසිදු පරාමිතියක් නිශ්චිතව දක්වා නැත ), foo.func_defs[0]( None) දේශීය විෂය පථයෙන් ලබා ගත හැකිය L.
  • පසුව L = [], පැවරුම සාර්ථක විය නොහැක foo.func_defs[0], මන්ද එම ගුණාංගය කියවීමට පමණි.
  • එක් (1) , නව දේශීය විචල්ය ද නම් Lදේශීය විෂය පථය තුල නිර්මාණය වන මෙම උත්සවයට ඇමතුමක් ඉතිරි සඳහා භාවිතා. foo.func_defs[0]මේ අනුව අනාගත ආයාචනා සඳහා නොවෙනස්ව පවතී foo.

19

පෙරනිමි ලැයිස්තු අගයක් ශ්‍රිතයකට යැවීම සඳහා මම විකල්ප ව්‍යුහයක් නිරූපණය කිරීමට යන්නෙමි (එය ශබ්දකෝෂ සමඟ සමානව ක්‍රියා කරයි).

අනෙක් අය පුළුල් ලෙස අදහස් දක්වා ඇති පරිදි, ලැයිස්තු පරාමිතිය එය ක්‍රියාත්මක වන විට ඊට ප්‍රතිවිරුද්ධ ලෙස අර්ථ දක්වා ඇති විට එය ශ්‍රිතයට බැඳී ඇත. ලැයිස්තු සහ ශබ්ද කෝෂ විකෘති බැවින්, මෙම පරාමිතිය වෙනස් කිරීම මෙම ශ්‍රිතයේ වෙනත් ඇමතුම් වලට බලපායි. එහි ප්‍රති As ලයක් ලෙස, ශ්‍රිතයට පසුව ලැබෙන ඇමතුම් වලට මෙම හවුල් ලැයිස්තුව ලැබෙනු ඇත, එය ශ්‍රිතයට වෙනත් ඇමතුම් මගින් වෙනස් කර ඇත. ඊටත් වඩා භයානක දෙය නම්, පරාමිතීන් දෙකක් මෙම ශ්‍රිතයේ හවුල් පරාමිතිය එකවර භාවිතා කරන අතර අනෙකා විසින් සිදුකරන ලද වෙනස්කම් නොසලකා හැරීමයි.

වැරදි ක්‍රමය (බොහෝ විට ...) :

def foo(list_arg=[5]):
    return list_arg

a = foo()
a.append(6)
>>> a
[5, 6]

b = foo()
b.append(7)
# The value of 6 appended to variable 'a' is now part of the list held by 'b'.
>>> b
[5, 6, 7]  

# Although 'a' is expecting to receive 6 (the last element it appended to the list),
# it actually receives the last element appended to the shared list.
# It thus receives the value 7 previously appended by 'b'.
>>> a.pop()             
7

ඒවා භාවිතා කිරීමෙන් ඒවා එකම වස්තුවක් බව ඔබට තහවුරු කර ගත හැකිය id:

>>> id(a)
5347866528

>>> id(b)
5347866528

බ්‍රෙට් ස්ලැට්කින්ගේ “ P ලදායී පයිතන්: වඩා හොඳ පයිතන් ලිවීමට නිශ්චිත ක්‍රම 59”, අයිතමය 20: Noneගතික පෙරනිමි තර්ක නියම කිරීම සඳහා භාවිතා කිරීම සහ ලේඛනය කිරීම (පිටුව 48)

පයිතන් හි අපේක්ෂිත Noneප්‍රති result ලය ලබා ගැනීම සඳහා වන සම්මුතිය වන්නේ පෙරනිමි අගය සැපයීම සහ ලේඛනයේ සත්‍ය හැසිරීම ලේඛනගත කිරීමයි.

මෙම ක්‍රියාවට නැංවීම මඟින් ශ්‍රිතයට කෙරෙන සෑම ඇමතුමකටම පෙරනිමි ලැයිස්තුවක් ලැබෙනු ඇති බවට සහතික වේ.

කැමති ක්‍රමය :

def foo(list_arg=None):
   """
   :param list_arg:  A list of input values. 
                     If none provided, used a list with a default value of 5.
   """
   if not list_arg:
       list_arg = [5]
   return list_arg

a = foo()
a.append(6)
>>> a
[5, 6]

b = foo()
b.append(7)
>>> b
[5, 7]

c = foo([10])
c.append(11)
>>> c
[10, 11]

ක්‍රමලේඛකයා විසින් පෙරනිමි ලැයිස්තු පරාමිතිය බෙදා ගැනීමට අදහස් කරන 'වැරදි ක්‍රමය' සඳහා නීත්‍යානුකූල භාවිත අවස්ථා තිබිය හැකි නමුත් මෙය නීතියට වඩා ව්‍යතිරේකයකි.


17

මෙහි විසඳුම්:

  1. Noneඔබගේ පෙරනිමි අගය ලෙස (හෝ නොන්ස් object) භාවිතා කරන්න , සහ ධාවන වේලාවේදී ඔබේ අගයන් නිර්මාණය කිරීමට එය ක්‍රියාත්මක කරන්න; හෝ
  2. lambdaඔබගේ පෙරනිමි පරාමිතිය ලෙස භාවිතා කරන්න , පෙරනිමි අගය ලබා ගැනීම සඳහා එය උත්සාහක වාරණයක් තුළ අමතන්න (මෙය ලැම්බඩා වියුක්ත කිරීම සඳහා වන දෙයයි).

දෙවන විකල්පය හොඳයි, මන්ද ශ්‍රිතයේ පරිශීලකයින්ට ඇමතිය හැකි ආකාරයෙන් සමත් විය හැකි අතර එය දැනටමත් පවතින (අ වැනි type)


16

වස්තුව ප්‍රතිස්ථාපනය කිරීමෙන් ඔබට මෙය වට කර ගත හැකිය (එම නිසා විෂය පථය සමඟ ටයි පටිය):

def foo(a=[]):
    a = list(a)
    a.append(5)
    return a

කැත, නමුත් එය ක්රියා කරයි.


3
ශ්‍රිතය මඟින් අපේක්ෂා කරන තර්ක වර්ග ලේඛනගත කිරීම සඳහා ඔබ ස්වයංක්‍රීය ප්‍රලේඛන උත්පාදන මෘදුකාංග භාවිතා කරන අවස්ථාවන්හිදී මෙය කදිම විසඳුමකි. A = කිසිවක් නොතබන අතර, [කිසිවක් නොමැති නම් [] ලෙස සැකසීම පා er කයාට බැලූ බැල්මට අපේක්ෂා කරන දේ තේරුම් ගැනීමට උපකාරී නොවේ.
මයිකල් ස්කොට් කත්බර්ට්

සිසිල් අදහස: එම නම නැවත සකස් කිරීමෙන් එය කිසි විටෙකත් වෙනස් කළ නොහැකි බව සහතික කරයි. මම ඇත්තටම ඒකට කැමතියි.
holdenweb

මෙය හරියටම කළ යුතු ක්‍රමයයි. පයිතන් පරාමිතියේ පිටපතක් සාදන්නේ නැත, එබැවින් පිටපත පැහැදිලිවම සෑදීම ඔබ සතුය. ඔබ සතුව පිටපතක් ලැබුණු පසු, අනපේක්ෂිත අතුරු ආබාධ නොමැතිව ඔබ කැමති පරිදි වෙනස් කිරීම ඔබගේ ය.
මාර්ක් රැන්සම්

16

අප මෙය කරන විට:

def foo(a=[]):
    ...

... තර්කය අපි නියම aෙවත නම සඳහන් නොකල අමතන්නා වූ වටිනාකම සමත් නොවේ නම්, ලැයිස්තුව.

මෙම සාකච්ඡාව සඳහා දේවල් සරල කිරීම සඳහා, අපි තාවකාලිකව නම් නොකළ ලැයිස්තුවට නමක් දෙමු. කොහොමද pavlo?

def foo(a=pavlo):
   ...

ඕනෑම වේලාවක, අමතන්නා අපට කුමක්දැයි නොකියන්නේ aනම්, අපි නැවත භාවිතා කරමු pavlo.

නම් pavlomutable (modifiable) වන අතර, fooඑය වෙනස් කිරීම දක්වා අවසන්, අපි ඉදිරි කාලය නිරීක්ෂණය බලපෑමක් fooනියම තොරව ලෙස හැඳින්වේ a.

එබැවින් ඔබ දකින දේ මෙයයි (මතක තබා ගන්න, pavloආරම්භ කර ඇත්තේ []):

 >>> foo()
 [5]

දැන්, pavlo[5] වේ.

foo()නැවත ඇමතීම නැවත වෙනස් කරයි pavlo:

>>> foo()
[5, 5]

ඇමතුම සහතික aකිරීමේදී ස්පර්ශ නොකෙරේ.foo()pavlo

>>> ivan = [1, 2, 3, 4]
>>> foo(a=ivan)
[1, 2, 3, 4, 5]
>>> ivan
[1, 2, 3, 4, 5]

ඉතින්, pavloතවමත් [5, 5].

>>> foo()
[5, 5, 5]

16

පහත දැක්වෙන රටාවට විකල්පයක් ලෙස මම සමහර විට මෙම හැසිරීම ගසාකමි.

singleton = None

def use_singleton():
    global singleton

    if singleton is None:
        singleton = _make_singleton()

    return singleton.use_me()

singletonභාවිතා කරන්නේ පමණක් නම් use_singleton, ආදේශකයක් ලෙස මම පහත රටාවට කැමතියි:

# _make_singleton() is called only once when the def is executed
def use_singleton(singleton=_make_singleton()):
    return singleton.use_me()

බාහිර සම්පත් වෙත ප්‍රවේශ වන සේවාදායක පංති ස්ථාපනය කිරීම සඳහා සහ මතක තබා ගැනීම සඳහා නියෝග හෝ ලැයිස්තු නිර්මාණය කිරීම සඳහා මම මෙය භාවිතා කර ඇත්තෙමි.

මෙම රටාව හොඳින් දන්නා බව මම නොසිතන හෙයින්, අනාගත වැරදි වැටහීම් වලින් ආරක්ෂා වීමට මම කෙටි අදහසක් ඉදිරිපත් කරමි.


2
මතක තබා ගැනීම සඳහා සැරසිලි කරුවෙකු එක් කිරීමට මම කැමැත්තෙමි, මතක සටහන් හැඹිලිය ක්‍රියාකාරී වස්තුවටම දමන්න.
ස්ටෙෆානෝ බෝරිනි

මෙම උදාහරණය ඔබ පෙන්වන වඩාත් සංකීර්ණ රටාව ප්‍රතිස්ථාපනය නොකරයි, මන්ද ඔබ _make_singletonපෙරනිමි තර්ක උදාහරණයේ දී ඩෙෆ් වේලාවට කතා කරන නමුත් ගෝලීය උදාහරණයේ ඇමතුම් වේලාවට ය. සත්‍ය ආදේශකයක් මඟින් පෙරනිමි තර්ක අගය සඳහා යම් ආකාරයක විකෘති කොටුවක් භාවිතා කරනු ඇත, නමුත් තර්කය එකතු කිරීම විකල්ප අගයන් පසු කිරීමට අවස්ථාවක් ලබා දෙයි.
යාන් වර්නියර්

13

එය සත්‍යයක් විය හැකිය:

  1. කවුරුහරි සෑම භාෂා / පුස්තකාල අංගයක්ම භාවිතා කරයි, සහ
  2. මෙහි හැසිරීම මාරු කිරීම වැරදි ලෙස උපදෙස් දෙනු ඇත, නමුත්

ඉහත අංග දෙකම තදින් අල්ලාගෙන සිටීම සහ තවත් කරුණක් ඉදිරිපත් කිරීම සම්පූර්ණයෙන්ම අනුකූල වේ:

  1. එය ව්‍යාකූල අංගයක් වන අතර එය පයිතන්හි අවාසනාවකි.

අනෙක් පිළිතුරු, හෝ අවම වශයෙන් සමහර ඒවා ලකුණු 1 සහ 2 නමුත් 3 නොව, හෝ ලක්ෂ්‍ය 3 සහ පහත් ලකුණු 1 සහ 2 සාදයි. නමුත් මේ තුනම සත්‍ය වේ.

මෙහි මැදට අශ්වයන් මාරු කිරීම සැලකිය යුතු බිඳීමක් ඉල්ලා සිටින බව සත්‍යයක් විය හැකි අතර, ස්ටෙෆානෝගේ ආරම්භක ස්නිපටය බුද්ධිමත්ව හැසිරවීමට පයිතන් වෙනස් කිරීමෙන් තවත් ගැටලු ඇතිවිය හැකිය. පයිතන් අභ්‍යන්තරය හොඳින් දන්නා කෙනෙකුට එහි ප්‍රතිවිපාක පිළිබඳ බිම් බෝම්බයක් පැහැදිලි කළ හැකි බව සත්‍යයක් විය හැකිය. කෙසේවෙතත්,

පවත්නා හැසිරීම පයිතොනික් නොවන අතර පයිතන් සාර්ථක වන්නේ භාෂාව පිළිබඳ ඉතා සුළු ප්‍රමාණයක් ඕනෑම තැනක අවම වශයෙන් විස්මයට පත් කිරීමේ මූලධර්මය උල්ලං lates නය කරන බැවිනි ආසන්නයේමෙය නරක ලෙස. එය මුලිනුපුටා දැමීම wise ානවන්තද නැද්ද යන්න සැබෑ ගැටළුවකි. එය නිර්මාණ දෝෂයකි. හැසිරීම සොයා ගැනීමට උත්සාහ කිරීමෙන් ඔබ භාෂාව වඩා හොඳින් තේරුම් ගන්නේ නම්, මට කිව හැකිය C ++ මේ සියල්ල සහ තවත් බොහෝ දේ කරයි; සැරිසැරීමෙන් ඔබ බොහෝ දේ ඉගෙන ගන්නවා, උදාහරණයක් ලෙස, සියුම් දර්ශක දෝෂ. නමුත් මෙය පයිතොනික් නොවේ: මෙම හැසිරීම හමුවේ නොපසුබට උත්සාහයක් දැරීමට තරම් පයිතන් ගැන සැලකිලිමත් වන අය භාෂාවට ඇදී යන අය වන්නේ පයිතන්ට වෙනත් භාෂාවන්ට වඩා විස්මයන් අඩු නිසාය. ඩබ්ලර්ස් සහ කුතුහලය දනවන අය පයිතොනිස්ටා බවට පත්වන්නේ යමක් වැඩ කිරීමට කොපමණ කාලයක් ගතවේද යන්න ගැන මවිතයට පත්වන විටය - මෝස්තරයක් නිසා නොවේ - මම අදහස් කළේ සැඟවුණු තාර්කික ප්‍රහේලිකාවකි - එය පයිතන් වෙත ඇදී යන ක්‍රමලේඛකයින්ගේ අභිප්‍රායන් කපා හැරේ. මොකද ඒක වැඩ කරනවා .


6
1 ක defensible ඉදිරිදර්ශනය, මෙම නොවන පිළිතුර වුවද, සහ මම ඒ අදහස්වලට එකඟ වන්නේ නැහැ. විශේෂ ව්‍යතිරේකයන් ඕනෑවට වඩා ඔවුන්ගේම කෙළවරේ ඇති වේ.
මාර්සින්

3
එසේ නම්, ශ්‍රිතය හැඳින්වෙන සෑම අවස්ථාවකම පයිතන්හි [] හි පෙරනිමි තර්කයක් [] [පැවතීම] වඩා අර්ථවත් වනු ඇතැයි පැවසීම “පුදුම සහගත ලෙස නොදැනුවත්කම” ද?
ක්‍රිස්ටෝස් හේවර්ඩ්

3
අවාසනාවන්ත මෝඩයෙකු ලෙස පෙරනිමි තර්කයක් කිසිවක් ලෙස සැකසීම නොදැනුවත්කමකි, පසුව ශ්‍රිතය සැකසීමේදී ශරීරයේ ශරීරය තුළ තර්කය == කිසිවක් නැත: තර්කය = []? අහිංසක නවකයෙකු අපේක්ෂා කරන දේ බොහෝ විට මිනිසුන්ට අවශ්‍ය බැවින් මෙම මෝඩකම අවාසනාවන්ත ලෙස සැලකීම නොදැනුවත්කමින්, ඔබ f (තර්කය = []) පවරන්නේ නම්, තර්කය ස්වයංක්‍රීයව පෙරනිමියෙන් [] හි අගයක් ගනීද?
ක්‍රිස්ටෝස් හේවර්ඩ්

3
නමුත් පයිතන්හි, භාෂාවේ ආත්මයේ කොටසක් නම්, ඔබ වැඩි ගැඹුරට කිමිදිය යුතු නැත; array.sort () ක්‍රියා කරන අතර, වර්ග කිරීම, බිග්-ඕ සහ නියතයන් පිළිබඳව ඔබ කෙතරම් අවබෝධ කර ගත්තද ක්‍රියා නොකරයි. අරා වර්ග කිරීමේ යාන්ත්‍රණයේ ඇති පයිතන්ගේ සුන්දරත්වය, ගණන් කළ නොහැකි උදාහරණ වලින් එකක් නම්, ඔබ අභ්‍යන්තරයට ගැඹුරට කිමිදීම අවශ්‍ය නොවේ. එය වෙනස් ලෙස කිවහොත්, පයිතන්ගේ සුන්දරත්වය නම්, යන්තම් ක්‍රියා කරන දෙයක් ලබා ගැනීම සඳහා යමෙකු ගැඹුරට කිමිදීම අවශ්‍ය නොවේ. තවද ක්‍රියාමාර්ගයක් ඇත (... තර්කය නම් == කිසිවක් නැත: තර්කය = []), අසාර්ථකයි.
ක්‍රිස්ටෝස් හේවර්ඩ්

3
ස්වාධීනව, ප්‍රකාශයේ x=[]තේරුම "හිස් ලැයිස්තු වස්තුවක් සාදන්න, සහ 'x' යන නාමය එයට බැඳ තබන්න." එබැවින්, def f(x=[])හිස් ලැයිස්තුවක් ද සාදනු ලැබේ. එය සැමවිටම x ට බැඳී නැත, ඒ වෙනුවට එය පෙරනිමි අන්‍යාගමිකයට බැඳී ඇත. පසුව f () ලෙස හැඳින්වූ විට, පෙරනිමිය පිටතට ඇදගෙන x ට බැඳී ඇත. එය හිස් ලැයිස්තුවෙන් ඉවතට විසිවී ගිය හෙයින්, x සමඟ බැඳීමට ඇති එකම දෙය එම ලැයිස්තුවම වන අතර, එහි කිසිවක් සිරවී තිබේද නැද්ද යන්න. එය වෙනත් ආකාරයකින් විය හැක්කේ කෙසේද?
ජෙරී බී

10

මෙය නිර්මාණ දෝෂයක් නොවේ . මේ හරහා ගමන් කරන ඕනෑම අයෙක් වැරදි දෙයක් කරයි.

ඔබට මෙම ගැටලුවට මුහුණ දිය හැකි අවස්ථා 3 ක් ඇත:

  1. ශ්‍රිතයේ අතුරු as ලයක් ලෙස තර්කය වෙනස් කිරීමට ඔබ අදහස් කරයි. මෙම අවස්ථාවේ දී පෙරනිමි තර්කයක් තිබීම කිසි විටෙකත් අර්ථවත් නොවේ . එකම ව්‍යතිරේකය වන්නේ ඔබ ශ්‍රිත ගුණාංග ඇති බවට තර්ක ලැයිස්තුව අනිසි ලෙස භාවිතා කරන විට, උදා cache={}, ඔබ කිසිසේත්ම සත්‍ය තර්කයක් සමඟ ශ්‍රිතය ඇමතීමට බලාපොරොත්තු නොවනු ඇත.
  2. ඔබ අනූන තර්කය ඉවත් කිරීමට අදහස් කරන්නේ නම්, නමුත් අහම්බෙන් ඔබ කළේ එය වෙනස් කරගත හැක. එය දෝෂයකි, එය නිවැරදි කරන්න.
  3. ශ්‍රිතය තුළ භාවිතා කිරීම සඳහා වන තර්කය වෙනස් කිරීමට ඔබ අදහස් කළ නමුත්, වෙනස් කිරීම ශ්‍රිතයෙන් පිටත දැකිය හැකි යැයි අපේක්ෂා කළේ නැත. එවැනි අවස්ථාවකදී ඔබ තර්කයේ පිටපතක් සෑදිය යුතුය , එය පෙරනිමියද නැද්ද යන්න! පයිතන් යනු ඇමතුමකින් වටිනා භාෂාවක් නොවන බැවින් එය ඔබ වෙනුවෙන් පිටපතක් සාදන්නේ නැත, ඔබ ඒ පිළිබඳව පැහැදිළි විය යුතුය.

ප්‍රශ්නයේ උදාහරණය 1 හෝ 3 කාණ්ඩයට අයත් විය හැකිය. එය සම්මත කළ ලැයිස්තුව වෙනස් කර නැවත ලබා දීම අමුතු දෙයක්; ඔබ එකක් හෝ වෙනත් එකක් තෝරා ගත යුතුය.


"වැරදි දෙයක් කිරීම" යනු රෝග විනිශ්චයයි. එයින් කියැවුණේ, වේලාවන් ඇති බව ය. මෙම cache={}රටාව ඇත්තටම, ඔබට මීට අවශ්ය සැබෑ කේතය ලද සම්මුඛ සාකච්ඡාවක-එකම විසඳුම වේ @lru_cache!
ඇන්ඩි හේඩන්

9

මෙම "දෝෂය" මට අතිකාල වැඩ පැය රාශියක් ලබා දුන්නේය! නමුත් මම එය භාවිතා කළ හැකි විභවයක් දැකීමට පටන් ගෙන ඇත (නමුත් එය ක්‍රියාත්මක කිරීමේ වේලාවට පැමිණීමට මා කැමති වනු ඇත, තවමත්)

ප්‍රයෝජනවත් උදාහරණයක් ලෙස මා දකින දේ මම ඔබට දෙන්නම්.

def example(errors=[]):
    # statements
    # Something went wrong
    mistake = True
    if mistake:
        tryToFixIt(errors)
        # Didn't work.. let's try again
        tryToFixItAnotherway(errors)
        # This time it worked
    return errors

def tryToFixIt(err):
    err.append('Attempt to fix it')

def tryToFixItAnotherway(err):
    err.append('Attempt to fix it by another way')

def main():
    for item in range(2):
        errors = example()
    print '\n'.join(errors)

main()

පහත සඳහන් දෑ මුද්‍රණය කරයි

Attempt to fix it
Attempt to fix it by another way
Attempt to fix it
Attempt to fix it by another way

8

ශ්‍රිතය පහත පරිදි වෙනස් කරන්න:

def notastonishinganymore(a = []): 
    '''The name is just a joke :)'''
    a = a[:]
    a.append(5)
    return a

7

මෙම ප්‍රශ්නයට පිළිතුර පවතින්නේ පයිතන් දත්ත පරාමිතිය වෙත යොමු කරන්නේ කෙසේද යන්න (අගය අනුව හෝ යොමු කිරීමෙනි), විකෘතිතාව හෝ පයිතන් “ඩෙෆ්” ප්‍රකාශය හසුරුවන ආකාරය නොවේ.

කෙටි හැඳින්වීමක්. පළමුව, පයිතන්හි දත්ත වර්ග දෙකක් තිබේ, එකක් සංඛ්‍යා වැනි සරල මූලික දත්ත වර්ගයක් වන අතර තවත් දත්ත වර්ගයක් වස්තු වේ. දෙවනුව, පරාමිතීන් වෙත දත්ත සම්ප්‍රේෂණය කරන විට, පයිතන් මූලික දත්ත වර්ගය අගය අනුව සම්මත කරයි, එනම්, වටිනාකමේ දේශීය පිටපතක් දේශීය විචල්‍යයකට සාදන්න, නමුත් වස්තුව යොමු කිරීමෙන්, එනම්, වස්තුවට යොමු කරන්න.

ඉහත කරුණු දෙක පිළිගනිමින්, පයිතන් කේතයට සිදුවූයේ කුමක්ද යන්න පැහැදිලි කරමු. එය වස්තූන් සඳහා යොමු කිරීම නිසා පමණක් වන නමුත් විකෘති / වෙනස් කළ නොහැකි හෝ "ඩෙෆ්" ප්‍රකාශය ක්‍රියාත්මක වන්නේ එය නිර්වචනය කළ විට එක් වරක් පමණක් බව තර්ක කළ හැකිය.

[] යනු වස්තුවකි, එබැවින් පයිතන් යනු [] වෙත යොමු කිරීම a, එනම්, aවස්තුවක් ලෙස මතකයේ පවතින [] වෙත යොමු කිරීම පමණි. [] හි එක් පිටපතක් පමණක් ඇත, කෙසේ වෙතත්, ඒ පිළිබඳව බොහෝ යොමු කිරීම් ඇත. පළමු foo () සඳහා, ලැයිස්තුව [] උපග්‍රන්ථ ක්‍රමය මඟින් 1 ට වෙනස් කරයි . නමුත් ලැයිස්තු වස්තුවෙහි එක් පිටපතක් පමණක් ඇති බවත් මෙම වස්තුව දැන් 1 බවට පත්වන බවත් සලකන්න . දෙවන foo () ධාවනය කරන විට, කාර්යක්ෂම වෙබ් පිටුව පවසන දේ (අයිතම තවදුරටත් ඇගයීමට ලක් නොකෙරේ) වැරදිය. aලැයිස්තුගත වස්තුව ලෙස තක්සේරු කර ඇත, නමුත් දැන් වස්තුවේ අන්තර්ගතය 1 වේ. යොමු දැක්වීමෙන් සම්මත වීමේ බලපෑම මෙයයි! Foo (3) හි ප්‍රති result ලය එකම ආකාරයකින් පහසුවෙන් ලබා ගත හැකිය.

මගේ පිළිතුර තවදුරටත් වලංගු කිරීම සඳහා, අතිරේක කේත දෙකක් දෙස බලමු.

====== අංක 2 =======

def foo(x, items=None):
    if items is None:
        items = []
    items.append(x)
    return items

foo(1)  #return [1]
foo(2)  #return [2]
foo(3)  #return [3]

[]වස්තුවක් ද එසේමය. None(පළමුවැන්න විකෘති වන අතර දෙවැන්න වෙනස් කළ නොහැකි ය. එහෙත් විකෘතිතාවයට ප්‍රශ්නයට කිසිදු සම්බන්ධයක් නැත). කිසිවක් අවකාශයේ කොතැනකවත් නැති නමුත් එය එහි ඇති බව අපි දනිමු. එහි ඇත්තේ කිසිවක් නැත. එබැවින් foo ආයාචනා කරන සෑම අවස්ථාවකම, අයිතමයන් ඇගයීමට ලක් කරනු ලැබේ (එය එක් වරක් පමණක් ඇගයීමට ලක් කරන පිළිතුරකට පටහැනිව) කිසිවක් නැත, පැහැදිලිව කිවහොත්, කිසිවක් නැත. ඉන්පසු foo හි අයිතමය [] ලෙස වෙනස් වේ, එනම් වෙනත් ලිපිනයක් ඇති වෙනත් වස්තුවකට යොමු කරයි.

====== අංක 3 =======

def foo(x, items=[]):
    items.append(x)
    return items

foo(1)    # returns [1]
foo(2,[]) # returns [2]
foo(3)    # returns [1,3]

Foo (1) හි ආයාචනය 11111111 ලිපිනයකින් ලැයිස්තුගත වස්තුවකට යොමු කරයි. ලැයිස්තුවේ අන්තර්ගතය අනුක්‍රමයේ foo ශ්‍රිතයේ 1 ට වෙනස් කර ඇත, නමුත් ලිපිනය වෙනස් නොවේ, තවමත් 11111111 එවිට foo (2, []) පැමිණේ. Foo (1) අමතන විට [] foo (2, []) හි පෙරනිමි පරාමිතිය [] ට සමාන අන්තර්ගතයක් තිබුණද, ඒවායේ ලිපිනය වෙනස් වේ! අපි පරාමිතිය පැහැදිලිව සපයන බැවින් items, මෙම නව ලිපිනය රැගෙන []2222222 කියන්න, යම් වෙනසක් කිරීමෙන් පසු එය ආපසු එවන්න. දැන් foo (3) ක්‍රියාත්මක වේ. සිට පමණිxසපයා ඇති විට, අයිතමයන්ට එහි පෙරනිමි අගය නැවත ගත යුතුය. පෙරනිමි අගය කුමක්ද? Foo ශ්‍රිතය නිර්වචනය කිරීමේදී එය සකසා ඇත: ලැයිස්තු වස්තුව 11111111 හි පිහිටා ඇත. එබැවින් අයිතම 11111111 මූලද්‍රව්‍යය සහිත ලිපිනය ලෙස ඇගයීමට ලක් කෙරේ. තවත්. එහි ප්‍රති 3 ලයක් වශයෙන්, 3 ක එකතු කිරීමක් items[1,3] කරයි.

ඉහත පැහැදිලි කිරීම් වලින්, පිළිගත් පිළිතුරේ නිර්දේශිත කාර්යක්ෂම වෙබ් පිටුව මෙම ප්‍රශ්නයට අදාළ පිළිතුරක් ලබා දීමට අපොහොසත් වී ඇති බව අපට පෙනේ . එපමණක්ද නොව, මම සිතන්නේ එෆ්බොට් වෙබ් පිටුවේ කරුණක් වැරදිය. මම හිතන්නේ UI.Button සම්බන්ධ කේතය නිවැරදියි:

for i in range(10):
    def callback():
        print "clicked button", i
    UI.Button("button %s" % i, callback)

සෑම බොත්තමකටම වෙනස් ඇමතුම් ලබා ගැනීමේ ශ්‍රිතයක් තබා ගත හැකි අතර එමඟින් විවිධ අගයන් පෙන්වනු ඇත i. මෙය පෙන්වීමට මට උදාහරණයක් සැපයිය හැකිය:

x=[]
for i in range(10):
    def callback():
        print(i)
    x.append(callback) 

අප ක්‍රියාත්මක කළහොත් අපට x[7]()අපේක්ෂිත පරිදි 7 ක් ලැබෙනු ඇති අතර x[9]()තවත් අගයක් 9 ක් ලබා දෙනු ඇත i.


5
ඔබේ අවසාන කරුණ වැරදියි. එය උත්සාහ කරන්න ඔබ බව පෙනෙනු ඇත x[7]()වේ 9.
ඩන්කන්

2
"පයිතන් පාස් මූලික දත්ත වර්ගය අනුව, එනම්, දේශීය විචල්‍යයකට දේශීය පිටපතක් සාදන්න" සම්පූර්ණයෙන්ම වැරදිය. යමෙකුට පැහැදිලිවම පයිතන් ගැන හොඳින් දැනගත හැකි වුවත්, මූලධර්ම පිළිබඳ එතරම් බිහිසුණු වරදවා වටහාගැනීමක් තිබීම ගැන මම පුදුම වෙමි. :-(
Veky

6

TLDR: නිර්වචන-කාල පෙරනිමි ස්ථාවර වන අතර දැඩි ලෙස ප්‍රකාශිත වේ.


මෙම නිර්වචනය විෂය පථය: උත්සවයකට නිර්වචනය දෙකක් විෂය පථ බලපාන අඩංගු වන උත්සවයක්, හා ක්රියාත්මක විෂය පථය විසින් අඩංගු දැමේ. විෂය පථයට සිතියම් අවහිර කරන්නේ කෙසේද යන්න පැහැදිලිව පෙනෙන අතර, ප්‍රශ්නය වන්නේ කොතැනටද def <name>(<args=defaults>)::

...                           # defining scope
def name(parameter=default):  # ???
    ...                       # execution scope

මෙම def nameකොටස යුතු නිර්වචනය විෂය පථය තුල ඇගයීමට - අපිට ඕන nameලබා ගත හැකි සියලු පසු, එහි විය. ශ්‍රිතය තමා තුළම තක්සේරු කිරීමෙන් එය ප්‍රවේශ කළ නොහැකි වනු ඇත.

parameterනියත නමක් බැවින් අපට එය එකවරම "ඇගයීමට" හැකිය def name. මෙය ද එය ලෙස දන්නා අත්සන සහිතව කාර්යය නිෂ්පාදනය වාසියක් name(parameter=...):වෙනුවට මුඩුබිම්, name(...):.

දැන්, ඇගයීමට ලක් defaultකරන්නේ කවදාද?

අනුකූලතාව දැනටමත් "අර්ථ දැක්වීමේදී" පවසයි: අනෙක් සියල්ලම def <name>(<args=defaults>):අර්ථ දැක්වීමේදී වඩාත් හොඳින් ඇගයීමට ලක් කෙරේ. එහි කොටස් ප්‍රමාද කිරීම විශ්මය ජනක තේරීම වනු ඇත.

තේරීම් දෙක සමාන නොවේ, එක්කෝ: defaultඅර්ථ දැක්වීමේ වේලාවේදී ඇගයීමට ලක් කළ හොත් , එය ක්‍රියාත්මක කිරීමේ වේලාවට තවමත් බලපායි. defaultක්‍රියාත්මක කිරීමේ වේලාවේදී ඇගයීමට ලක් කරන්නේ නම් , එය අර්ථ දැක්වීමේ වේලාවට බලපාන්නේ නැත . “අර්ථ දැක්වීම” තේරීමෙන් අවස්ථා දෙකම ප්‍රකාශ කිරීමට ඉඩ ලබා දෙන අතර “ක්‍රියාත්මක කිරීමේදී” තේරීමෙන් ප්‍රකාශ කළ හැක්කේ එකක් පමණි:

def name(parameter=defined):  # set default at definition time
    ...

def name(parameter=default):     # delay default until execution time
    parameter = default if parameter is None else parameter
    ...

"අනුකූලතාව දැනටමත්" අර්ථ දැක්වීමේදී "පවසයි: අනෙක් සියල්ලම def <name>(<args=defaults>):අර්ථ දැක්වීමේදී වඩාත් හොඳින් ඇගයීමට ලක් කෙරේ." මම හිතන්නේ නැහැ නිගමනය පරිශ්‍රයෙන් එනවා කියලා. කාරණා දෙකක් එකම රේඛාවක ඇති නිසා ඒවා එකම විෂය පථයකින් ඇගයීමට ලක් කළ යුතු යැයි අදහස් නොකෙරේ. defaultයනු අනෙක් පේළියට වඩා වෙනස් දෙයකි: එය ප්‍රකාශනයකි. ප්‍රකාශනයක් ඇගයීම ශ්‍රිතයක් අර්ථ දැක්වීමට වඩා වෙනස් ක්‍රියාවලියකි.
LarsH

@LarsH කාර්යභාරය අර්ථ දැක්වීම් ඇත ඇත Python ඇගයීමට ලක්. එය ප්‍රකාශයකින් ( def) හෝ ප්‍රකාශනයෙන් ( ) වේවා lambdaශ්‍රිතයක් නිර්මාණය කිරීම යනු ඇගයීම - විශේෂයෙන් එහි අත්සන බව වෙනස් නොවේ. පෙරනිමි යනු ශ්‍රිතයේ අත්සනෙහි කොටසකි. තේරුම පෙරනිමි නැති කර උදාහරණයක් ලෙස, වර්ගය ඉඟි නැති විය හැකි - වහාම ඇගයීමට ලක් කළ යුතුය. නමුත් එය නිසැකවම යෝජනා කරන්නේ එසේ නොකිරීමට හොඳ හේතුවක් නොමැති නම් පමණි.
මිස්ටර්මියාගි

හරි, ශ්‍රිතයක් නිර්මාණය කිරීම යනු යම් අර්ථයකින් ඇගයීමකි, නමුත් පැහැදිලිවම එය තුළ ඇති සෑම ප්‍රකාශනයක්ම නිර්වචනය කරන අවස්ථාවේ දී ඇගයීමට ලක් වේ. බොහෝමයක් එසේ නොවේ. ක්‍රියාකාරී ශරීරය “ඇගයීමට” (සුදුසු නිරූපණයකට විග්‍රහ කර ඇත) වඩා අර්ථකථන වේලාවේදී අත්සන විශේෂයෙන් “ඇගයීමට ලක් කරන්නේ” කුමන අර්ථයෙන්ද යන්න මට පැහැදිලි නැත; ශ්‍රිත ශරීරයේ ප්‍රකාශන පූර්ණ අර්ථයෙන් තක්සේරු නොකෙරේ. මෙම දෘෂ්ටි කෝණයෙන්, අනුකූලතාවයෙන් කියැවෙන්නේ අත්සනෙහි ප්‍රකාශන “සම්පූර්ණයෙන්” ඇගයීමට ලක් නොකළ යුතු බවයි.
LarsH

ඔබ වැරදියි කියා මම අදහස් නොකරමි, ඔබේ නිගමනය අනුකූලතාවයෙන් පමණක් අනුගමනය නොකෙරේ.
LarsH

ArLarsH පෙරනිමිති ශරීරයේ කොටසක් නොවේ, අනුකූලතාව එකම නිර්ණායකය යැයි මම නොකියමි. පිළිතුර පැහැදිලි කර ගන්නේ කෙසේද යන්න ඔබට යෝජනාවක් කළ හැකිද?
මිස්ටර්මියාගි

3

අනෙක් සෑම පිළිතුරකින්ම පැහැදිලි වන්නේ මෙය සැබවින්ම යහපත් හා අපේක්ෂිත හැසිරීමක් වන්නේ මන්ද යන්න හෝ ඔබට මෙය කෙසේ හෝ අවශ්‍ය නොවන්නේ මන්ද යන්නයි. මගේ යනු මුරණ්ඩු අයට භාෂාව තම අභිමතය පරිදි නැමීමේ අයිතිය ක්‍රියාත්මක කිරීමට අවශ්‍ය මිස වෙනත් ආකාරයකින් නොවේ.

අපි මෙම හැසිරීම සැරසිලි කරුවෙකු සමඟ "නිවැරදි කරන්නෙමු", එය පෙරනිමි අගයෙහි ඉතිරිව ඇති සෑම ස්ථානීය තර්කයක් සඳහාම එකම අවස්ථාව නැවත භාවිතා කිරීම වෙනුවට පෙරනිමි අගය පිටපත් කරනු ඇත.

import inspect
from copy import copy

def sanify(function):
    def wrapper(*a, **kw):
        # store the default values
        defaults = inspect.getargspec(function).defaults # for python2
        # construct a new argument list
        new_args = []
        for i, arg in enumerate(defaults):
            # allow passing positional arguments
            if i in range(len(a)):
                new_args.append(a[i])
            else:
                # copy the value
                new_args.append(copy(arg))
        return function(*new_args, **kw)
    return wrapper

දැන් අපි මෙම සැරසිලි යන්ත්‍රය භාවිතයෙන් අපගේ ක්‍රියාකාරිත්වය නැවත අර්ථ දැක්වමු:

@sanify
def foo(a=[]):
    a.append(5)
    return a

foo() # '[5]'
foo() # '[5]' -- as desired

බහු තර්ක ගන්නා ශ්‍රිත සඳහා මෙය විශේෂයෙන් පිළිවෙලට ඇත. සසඳන්න:

# the 'correct' approach
def bar(a=None, b=None, c=None):
    if a is None:
        a = []
    if b is None:
        b = []
    if c is None:
        c = []
    # finally do the actual work

සමග

# the nasty decorator hack
@sanify
def bar(a=[], b=[], c=[]):
    # wow, works right out of the box!

ඔබ වැනි යතුරු පද භාවිතා කිරීමට උත්සාහ කළහොත් ඉහත විසඳුම කැඩී යන බව සැලකිල්ලට ගැනීම වැදගත්ය:

foo(a=[4])

ඒ සඳහා සැරසිලි කරුවෙකු සකස් කළ හැකි නමුත් අපි මෙය පා er කයාට අභ්‍යාසයක් ලෙස තබමු;)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.