অভিধান এবং ডিফল্ট মান


213

ধরে connectionDetailsনেওয়া একটি পাইথন অভিধান, এর মতো রিফ্যাক্টরিং কোডের সেরা, সবচেয়ে মার্জিত, সর্বাধিক "পাইথোনিক" উপায় কী?

if "host" in connectionDetails:
    host = connectionDetails["host"]
else:
    host = someDefaultValue

উত্তর:


311

এটার মত:

host = connectionDetails.get('host', someDefaultValue)

40
নোট করুন যে দ্বিতীয় আর্গুমেন্টটি একটি মান, কোনও কী নয়।
মার্সিন

7
পাঠযোগ্যতার জন্য +1, তবে if/elseএটি আরও দ্রুত। এটি সম্ভবত ভূমিকা নিতে পারে বা নাও পারে।
টিম পিটজ্যাকার

7
@ টিম, আপনি if/elseদ্রুত কেন একটি রেফারেন্স দিতে পারেন ?
নিশান্তজর

2
@ টিম: আমি ধরে নিয়েছি যে উচ্চ স্তরের ভাষা ব্যবহারের একটি সুবিধা হ'ল দোভাষী তার কার্যকারিতাটির ভিতরে 'দেখতে' এবং এটি অনুকূল করতে সক্ষম হবেন - যে ব্যবহারকারীকে মাইক্রো-অপ্টিমাইজেশানকে এতটা মোকাবেলা করতে হবে না । এটি কি জেআইটি সংকলনের মতো জিনিস নয়?
নিশান্তজর

3
@ নিশান্তজর: পাইথন (কমপক্ষে সিপিথন, সর্বাধিক সাধারণ রূপ) জেআইটি সংকলন নেই। পাইপাই প্রকৃতপক্ষে এটি দ্রুত সমাধান করতে পারে তবে স্ট্যান্ডার্ড পাইথন এখনও পর্যন্ত আমার উদ্দেশ্যগুলির জন্য যথেষ্ট দ্রুতগতি সম্পন্ন হওয়ায় আমি এটি ইনস্টল করি নি। সাধারণভাবে, এটি বাস্তব জীবনে গুরুত্বপূর্ণ হওয়ার সম্ভাবনা নেই - যদি আপনাকে সময়-সমালোচনামূলক সংখ্যা
ক্রাঞ্চিংয়ের

99

আপনি এটির defaultdictমতো ব্যবহার করতে পারেন:

from collections import defaultdict
a = defaultdict(lambda: "default", key="some_value")
a["blabla"] => "default"
a["key"] => "some_value"

ল্যাম্বদার পরিবর্তে আপনি কোনও সাধারণ ক্রিয়াকলাপটি পাস করতে পারেন:

from collections import defaultdict
def a():
  return 4

b = defaultdict(a, key="some_value")
b['absent'] => 4
b['key'] => "some_value"

7
আমি এখানে ওপি-র প্রশ্নের চেয়ে আলাদা কিছু সমস্যার জন্য এসেছি এবং আপনার সমাধানটি হুবহু সমাধান করে।
0xc0de

আমি এটি +1 করব তবে দুঃখের বিষয় এটি এর সাথে getবা অনুরূপ পদ্ধতির সাথে খাপ খায় না ।
0xc0de

এই উত্তরটি একটি অভিধান অন্তর্ভুক্ত ডিফল্ট কীগুলিতে সংযোজন নিশ্চিত করার জন্য আমার পক্ষে দরকারী। আমার বাস্তবায়ন স্ট্যাকওভারফ্লো উত্তরে বর্ণনা করতে কিছুটা দীর্ঘ। তাই আমি এটি সম্পর্কে এখানে লিখেছিলাম। persagen.com/2020/03/05/…
ভিক্টোরিয়া স্টুয়ার্ট

24

যদিও .get()একটি দুর্দান্ত প্রতিভা, এটির চেয়ে ধীর if/else(এবং try/exceptঅভিধানে কীটির উপস্থিতি বেশিরভাগ সময় আশা করা যায় তার চেয়ে ধীর ):

>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
... stmt="try:\n a=d[1]\nexcept KeyError:\n a=10")
0.07691968797894333
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
... stmt="try:\n a=d[2]\nexcept KeyError:\n a=10")
0.4583777282275605
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
... stmt="a=d.get(1, 10)")
0.17784020746671558
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
... stmt="a=d.get(2, 10)")
0.17952161730158878
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
... stmt="if 1 in d:\n a=d[1]\nelse:\n a=10")
0.10071221458065338
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", 
... stmt="if 2 in d:\n a=d[2]\nelse:\n a=10")
0.06966537335119938

3
আমি এখনও দেখছি না কেন if/then দ্রুত হবে। উভয় ক্ষেত্রেই একটি লুকআপ অভিধান প্রয়োজন, এবং যদি না নামোচ্চারণের get()হয় তাই অনেক ধীর ছাড়া আর কী মন্দার জন্য অ্যাকাউন্টসের?
জেনস

1
@ জেনস: ফাংশন কলগুলি ব্যয়বহুল।
টিম পিটজ্যাকার

1
কোনটি একটি বিশাল জনবহুল অভিধানে বড় বিষয় হওয়া উচিত নয়, সঠিক? অর্থ আসল চেহারা ব্যয়বহুল হলে ফাংশন কলটি তেমন গুরুত্ব পাচ্ছে না। এটি সম্ভবত খেলনার উদাহরণগুলিতে গুরুত্বপূর্ণ।
আতুরস্যাম 14'15

2
@ জেহেলভিয়ন: অভিধানের অনুসন্ধান O(1)অভিধানের আকার নির্বিশেষে, সুতরাং ফাংশন কল ওভারহেড প্রাসঙ্গিক।
টিম পিটজ্যাকার

35
এটি কোনও উদ্ভট বিষয় যদি কোনও ফাংশন কল করার ওভারহেড আপনাকে গিট ব্যবহারের বিরুদ্ধে সিদ্ধান্ত নিতে বাধ্য করে। আপনার সহযোগী দলের সদস্যরা যা ভাল পড়তে পারে তা ব্যবহার করুন।
জোচেন বেডারসর্ডার

19

একাধিক ভিন্ন ডিফল্টর জন্য এটি ব্যবহার করে দেখুন:

connectionDetails = { "host": "www.example.com" }
defaults = { "host": "127.0.0.1", "port": 8080 }

completeDetails = {}
completeDetails.update(defaults)
completeDetails.update(connectionDetails)
completeDetails["host"]  # ==> "www.example.com"
completeDetails["port"]  # ==> 8080

3
এটি একটি ভাল আইডোমেটিক সমাধান, তবে একটি সমস্যা রয়েছে। অপ্রত্যাশিত ফলাফলের ফলে যদি সংযোগের Noneবিবরণগুলি সরবরাহ করা হয় বা খালি স্ট্রিংকে মূল-মান জোড়গুলির মানগুলির মধ্যে একটি হিসাবে সরবরাহ করা হয় । defaultsঅভিধান সম্ভাব্য তার মান এক অনিচ্ছাকৃতভাবে আউট blanked ফেলতে পারে। (এছাড়াও দেখুন stackoverflow.com/questions/6354436 )
dreftymac

9

এটি করার জন্য অজগর অভিধানগুলিতে একটি পদ্ধতি রয়েছে: dict.setdefault

connectionDetails.setdefault('host',someDefaultValue)
host = connectionDetails['host']

তবে এই পদ্ধতি মূল্য নির্ধারণ connectionDetails['host']করার জন্য someDefaultValueযদি চাবি hostইতিমধ্যে সংজ্ঞায়িত করা হয় না, কি প্রশ্ন জিজ্ঞাসা অসদৃশ।


1
লক্ষ্য করুন setdefault()আয় মান, তাই এই হিসাবে ভাল কাজ করে: host = connectionDetails.setdefault('host', someDefaultValue)। কেবল সাবধান যে connectionDetails['host']কীটি আগে সেখানে না থাকলে এটি ডিফল্ট মান সেট করে।
ash108

7

(এটি একটি দেরী উত্তর)

dictক্লাসের সাবক্লাস করা এবং __missing__()পদ্ধতিটি প্রয়োগ করা এর বিকল্প হিসাবে রয়েছে :

class ConnectionDetails(dict):
    def __missing__(self, key):
        if key == 'host':
            return "localhost"
        raise KeyError(key)

উদাহরণ:

>>> connection_details = ConnectionDetails(port=80)

>>> connection_details['host']
'localhost'

>>> connection_details['port']
80

>>> connection_details['password']
Traceback (most recent call last):
  File "python", line 1, in <module>
  File "python", line 6, in __missing__
KeyError: 'password'

4

পাইথনের ৩.৩.৫ এর জন্য পাইপাইয়ের (5.2.0-alpha0) পরিস্থিতি সম্পর্কে @ টিম পিটজ্যাকারের সন্দেহ পরীক্ষা করে, আমি দেখতে পেয়েছি যে প্রকৃতপক্ষে .get()এবং if/ elseউপায় উভয়ই একই রকম সম্পাদন করেছে। আসলে এটি মনে হয় যে / যদি অন্য ক্ষেত্রে শর্ত এবং অ্যাসাইনমেন্ট একই কী জড়িত থাকে তবে কেবলমাত্র একটি একক অনুসন্ধান রয়েছে (যেখানে দুটি লকআপ রয়েছে সেখানে শেষ কেসের সাথে তুলনা করুন)।

>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="try:\n a=d[1]\nexcept KeyError:\n a=10")
0.011889292989508249
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="try:\n a=d[2]\nexcept KeyError:\n a=10")
0.07310474599944428
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="a=d.get(1, 10)")
0.010391917996457778
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="a=d.get(2, 10)")
0.009348208011942916
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="if 1 in d:\n a=d[1]\nelse:\n a=10")
0.011475925013655797
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="if 2 in d:\n a=d[2]\nelse:\n a=10")
0.009605801998986863
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="if 2 in d:\n a=d[2]\nelse:\n a=d[1]")
0.017342638995614834

1

আপনি ওয়ান লাইনার হিসাবে এটির জন্য একটি ল্যাম্বা ফাংশন ব্যবহার করতে পারেন। একটি নতুন অবজেক্ট তৈরি করুন connectionDetails2যা কোনও ফাংশনের মতো অ্যাক্সেস করা ...

connectionDetails2 = lambda k: connectionDetails[k] if k in connectionDetails.keys() else "DEFAULT"

এখন ব্যবহার করুন

connectionDetails2(k)

পরিবর্তে

connectionDetails[k]

kকীগুলিতে থাকলে অভিধানের মানটি দেয় , অন্যথায় এটি প্রত্যাবর্তন করে"DEFAULT"


আমি আপনাকে উত্সাহিত করেছি কিন্তু আপনার সমাধানের সমস্যাটি
হ'ল চিকিত্সা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.