কাঠামোগত বিষয়বস্তু তৈরি করে


85

আমি একটি অভিধানকে 'ডেসট্রাকচার' করার চেষ্টা করছি এবং এর কীগুলির পরে ভেরিয়েবলের নামের সাথে মানগুলি সংযুক্ত করছি। কিছুটা এইরকম

params = {'a':1,'b':2}
a,b = params.values()

কিন্তু যেহেতু params.values()অভিধানগুলি অর্ডার করা হয়নি, কোনও গ্যারান্টি নেই যে ক্রম অনুসারে মানগুলি ফিরিয়ে দেবে (a, b)। এটি করার একটি দুর্দান্ত উপায় আছে?


4
অলস? হতে পারে ... তবে অবশ্যই আমি উদাহরণের জন্য সবচেয়ে সহজ কেসটি দেখিয়েছি। আদর্শভাবে আমি প্যারাম.আইটিএমগুলিতে এক্স পছন্দ করতে চেয়েছিলাম: ইভাল ('% s =% f'% x) তবে আমার ধারণা এভাল () অ্যাসাইনমেন্টের অনুমতি দেয় না।
হ্যাটম্যাট্রিক্স

7
@JochenRitzel আমি নিশ্চিত ES6 (জাভাস্ক্রিপ্ট) অধিকাংশ ব্যবহারকারীদের লেগেছে নতুন অবজেক্ট ডেসট্রাকচারিং শব্দবিন্যাস: let {a, b} = params। এটি পঠনযোগ্যতা বাড়ায় এবং জেন আপনি যে বিষয়ে কথা বলতে চান তার সাথে সম্পূর্ণভাবে ইনলাইন line
অ্যান্ডি

8
@ অ্যান্ডি আমি জেএসে অবজেক্ট ডেস্ট্রাকচারিং পছন্দ করি । কোনও ডিক থেকে কিছু কী বের করার জন্য কী পরিষ্কার, সহজ এবং পঠনযোগ্য উপায়। পাইথনে অনুরূপ কিছু খুঁজে পাওয়ার আশা নিয়ে এখানে এসেছি।
রোটেরেটি

4
আমি ইএস object অবজেক্টের ডেস্ট্রাকচারিংকেও পছন্দ করি তবে আমি ভয় করি যে এটি পাইথনে কাজ করতে পারে না একই কারণে ইএস's এর ম্যাপ অবজেক্ট ডেস্ট্রাকচারিং সমর্থন করে না। কীগুলি কেবল ES6 মানচিত্র এবং পাইথন ডিকের স্ট্রিং নয়। এছাড়াও, যদিও আমি ES6 এ অবজেক্ট ডেস্ট্রাকচারিংয়ের "প্লাক" শৈলী পছন্দ করি, তবে অ্যাসাইনমেন্ট শৈলীটি সহজ নয়। এখানে কি হচ্ছে? let {a: waffles} = params। আপনি এটি ব্যবহার করতে না পারলেও এটি নির্ধারণ করতে কয়েক সেকেন্ড সময় লাগে।
জন ক্রিস্টোফার জোন্স

4
@ naught101 পরিস্থিতিগতভাবে ট্রেড অফসের জন্য বাজে আশ্চর্যর সাথে কার্যকর। ব্যবহারকারীদের জন্য: পাইথনে যে কোনও বস্তু তার নিজস্ব স্ট্র / রেপি পদ্ধতি সরবরাহ করতে পারে। এমনকি সহজ JSON সিরিয়ালাইজেশনের জন্য সামান্য জটিল কী বস্তুর (যেমন, নামযুক্ত টিপলস) এর জন্য এটি করতে প্ররোচিত হতে পারে। এখন আপনি নিজের মাথা আঁচড়ান রেখে গেছেন যে আপনি নামের দ্বারা কী কী তৈরি করতে পারবেন না। এছাড়াও, কেন এটি আইটেমগুলির জন্য কাজ করে তবে অ্যাট্রেস নয়? প্রচুর গ্রন্থাগার অ্যাটর্স পছন্দ করে। প্রয়োগকারীদের জন্য, এই ES6 বৈশিষ্ট্যটি প্রতীকগুলি (বাইন্ডেবল নামগুলি) এবং স্ট্রিংগুলিকে গুলিয়ে দেয়: জাভাস্ক্রিপ্টে যুক্তিসঙ্গত তবে পাইথনটিতে অনেক বেশি সমৃদ্ধ ধারণা রয়েছে। এছাড়াও, এটি কেবল কুরুচিপূর্ণ দেখাবে।
জন ক্রিস্টোফার জোন্স

উত্তর:


10

যদি আপনি স্থানীয় অভিধানের ব্যবহারের সাথে জড়িত সমস্যাগুলি সম্পর্কে ভীত হন এবং আপনি আপনার মূল কৌশলটি অনুসরণ করতে পছন্দ করেন, অজগর ২.7 এবং ৩.১ সংগ্রহ থেকে অর্ডার ডিকোরিজস O অর্ডারডিক্টসগুলি আপনাকে অভিধানের আইটেমগুলি প্রথমে সন্নিবেশ করানো হয়েছে যাতে সেগুলি পুনরুদ্ধার করতে দেয়


@ স্টিফেন আপনি ভাগ্যবান কারণ অর্ডারডিক্টস অজগর ৩.১ থেকে পাইথন ২.7 এ স্থাপন করেছেন
জোয়াকুইন

আমি এটা করার জন্য উন্মুখ...! ভেবেছিলেন যে আমার কাছে পাইথনের জন্য সর্বদা একটি স্টিকিং পয়েন্ট ছিল (যে
আদেশগুলি

4
বর্তমানে, 3.5+ তে সমস্ত অভিধানের অর্ডার দেওয়া হয়েছে। এটি এখনও "গ্যারান্টিযুক্ত" নয়, এর অর্থ এটি পরিবর্তন হতে পারে।
চার্লস মেরিয়ামিয়াম

4
এটি 3.6+ থেকে গ্যারান্টিযুক্ত।
nnot101

123
from operator import itemgetter

params = {'a': 1, 'b': 2}

a, b = itemgetter('a', 'b')(params)

বিস্তৃত ল্যাম্বদা ফাংশন বা অভিধান বোঝার পরিবর্তে লাইব্রেরিতে বিল্ট ব্যবহার করতে পারে।


9
এটি সম্ভবত গ্রহণযোগ্য উত্তর হওয়া উচিত, কারণ এটি করা সবচেয়ে পাইথোনিক উপায়। এমনকি attrgetterএকই মানের লাইব্রেরি মডিউল থেকে আপনি উত্তরটি প্রসারিত করতে পারেন , যা অবজেক্ট বৈশিষ্ট্যগুলির জন্য কাজ করে ( obj.a)। এটি জাভাস্ক্রিপ্ট থেকে একটি প্রধান পার্থক্য, যেখানে obj.a === obj["a"]
জন ক্রিস্টোফার জোনস

অভিধানে কীটি উপস্থিত না থাকলে KeyErrorব্যতিক্রম উত্থাপিত হবে
তাসাওয়ার হুসেন

4
তবে আপনি এখন দু'বার a এবং b টাইপ করছেন বিধ্বংসী বিবৃতিতে
অটো

4
পছন্দ করেছেন আমি সন্দেহ করি অনেক লোক তাত্ক্ষণিকভাবে একটি আসল কোডে বুঝতে পারে। অন্যদিকে, প্রস্তাবিত হিসাবে উপায়টি a, b = [d[k] for k in ('a','b')]আরও প্রাকৃতিক / পঠনযোগ্য (ফর্মটি আরও সাধারণভাবে)। এটি এখনও একটি আকর্ষণীয় উত্তর, তবে এটি সবচেয়ে সহজ সমাধান নয়।
সিগ্লেসেট

@ সিগ্লেসেট আমি মনে করি এটি আপনাকে কতবার পড়তে / প্রয়োগ করতে হবে তার উপর নির্ভর করে। আপনি যদি নিয়মিত একই 3 টি কী বাছাই করেন get_id = itemgetter(KEYS)তবে পরে ব্যবহারের মতো কিছু serial, code, ts = get_id(document)সহজ is স্বীকারোক্তিহীন, আপনাকে উচ্চতর ক্রমের সাথে স্বাচ্ছন্দ্য বোধ করতে হবে তবে পাইথন সাধারণত তাদের সাথে খুব আরামদায়ক হয়। উদাহরণস্বরূপ, সাজসজ্জার জন্য ডক্স দেখুন @contextmanager
জন ক্রিস্টোফার জোন্স

29

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

pluck = lambda dict, *args: (dict[arg] for arg in args)

things = {'blah': 'bleh', 'foo': 'bar'}
foo, blah = pluck(things, 'foo', 'blah')

এছাড়াও, জোয়াকুইনের অর্ডারডিক্টের পরিবর্তে আপনি কীগুলি বাছাই করতে এবং মানগুলি পেতে পারেন। কেবলমাত্র ক্যাচগুলির জন্য আপনার বর্ণানুক্রমিক ক্রমে আপনার পরিবর্তনশীল নামগুলি নির্দিষ্ট করতে হবে এবং ডিকের সমস্ত কিছুই ডিস্ট্রাকচার করতে হবে:

sorted_vals = lambda dict: (t[1] for t in sorted(dict.items()))

things = {'foo': 'bar', 'blah': 'bleh'}
blah, foo = sorted_vals(things)

4
এটি একটি ছোটখাটো বাচ্চা, তবে আপনি যদি lambdaকোনও ভেরিয়েবলকে একটি বরাদ্দ করতে চলেছেন তবে আপনি এর সাথে সাধারণ ফাংশন সিনট্যাক্সটিও ব্যবহার করতে পারেন def
আর্থার টাচকা

আপভোটেড ক্যান্ট আপনি জেএসের মতো এটি করতে পারেন যেখানে এটি কনস্ট্যান্ট {এ, বি} = {এ: 1, বি: 2}
পাইরেটএপ

4
আপনি স্ট্যান্ডার্ড লাইব্রেরি itemgetterথেকে প্রয়োগ করেছেন operator। :)
জন ক্রিস্টোফার জোন্স

17

পাইথন কেবল অভিধানগুলিতে নয় "ডিস্ট্রাকচার" সিকোয়েন্সগুলিতে সক্ষম। সুতরাং, আপনি যা লিখতে চান তা লিখতে আপনাকে প্রয়োজনীয় প্রবেশাগুলিকে একটি যথাযথ ক্রমের মানচিত্র করতে হবে। আমার হিসাবে, আমি যে নিকটতম ম্যাচটি দেখতে পেল তা হ'ল (খুব সেক্সি নয়):

a,b = [d[k] for k in ('a','b')]

এটি জেনারেটরের সাথেও কাজ করে:

a,b = (d[k] for k in ('a','b'))

এখানে একটি সম্পূর্ণ উদাহরণ:

>>> d = dict(a=1,b=2,c=3)
>>> d
{'a': 1, 'c': 3, 'b': 2}
>>> a, b = [d[k] for k in ('a','b')]
>>> a
1
>>> b
2
>>> a, b = (d[k] for k in ('a','b'))
>>> a
1
>>> b
2


10

জেএসে একটি ডেস্ট্রাকচারিং অ্যাসাইনমেন্ট কীভাবে কাজ করে তার অনুরূপ করার জন্য এখানে অন্য উপায় :

params = {'b': 2, 'a': 1}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)

আমরা যা করেছি তা হ'ল প্যারামের অভিধানটি মূল মানগুলিতে (** ব্যবহার করে) অনুলিপি করা (যেমন জোখেনের উত্তরে ), তখন আমরা সেই মানগুলি ল্যাম্বদা স্বাক্ষরে নিয়েছি এবং মূল নাম অনুসারে তাদের নির্ধারিত করেছি - এবং এখানে একটি বোনাস রয়েছে - আমরা এছাড়াও যাই হোক না কেন হয় একটি অভিধান পেতে না তাই যদি আপনি ছিল ল্যামডা স্বাক্ষর মধ্যে:

params = {'b': 2, 'a': 1, 'c': 3}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)

ল্যাম্বডা প্রয়োগ করার পরে, বাকী চলকগুলিতে এখন থাকবে:: 'সি': 3:

অভিধান থেকে অপরিবর্তিত চাবি বাদ দেওয়ার জন্য দরকারী।

আশাকরি এটা সাহায্য করবে.


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

3

এটা চেষ্টা কর

d = {'a':'Apple', 'b':'Banana','c':'Carrot'}
a,b,c = [d[k] for k in ('a', 'b','c')]

ফলাফল:

a == 'Apple'
b == 'Banana'
c == 'Carrot'

3

সতর্কতা 1: দস্তাবেজগুলিতে বর্ণিত হিসাবে, এটি সমস্ত পাইথন বাস্তবায়নে কাজ করার গ্যারান্টিযুক্ত নয়:

সিপথন বাস্তবায়নের বিশদ: এই ফাংশনটি দোভাষীগুলিতে পাইথন স্ট্যাক ফ্রেম সমর্থনের উপর নির্ভর করে, যা পাইথনের সমস্ত বাস্তবায়নের জন্য গ্যারান্টিযুক্ত নয়। পাইথন স্ট্যাক ফ্রেম সমর্থন ছাড়াই কোনও বাস্তবায়নে চলতে থাকলে এই ফাংশনটি কোনও দেয় না।

সতর্কতা 2: এই ফাংশনটি কোডটি আরও ছোট করে তোলে তবে এটি পাইথন দর্শনের পক্ষে যতটা স্পষ্ট তা স্পষ্ট হওয়ার বিরোধিতা করে। তদ্ব্যতীত, জন মন্তব্যে জন ক্রিস্টোফার জোন্সের নির্দেশিত সমস্যাগুলি সমাধান করে না, যদিও আপনি কীগুলির পরিবর্তে বৈশিষ্ট্যগুলির সাথে কাজ করে এমন একটি ফাংশন করতে পারেন। এই মাত্র একটি বিক্ষোভের পথ পাবো না করতে যে আপনি যদি সত্যিই চাই না!

def destructure(dict_):
    if not isinstance(dict_, dict):
        raise TypeError(f"{dict_} is not a dict")
    # the parent frame will contain the information about
    # the current line
    parent_frame = inspect.currentframe().f_back

    # so we extract that line (by default the code context
    # only contains the current line)
    (line,) = inspect.getframeinfo(parent_frame).code_context

    # "hello, key = destructure(my_dict)"
    # -> ("hello, key ", "=", " destructure(my_dict)")
    lvalues, _equals, _rvalue = line.strip().partition("=")

    # -> ["hello", "key"]
    keys = [s.strip() for s in lvalues.split(",") if s.strip()]

    if missing := [key for key in keys if key not in dict_]:
        raise KeyError(*missing)

    for key in keys:
        yield dict_[key]
In [5]: my_dict = {"hello": "world", "123": "456", "key": "value"}                                                                                                           

In [6]: hello, key = destructure(my_dict)                                                                                                                                    

In [7]: hello                                                                                                                                                                
Out[7]: 'world'

In [8]: key                                                                                                                                                                  
Out[8]: 'value'

এই সমাধানটি আপনাকে জাভাস্ক্রিপ্টের মতো কিছু না কিছু কী বাছাই করতে দেয়। এটি ব্যবহারকারী-প্রদত্ত অভিধানের জন্যও নিরাপদ


1

ঠিক আছে, আপনি যদি কোনও ক্লাসে এটি চান তবে আপনি সর্বদা এটি করতে পারেন:

class AttributeDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttributeDict, self).__init__(*args, **kwargs)
        self.__dict__.update(self)

d = AttributeDict(a=1, b=2)

ভাল লাগল ধন্যবাদ, তবে কি কল সিনট্যাক্সকে d ['a'] থেকে da তে পরিবর্তন করার মতো মনে হচ্ছে? এবং সম্ভবত এই পরামিতিগুলিতে
স্পষ্টভাবে

0

@ শ্যাশনফুমো উত্তরের ভিত্তিতে আমি এটি নিয়ে এসেছি:

def destruct(dict): return (t[1] for t in sorted(dict.items()))

d = {'b': 'Banana', 'c': 'Carrot', 'a': 'Apple' }
a, b, c = destruct(d)

(ডিকের আইটেমগুলির ক্রম লক্ষ্য করুন)


0

যেহেতু অভিধানগুলি পাইথন> = 3.7 এ তাদের সন্নিবেশের আদেশ রাখার গ্যারান্টিযুক্ত , এর অর্থ এটি আজকাল কেবল এটি করা সম্পূর্ণ নিরাপদ এবং মূর্তিমান:

params = {'a': 1, 'b': 2}
a, b = params.values()
print(a)
print(b)

আউটপুট:

1
2

4
দুর্দান্ত! আমার পোস্টের পরে তাদের কেবল 9 বছর সময় লেগেছে। :)
হ্যাটম্যাট্রিক্স

4
সমস্যাটি হ'ল আপনি করতে পারবেন না b, a = params.values(), কারণ এটি অর্ডার ব্যবহার করে নাম নয়।
Corman

4
@রুহোলা এটিই এই সমস্যার সমাধান with এটি নামের জন্য অভিধানের ক্রমের উপর নির্ভর করে, নামগুলি নিজেরাই নয়, এ কারণেই আমি এটিকে অগ্রাহ্য করেছি।
Corman

4
এবং যদি এটি কীগুলির ক্রমের উপর নির্ভর করে তবে এটি একটি খারাপ সমাধান করে। itemgetterএটি করার জন্য সবচেয়ে অজগর উপায় on এটি পাইথন 3.6 বা তার নীচে কাজ করবে না এবং এটি অর্ডারের উপর নির্ভর করে বলে এটি প্রথমে বিভ্রান্তিকর হতে পারে।
Corman

-1

আমি জানি না এটি ভাল স্টাইল কিনা, তবে

locals().update(params)

কৌতুক করবে এর পরে আপনি আছে a, bএবং যাই হোক না কেন আপনার মধ্যে ছিল paramsস্থানীয় ভেরিয়েবল সংশ্লিষ্ট হিসাবে উপলব্ধ অভি।


4
দয়া করে মনে রাখবেন যে 'প্যারামস' অভিধানটি কোনওভাবেই ব্যবহারকারী দ্বারা সরবরাহ করা এবং সঠিকভাবে ফিল্টার না করা থাকলে এটি একটি বড় সুরক্ষা সমস্যা হতে পারে।
Jacek Konieczny

9
ডকস.পাইথন.আর. / লাইব্রেরি / ফাংশনস html# লোকসের উদ্ধৃতি দিতে : দ্রষ্টব্য: এই অভিধানের বিষয়বস্তুগুলি পরিবর্তন করা উচিত নয়; পরিবর্তনগুলি দোভাষী দ্বারা ব্যবহৃত স্থানীয় এবং বিনামূল্যে ভেরিয়েবলের মানগুলিকে প্রভাবিত করতে পারে না।
জোচেন রিটজেল

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