क्या डिफ़ॉल्ट के डिफॉल्ट_फैक्टिंग की कुंजी को पास करने का एक चतुर तरीका है?


93

एक क्लास में एक कंस्ट्रक्टर होता है जो एक पैरामीटर लेता है:

class C(object):
    def __init__(self, v):
        self.v = v
        ...

कहीं कोड में, यह एक कुंजी में मानों के लिए उपयोगी है उनकी कुंजियों को जानने के लिए।
मैं एक डिफ़ॉल्ट का उपयोग करना चाहता हूं जो कि नवजात डिफ़ॉल्ट मानों के लिए दी गई कुंजी के साथ है:

d = defaultdict(lambda : C(here_i_wish_the_key_to_be))

कोई सुझाव?

जवाबों:


127

यह शायद ही चालाक के रूप में योग्य है - लेकिन उपवर्ग आपका मित्र है:

class keydefaultdict(defaultdict):
    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError( key )
        else:
            ret = self[key] = self.default_factory(key)
            return ret

d = keydefaultdict(C)
d[x] # returns C(x)

16
यही कारण है कि बदसूरत मैं बचने की कोशिश कर रहा हूं ... यहां तक ​​कि एक साधारण तानाशाही का उपयोग करना और महत्वपूर्ण अस्तित्व की जांच करना बहुत साफ है।
बेंजामिन नितलेहो

1
@Paul: और फिर भी यह आपका जवाब है। कुरूपता? आ जाओ!
tzot

4
मुझे लगता है कि मैं बस उस कोड को लेने जा रहा हूं और इसे अपने व्यक्तिगत सामान्य उपयोगिताओं मॉड्यूल में डालूंगा ताकि जब भी मैं चाहूं इसका उपयोग कर सकूं। बहुत बदसूरत नहीं इस तरह से ...
वेरोनिका

24
+1 सीधे ओपी के प्रश्न को संबोधित करता है और मुझे "बदसूरत" नहीं दिखता है। इसके अलावा एक अच्छा जवाब कई क्योंकि एहसास है कि नहीं है defaultdictकी __missing__()विधि अधिरोहित जा सकता है (में से किसी उपवर्ग में यह कर सकते हैं के रूप में निर्मित dictवर्ग संस्करण 2.5 के बाद से)।
मार्टिन

7
+1 __missing__ का पूरा उद्देश्य गुम चाबियों के लिए व्यवहार को अनुकूलित करना है। @Silentghost द्वारा उल्लिखित तानाशाही.सेटडेफ़ॉल्ट () दृष्टिकोण भी काम करेगा (प्लस साइड में, सेटडेफ़ॉल्ट () कम है और पहले से मौजूद है; माइनस साइड पर, यह दक्षता के मुद्दों से ग्रस्त है और कोई भी वास्तव में "सेटडेफ़ॉल्ट" नाम पसंद नहीं करता है)) ।
रेमंड हेटिंगर

26

नहीं वहाँ नहीं है।

defaultdictकार्यान्वयन लापता पारित करने के लिए कॉन्फ़िगर नहीं किया जा सकता है keyके लिए default_factoryबाहर के बॉक्स। आपका एकमात्र विकल्प अपने खुद के defaultdictउपवर्ग को लागू करना है , जैसा कि @JochenRitzel द्वारा सुझाया गया है, ऊपर।

लेकिन यह "चालाक" या लगभग एक मानक पुस्तकालय समाधान के रूप में साफ नहीं होगा (यदि यह अस्तित्व में है)। इस प्रकार आपकी रसीली, हां / नहीं सवाल का जवाब स्पष्ट रूप से "नहीं" है।

यह बहुत खराब है मानक पुस्तकालय इस तरह के अक्सर आवश्यक उपकरण को याद कर रहा है।


हां, यह एक बेहतर डिजाइन विकल्प होता है कि कारखाने को कुंजी (शून्य के बजाय एकात्मक कार्य) लेने दें। जब हम एक स्थिर लौटना चाहते हैं तो एक तर्क को त्यागना आसान है।
येवसेरी

6

मुझे नहीं लगता कि आपको defaultdictयहां कोई जरूरत है। सिर्फ dict.setdefaultविधि का उपयोग क्यों नहीं ?

>>> d = {}
>>> d.setdefault('p', C('p')).v
'p'

निश्चित रूप से इसके कई उदाहरण बनेंगे C। मामले में यह एक मुद्दा है, मुझे लगता है कि सरल दृष्टिकोण क्या करेगा:

>>> d = {}
>>> if 'e' not in d: d['e'] = C('e')

यह defaultdictया जहाँ तक मैं देख सकता हूँ किसी भी अन्य विकल्प की तुलना में तेज होगा ।

inपरीक्षण को छोड़कर बनाम परीक्षण की गति के संबंध में ईटीए :

>>> def g():
    d = {}
    if 'a' in d:
        return d['a']


>>> timeit.timeit(g)
0.19638929363557622
>>> def f():
    d = {}
    try:
        return d['a']
    except KeyError:
        return


>>> timeit.timeit(f)
0.6167065411074759
>>> def k():
    d = {'a': 2}
    if 'a' in d:
        return d['a']


>>> timeit.timeit(k)
0.30074866358404506
>>> def p():
    d = {'a': 2}
    try:
        return d['a']
    except KeyError:
        return


>>> timeit.timeit(p)
0.28588609450770264

7
यह उन मामलों में बहुत बेकार है जहां डी कई बार पहुंच जाता है, और केवल शायद ही कभी एक कुंजी गायब होती है: सी (कुंजी) इस प्रकार जीसी के लिए अनावश्यक वस्तुओं के टन को इकट्ठा करेगा। इसके अलावा, मेरे मामले में एक अतिरिक्त दर्द है, क्योंकि नई सी वस्तुओं का निर्माण धीमा है।
बेंजामिन नाइटलेहू

@Paul: यह सही है। मैं फिर भी अधिक सरल विधि का सुझाव दूंगा, मेरा संपादन देखें।
साइलेंटगॉस्ट

मुझे यकीन नहीं है कि यह डिफ़ॉल्ट रूप से जल्दी है, लेकिन यह वही है जो मैं आमतौर पर करता हूं (THC4k के उत्तर के लिए मेरी टिप्पणी देखें)। मुझे उम्मीद थी कि इस तथ्य के आसपास हैक करने का एक सरल तरीका है default_factory कोड नहीं लेता है, कोड को और अधिक सुरुचिपूर्ण रखने के लिए।
बेंजामिन नितलेहो

5
@SilentGhost: मुझे समझ में नहीं आता - यह ओपी की समस्या को कैसे हल करता है? मुझे लगता है कि ओपी चाहता था कि अगर d[key]वह वापस आए d[key] = C(key)तो पढ़ने की कोई कोशिश करे key not in d। लेकिन आपके समाधान के लिए उसे वास्तव में जाने और पहले से निर्धारित करने की आवश्यकता है d[key]? उसे कैसे पता चलेगा कि keyउसे किस चीज की जरूरत है?
अधिकतम

2
क्योंकि सेटडेफॉल्ट नरक के रूप में बदसूरत है और संग्रह से डिफ़ॉल्ट रूप से एक फैक्ट्री फ़ंक्शन को अधिग्रहित करता है जो कुंजी प्राप्त करता है। अजगर डिजाइनरों से एक व्यर्थ अपारदर्शिता क्या है!
jgomo3

0

यहाँ एक शब्दकोश का एक कार्यशील उदाहरण है जो स्वचालित रूप से एक मूल्य जोड़ता है। / Usr / शामिल डुप्लिकेट फ़ाइलों को खोजने में प्रदर्शन कार्य। नोट करें कस्टमाइज़ किए गए शब्दकोश PathDict में केवल चार लाइनों की आवश्यकता होती है:

class FullPaths:

    def __init__(self,filename):
        self.filename = filename
        self.paths = set()

    def record_path(self,path):
        self.paths.add(path)

class PathDict(dict):

    def __missing__(self, key):
        ret = self[key] = FullPaths(key)
        return ret

if __name__ == "__main__":
    pathdict = PathDict()
    for root, _, files in os.walk('/usr/include'):
        for f in files:
            path = os.path.join(root,f)
            pathdict[f].record_path(path)
    for fullpath in pathdict.values():
        if len(fullpath.paths) > 1:
            print("{} located in {}".format(fullpath.filename,','.join(fullpath.paths)))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.