পাইথন ডিক.আপডেট () কেন বস্তুটি ফেরত দেয় না?


139

আমি চেষ্টা করছি:

award_dict = {
    "url" : "http://facebook.com",
    "imageurl" : "http://farm4.static.flickr.com/3431/3939267074_feb9eb19b1_o.png",
    "count" : 1,
}

def award(name, count, points, desc_string, my_size, parent) :
    if my_size > count :
        a = {
            "name" : name,
            "description" : desc_string % count,
            "points" : points,
            "parent_award" : parent,
        }
        a.update(award_dict)
        return self.add_award(a, siteAlias, alias).award

তবে যদি ফাংশনটিতে সত্যিই জটিল মনে হয়, এবং আমি বরং এটি করতাম:

        return self.add_award({
            "name" : name,
            "description" : desc_string % count,
            "points" : points,
            "parent_award" : parent,
        }.update(award_dict), siteAlias, alias).award

আপনি কেন শৃঙ্খলা করতে পারেন তাই কেন অবজেক্টটি ফেরত দেয় না?

জিকুরি চেইন করার জন্য এটি করে। অজগর কেন এটি গ্রহণযোগ্য নয়?


14
* টিএল; ডিআরnewdict = dict(dict001, **dict002)
ড্রেফটিম্যাক

2
@dreftymac, এটি যদিও বোঝার জন্য কাজ করে না।
অ্যালানচলভিট্টি

উত্তর:


219

পাইথনের বেশিরভাগই কমান্ড-কোয়েরি বিচ্ছিন্নতারNone ব্যবহারিকভাবে রঙযুক্ত গন্ধটি প্রয়োগ করে : মিউটররা ফিরে আসে ( pop;-) হিসাবে ব্যবহারিকভাবে অনুপ্রেরণা ব্যতীত তারা সম্ভবত অ্যাকসেসরগুলির সাথে বিভ্রান্ত হতে পারে না (এবং একই শিরাতে অ্যাসাইনমেন্টটি কোনও অভিব্যক্তি নয়, বিবৃতি নয় এক্সপ্রেশন বিচ্ছেদ আছে, এবং আরও এগিয়ে)।

এর অর্থ এই নয় যে আপনি যখন চান সত্যিই জিনিসগুলিকে একত্রীকরণের অনেকগুলি উপায় নেই, যেমন, আপনি যেমন প্রত্যাবর্তন dict(a, **award_dict)করতে চান তার মতো একটি নতুন ডিক তৈরি করে .update- তবে আপনি যদি সত্যিই এটি গুরুত্বপূর্ণ মনে করেন তবে কেন এটি ব্যবহার করবেন না? ?

সম্পাদনা করুন : বিটিডব্লিউ, আপনার নির্দিষ্ট ক্ষেত্রে প্রয়োজন নেই, পথে তৈরি করতে aহয়:

dict(name=name, description=desc % count, points=points, parent_award=parent,
     **award_dict)

আপনার মতো একই শব্দার্থক দিয়ে একটি একক ডিক তৈরি করে a.update(award_dict) (সংঘাতের ক্ষেত্রে, আপনি যে award_dictস্পষ্টরূপে দিচ্ছেন সেগুলিকে ওভাররাইড করে এমন বিষয়গুলি অন্তর্ভুক্ত করে; অন্য শব্দার্থবিজ্ঞানগুলি পেতে, যেমন, এই জাতীয় দ্বন্দ্বের স্পষ্টভাবে "বিজয়ী" থাকতে হবে, কীওয়ার্ডের আগে , এবং ফর্মটি বঞ্চিত হওয়া - ইত্যাদি ইত্যাদি award_dictএকমাত্র অবস্থানগত আর্গ হিসাবে পাস করুন ।**dict(award_dict, name=name


ঠিক আছে, এটি আমাকে তৈরি করার পরে একটি অন্য অভিধান তৈরি করবে। আমি একটি ডিক তৈরি করতে চেয়েছিলাম এবং তারপরে অন্যান্য মানগুলির একটি গুচ্ছ যুক্ত করতে এবং তারপরে এটি কোনও ফাংশনে দিতে চাই।
পল টারজান

@ পল, এবং ঠিক আপনি যা করছেন - দুটি বক্তব্য সহ (আপনি যে নেস্টেড পদ্ধতি চেয়েছিলেন তার চেয়ে অনেক বেশি পঠনযোগ্য) যা আপনার কাছে "সত্যিই বোঝা অনুভূত" হয়েছিল। কীভাবে aপুরোপুরি তৈরি করা এড়াতে হবে তা দেখানোর জন্য আমার উত্তরটি সম্পাদনা করা হচ্ছে , বিটিডাব্লু,
অ্যালেক্স মার্টেলি

1
আসল সমাধান মজবুত নয়। যদি অ্যাওয়ার্ড_ডিক্টে ইতিমধ্যে নির্দিষ্ট কীগুলি থাকে তবে পুনরাবৃত্ত কীওয়ার্ড আর্গুমেন্টের জন্য একটি সিনট্যাক্সেরর ফেলে দেওয়া হবে। জামিলাকের সলিউশন ডিক (itertools.chain (d1.iteitems (), .. d <n> .iteitems ()) কেবল অভিধানে ডুপ্লিকেট কী রয়েছে এমন ক্ষেত্রে কাজ করে না তবে সহজেই আপনাকে পরে ডিক্টের সাথে একাধিক অভিধানকে মার্জ করার অনুমতি দেয় চূড়ান্ত চূড়ান্ত মান জন্য অগ্রাধিকার গ্রহণ।
ম্যাট

2
এছাড়াও, যদি award_dict মধ্যে কী স্ট্রিং নয় ব্যাখ্যাকারী একটি নিক্ষেপ করা হবেTypeError
kunl

3
dict(old_dict, old_key=new_value)কীওয়ার্ডের জন্য একাধিক মান নিক্ষেপ করবে না এবং নতুন ডিক ফিরে আসবে না।
Charmy

35

পাইথনের এপিআই, কনভেনশন অনুসারে, পদ্ধতি এবং ফাংশনগুলির মধ্যে পার্থক্য করে। ফাংশনগুলি তাদের পরামিতিগুলির বাইরে নতুন মানগুলি গণনা করে (কোনও লক্ষ্য বস্তু সহ); পদ্ধতিগুলি বস্তুগুলিকে সংশোধন করে এবং কোনও কিছুই ফেরত দেয় না (যেমন তারা কোনও কিছুই ফেরায় না)। পদ্ধতিগুলির পার্শ্ব প্রতিক্রিয়া রয়েছে, ফাংশনগুলি নেই। আপডেট একটি পদ্ধতি, সুতরাং এটি কোনও মান ফেরায় না।

সেভাবে এটি করার অনুপ্রেরণা হ'ল অন্যথায়, আপনি অনাকাঙ্ক্ষিত পার্শ্ব প্রতিক্রিয়া পেতে পারেন। বিবেচনা

bar = foo.reverse()

যদি বিপরীত (যা জায়গাটিতে তালিকার বিপরীতে থাকে )ও এই তালিকাটি ফিরিয়ে দেয় তবে ব্যবহারকারীরা ভাবতে পারেন যে বিপরীত একটি নতুন তালিকা দেয় যা বারকে বরাদ্দ করা হয়, এবং কখনই লক্ষ্য করা যায় না যে foo এছাড়াও সংশোধিত হয়ে গেছে। বিপরীত রিটার্ন কোনও কিছুই না করে, তারা তত্ক্ষণাত্ চিনতে পেরেছিল যে বারটি বিপর্যয়ের ফলাফল নয়, এবং বিপরীত প্রভাব কী হবে তা আরও ঘনিষ্ঠভাবে দেখবে।


1
ধন্যবাদ. বিপরীতগুলি কেন এটি জায়গায় না করার বিকল্প দেয় না? কর্মক্ষমতা? করছেন reverse(foo)অদ্ভুত মতানুযায়ী।
পল টারজান

কোনও বিকল্প যুক্ত করা অনুচিত হবে: এটি পরামিতিগুলির উপর নির্ভর করে পদ্ধতির প্রকৃতির পরিবর্তন করবে। তবে, পদ্ধতিগুলিতে সত্যিকারের স্থির ফেরতের প্রকারগুলি থাকা উচিত (দুর্ভাগ্যক্রমে, এই নিয়মটি ভঙ্গ হওয়া ক্ষেত্রে রয়েছে)। রিভার্টেড অনুলিপি তৈরি করা সহজ: কেবল একটি অনুলিপি তৈরি করুন (ব্যবহার করে bar=foo[:]), তারপরে অনুলিপিটি উল্টো করুন।
মার্টিন বনাম লুইস

3
আমি মনে করি কারণটি স্পষ্টবাদী। ইন bar = foo.reverse(), আপনি ভাবতে পারেন যে fooএটি সংশোধিত নয়। এড়ানোর বিভ্রান্তির করার জন্য, আপনাকে উভয় আছে foo.reverse()এবং bar = reversed(foo)
রবার্তো বনভোলেট

প্যারামিটারের উপর ভিত্তি করে প্যারামিটারের প্রকৃতি পরিবর্তন করতে কী ভুল?
জুলিয়ান


15
>>> dict_merge = lambda a,b: a.update(b) or a
>>> dict_merge({'a':1, 'b':3},{'c':5})
{'a': 1, 'c': 5, 'b': 3}

মনে রাখবেন যে মার্জড ডিকটি ফেরত দেওয়ার পাশাপাশি এটি প্রথম প্যারামিটারটিকে জায়গায় পরিবর্তন করে। সুতরাং ডিকমেজ (ক, খ) এটিকে সংশোধন করবে।

অথবা, অবশ্যই আপনি এটি সমস্ত ইনলাইন করতে পারেন:

>>> (lambda a,b: a.update(b) or a)({'a':1, 'b':3},{'c':5})
{'a': 1, 'c': 5, 'b': 3}

10
-1 এর lambdaমতো ব্যবহার করা উচিত নয়, পরিবর্তে প্রচলিত ফাংশন defব্যবহার করুন
জামিলাক

8
এমনকি a.update(b) or a
ল্যাম্বদা

10

উপরের উত্তরে মন্তব্যের জন্য যথেষ্ট খ্যাতি নেই

@beardc এটি সিপিথন জিনিস বলে মনে হচ্ছে না। পিপাই আমাকে "টাইপএরর: কীওয়ার্ডগুলি অবশ্যই স্ট্রিং" হতে পারে

সমাধানটি কেবল সঙ্গে **kwargsকাজ করে কারণ অভিধানটি একত্রীকরণের জন্য কেবল টাইপ স্ট্রিংয়ের কী রয়েছে

অর্থাত

>>> dict({1:2}, **{3:4})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

বনাম

>>> dict({1:2}, **{'3':4})
{1: 2, '3': 4}

5

এটি এটি গ্রহণযোগ্য নয় এমন নয়, বরং dictsসেভাবে কার্যকর করা হয়নি।

আপনি যদি জ্যাঙ্গোর ওআরএম তাকান তবে এটি শৃঙ্খলার ব্যাপক ব্যবহার করে। এটিকে নিরুৎসাহিত করা হয়নি, আপনি এমনকি আপডেট পেতে dictএবং এমনকি যদি আপনি সত্যিই এটি চান তবে ওভাররাইড updateকরতে return selfপারেন।

class myDict(dict):
    def update(self, *args):
        dict.update(self, *args)
        return self

আপনাকে ধন্যবাদ, এটি ডিকটি প্যাচ করতে পারে, আমি কেবল জানতে চেয়েছিলাম কেন ডিক () এই কার্যকারিতাটি নিজেই অনুমতি দেয়নি (যেহেতু এটি আপনি প্রদর্শন করার মতো সহজ)। জ্যাঙ্গো কি প্যাচ ডিক এর মতো করে?
পল তারজান

2

আপনার প্রস্তাবিত সমাধানের কাছাকাছি হিসাবে আমি পেতে পারে

from collections import ChainMap

return self.add_award(ChainMap(award_dict, {
    "name" : name,
    "description" : desc_string % count,
    "points" : points,
    "parent_award" : parent,
}), siteAlias, alias).award

1

পার্টিতে দেরিতে যারা আসেন তাদের জন্য আমি কিছু সময় একসাথে রেখেছিলাম (পাই 3.7), এটি দেখিয়ে .update() ভিত্তিযুক্ত পদ্ধতিগুলি কিছুটা (~ 5%) দ্রুত দেখায় যখন ইনপুটগুলি সংরক্ষণ করা হয় এবং লক্ষণীয়ভাবে (30%) দ্রুত ইন-প্লেসে আপডেট করার সময় দ্রুত হয় ।

যথারীতি, সমস্ত মানদণ্ডগুলি লবণের দানা দিয়ে নেওয়া উচিত।

def join2(dict1, dict2, inplace=False):
    result = dict1 if inplace else dict1.copy()
    result.update(dict2)
    return result


def join(*items):
    iter_items = iter(items)
    result = next(iter_items).copy()
    for item in iter_items:
        result.update(item)
    return result


def update_or(dict1, dict2):
    return dict1.update(dict2) or dict1


d1 = {i: str(i) for i in range(1000000)}
d2 = {str(i): i for i in range(1000000)}

%timeit join2(d1, d2)
# 258 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit join(d1, d2)
# 262 ms ± 2.97 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit dict(d1, **d2)
# 267 ms ± 2.74 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit {**d1, **d2}
# 267 ms ± 1.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

স্থানটিতে অপারেশনের সময়গুলি কিছুটা কৌশলযুক্ত, সুতরাং এটির অতিরিক্ত অনুলিপি অপারেশনটি সংশোধন করা দরকার (প্রথম সময়টি কেবল রেফারেন্সের জন্য):

%timeit dd = d1.copy()
# 44.9 ms ± 495 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit dd = d1.copy(); join2(dd, d2)
# 296 ms ± 2.05 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit dd = d1.copy(); join2(dd, d2, True)
# 234 ms ± 1.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit dd = d1.copy(); update_or(dd, d2)
# 235 ms ± 1.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)


0

পাইথন ৩.৪ এ কেবল এটি চেষ্টা করে দেখছি (সুতরাং অভিনব {**dict_1, **dict_2}বাক্য গঠনটি ব্যবহার করতে সক্ষম হয়নি )।

আমি অভিধানগুলিতে নন-স্ট্রিং কীগুলি সক্ষম করার পাশাপাশি অভিধানগুলিতে একটি স্বেচ্ছাসেবী পরিমাণ সরবরাহ করতে চাইতাম।

এছাড়াও, আমি একটি নতুন অভিধান তৈরি করতে চেয়েছিলাম তাই আমি ব্যবহার না করা পছন্দ করলাম collections.ChainMap(কিন্ত যে কারণে dict.updateপ্রাথমিকভাবে আমি ব্যবহার করতে চাইনি) ।

এখানে আমি লেখার শেষ করেছি:

def merge_dicts(*dicts):
    all_keys  = set(k for d in dicts for k in d.keys())
    chain_map = ChainMap(*reversed(dicts))
    return {k: chain_map[k] for k in all_keys}

merge_maps({'1': 1}, {'2': 2, '3': 3}, {'1': 4, '3': 5})
# {'1': 4, '3': 5, '2': 2}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.