अजगर में वस्तु की विशेषताओं पर फेरबदल


162

मेरे पास कई विशेषताओं और विधियों के साथ एक अजगर वस्तु है। मैं ऑब्जेक्ट विशेषताओं पर पुनरावृति करना चाहता हूं।

class my_python_obj(object):
    attr1='a'
    attr2='b'
    attr3='c'

    def method1(self, etc, etc):
        #Statements

मैं सभी ऑब्जेक्ट्स विशेषताओं और उनके वर्तमान मानों वाला एक शब्दकोश उत्पन्न करना चाहता हूं, लेकिन मैं इसे एक गतिशील तरीके से करना चाहता हूं (इसलिए यदि बाद में मैं एक और विशेषता जोड़ता हूं तो मुझे अपने फ़ंक्शन को अपडेट करने के लिए याद रखने की आवश्यकता नहीं है)।

Php वेरिएबल्स में कुंजियों के रूप में उपयोग किया जा सकता है, लेकिन अजगर में ऑब्जेक्ट्स अकारण होते हैं और अगर मैं इसके लिए डॉट नोटेशन का उपयोग करता हूं, तो यह मेरी var के नाम के साथ एक नई विशेषता बनाता है, जो मेरा इरादा नहीं है।

बस चीजों को स्पष्ट करने के लिए:

def to_dict(self):
    '''this is what I already have'''
    d={}
    d["attr1"]= self.attr1
    d["attr2"]= self.attr2
    d["attr3"]= self.attr3
    return d

·

def to_dict(self):
    '''this is what I want to do'''
    d={}
    for v in my_python_obj.attributes:
        d[v] = self.v
    return d

अद्यतन: विशेषताओं के साथ मेरा मतलब है कि इस ऑब्जेक्ट के केवल चर, तरीके नहीं हैं।


3
stackoverflow.com/questions/1251692/… कुछ मदद हो सकती है।
शॉन

@ सीन विशेष रूप से, stackoverflow.com/a/1251789/4203 जाने का रास्ता है; आप predicateएक कॉल करने योग्य पास के लिए वैकल्पिक तर्क का उपयोग करेंगे जो कि फ़िल्टर (बाध्य?) फ़ंक्शंस (जो विधियों से छुटकारा दिलाता है) होगा।
हांक गे

प्रति शॉन, क्या यह आपके प्रश्न का उत्तर देता है? पायथन में किसी ऑब्जेक्ट के गुणों की गणना कैसे करें?
डेविस हेरिंग

जवाबों:


227

मान लें कि आपके पास एक वर्ग है जैसे कि

>>> class Cls(object):
...     foo = 1
...     bar = 'hello'
...     def func(self):
...         return 'call me'
...
>>> obj = Cls()

dirऑब्जेक्ट पर कॉल करना आपको उस ऑब्जेक्ट की सभी विशेषताओं को वापस देता है, जिसमें अजगर विशेष गुण भी शामिल है। यद्यपि कुछ ऑब्जेक्ट विशेषताएँ कॉल करने योग्य हैं, जैसे कि विधियाँ।

>>> dir(obj)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'foo', 'func']

आप सूची बोध का उपयोग करके हमेशा विशेष विधियों को फ़िल्टर कर सकते हैं।

>>> [a for a in dir(obj) if not a.startswith('__')]
['bar', 'foo', 'func']

या यदि आप मानचित्र / फ़िल्टर पसंद करते हैं।

>>> filter(lambda a: not a.startswith('__'), dir(obj))
['bar', 'foo', 'func']

यदि आप विधियों को फ़िल्टर करना चाहते हैं, तो आप callableचेक के रूप में बिलिन का उपयोग कर सकते हैं ।

>>> [a for a in dir(obj) if not a.startswith('__') and not callable(getattr(obj, a))]
['bar', 'foo']

आप अपनी कक्षा और इसके उदाहरण ऑब्जेक्ट के उपयोग के बीच के अंतर का भी निरीक्षण कर सकते हैं।

>>> set(dir(Cls)) - set(dir(object))
set(['__module__', 'bar', 'func', '__dict__', 'foo', '__weakref__'])

1
यह एक बुरा विचार है, मैं इसका सुझाव भी नहीं दूंगा, लेकिन यदि आप जा रहे हैं, तो कम से कम कैविएट प्रदान करें।
जूलियन

2
@Meitham @Pablo क्या गलत है मुख्यतः यह है कि आपको ऐसा करने की आवश्यकता नहीं है। कौन सी विशेषताएँ आप में रुचि रखते हैं अनन्य नहीं समावेशी होना चाहिए । जैसा कि आप पहले ही देख चुके हैं, आप विधियाँ शामिल कर रहे हैं, और उन्हें बाहर करने का कोई भी प्रयास त्रुटिपूर्ण होगा, क्योंकि वे या तो जैसी गंदी चीजें शामिल करने जा रहे हैं । यदि मैं "_foo" नामक एक विशेषता जोड़ता हूं, जो कुछ मध्यवर्ती परिणाम, या आंतरिक डेटा संरचना को संग्रहीत करता है? क्या होता है अगर मैं केवल हानिरहित रूप से कक्षा में एक विशेषता जोड़ता हूं, ए , कहता हूं, और अब अचानक यह शामिल हो जाता है। callabletypes.MethodTypename
जूलियन

3
@ जूलियन उपरोक्त कोड दोनों को चुन लेगा _fooऔर nameक्योंकि वे अब ऑब्जेक्ट की विशेषता हैं। यदि आप उन्हें शामिल नहीं करना चाहते हैं तो आप उन्हें सूची बोध स्थिति में बाहर कर सकते हैं। ऊपर दिया गया कोड एक सामान्य अजगर मुहावरा है और अजगर की वस्तुओं को आत्मसात करने का लोकप्रिय तरीका है।
मित्थम

30
वास्तव में obj .__ dict__ इस उद्देश्य के लिए (शायद) बेहतर है।
डेव

5
@ जूलियन dir()केवल "झूठ" करता है जब पास किए गए मेटाक्लासेस (एक चरम किनारे का मामला) या वर्गों @DynamicClassAttribute(एक और चरम किनारे के मामले) द्वारा सजाई गई विशेषताओं के साथ । दोनों मामलों में, dirs()आवरण को inspect.getmembers()हल करने से यह हल होता है। मानक वस्तुओं के लिए, हालांकि, इस समाधान की सूची समझ दृष्टिकोण गैर-कॉलबेल को पूरी तरह से दबा देता है। कि कुछ पाइथोनिस्टस इसे "बुरा विचार" कहेंगे, यह मुझे चकित कर देगा, लेकिन ... प्रत्येक अपने स्वयं के लिए, मुझे लगता है?
सेसिल करी

57

सामान्य तौर __iter__पर अपने वर्ग में एक विधि डालते हैं और ऑब्जेक्ट विशेषताओं के माध्यम से पुनरावृति करते हैं या इस मिश्रण वर्ग को अपनी कक्षा में रखते हैं।

class IterMixin(object):
    def __iter__(self):
        for attr, value in self.__dict__.iteritems():
            yield attr, value

आपकी कक्षा:

>>> class YourClass(IterMixin): pass
...
>>> yc = YourClass()
>>> yc.one = range(15)
>>> yc.two = 'test'
>>> dict(yc)
{'one': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], 'two': 'test'}

यह केवल जब काम करता है oneऔर twoबाद परिभाषित किया गया है yc = YourClass()। प्रश्न मौजूदा अटार्नी के माध्यम से लूपिंग के बारे में पूछता है YourClass()। इसके अलावा, IterMixinवर्ग को विरासत में देना हमेशा समाधान के रूप में उपलब्ध नहीं हो सकता है।
जिओ

4
vars(yc)दूसरे वर्ग से विरासत में मिले बिना एक ही परिणाम देता है।
नाथन

1
मेरी उपरोक्त टिप्पणी बिल्कुल सही नहीं है; vars(yc)लगभग समान है, लेकिन यह जो शब्दकोश आपको वापस देता है वह उदाहरण का अपना है __dict__, इसलिए इसे संशोधित करके उदाहरण पर प्रतिबिंबित किया जाएगा। यह समस्याएँ पैदा कर सकता है यदि आप सावधान नहीं हैं, तो उपरोक्त विधि कभी-कभी बेहतर हो सकती है (हालांकि शब्दकोश की नकल करना शायद आसान है)। यह भी ध्यान दें, जबकि ऊपर दिया गया शब्दकोश उदाहरण का नहीं है __dict__, मान समान हैं, इसलिए किसी भी परिवर्तनशील मूल्यों को संशोधित करना अभी भी उदाहरण की विशेषताओं में दिखाई देगा।
नाथन

25

जैसा कि पहले से ही कुछ उत्तर / टिप्पणियों में उल्लेख किया गया है, पायथन ऑब्जेक्ट्स पहले से ही अपनी विशेषताओं (विधियों को शामिल नहीं किया गया है) का एक शब्दकोश संग्रहीत करते हैं। इसे एक्सेस किया जा सकता है __dict__, लेकिन इसका उपयोग करने का बेहतर तरीका है vars(आउटपुट समान है, हालांकि)। ध्यान दें कि इस शब्दकोश को संशोधित करने से उदाहरण पर विशेषताओं को संशोधित किया जाएगा! यह उपयोगी हो सकता है, लेकिन इसका मतलब यह भी है कि आपको इस शब्दकोश का उपयोग करने से सावधान रहना चाहिए। यहाँ एक त्वरित उदाहरण है:

class A():
    def __init__(self, x=3, y=2, z=5):
        self.x = x
        self._y = y
        self.__z__ = z

    def f(self):
        pass

a = A()
print(vars(a))
# {'x': 3, '_y': 2, '__z__': 5}
# all of the attributes of `a` but no methods!

# note how the dictionary is always up-to-date
a.x = 10
print(vars(a))
# {'x': 10, '_y': 2, '__z__': 5}

# modifying the dictionary modifies the instance attribute
vars(a)["_y"] = 20
print(vars(a))
# {'x': 10, '_y': 20, '__z__': 5}

का उपयोग करना dir(a)एक अजीब है, अगर एकमुश्त बुरा नहीं है, तो इस समस्या से संपर्क करें। यह अच्छा है अगर आपको वास्तव में कक्षा की सभी विशेषताओं और विधियों पर (विशेष विधियों जैसे __init__) को पुनरावृत्त करने की आवश्यकता है । हालाँकि, ऐसा नहीं लगता है कि आप क्या चाहते हैं, और यहां तक ​​कि स्वीकृत उत्तर भी खराब तरीके से इस बारे में कुछ भंगुर फ़िल्टरिंग करके तरीकों को हटाने की कोशिश करते हैं और सिर्फ विशेषताओं को छोड़ देते हैं; आप देख सकते हैं कि Aऊपर बताई गई कक्षा के लिए यह कैसे विफल होगा ।

(उपयोग __dict__एक-दो उत्तर में किया गया है, लेकिन वे सभी सीधे उपयोग करने के बजाय अनावश्यक तरीकों को परिभाषित करते हैं। केवल एक टिप्पणी का उपयोग करने का सुझाव देते हैं vars)।


1
कुछ ऐसा है जिसे मैं vars () दृष्टिकोण के साथ नहीं समझ पाया हूं कि वह स्थिति कैसे संभाली जाए जहां वर्ग A में एक सदस्य है जो एक अन्य वस्तु है जिसका प्रकार उपयोगकर्ता-परिभाषित वर्ग B. vars (a) लगता है __repr __ () इसके प्रकार बी के सदस्य __repr __ (), जैसा कि मैं समझता हूं, एक स्ट्रिंग वापस करने वाला है। लेकिन जब मैं vars (a) कहता हूं, तो ऐसा लगता है कि इस कॉल के लिए नेस्टेड
तानाशाह के

1
यदि आपके पास a.bकुछ कस्टम वर्ग के रूप में है, Bतो vars(a)["b"] is a.bजैसा कि कोई उम्मीद करेगा; और कुछ नहीं वास्तव में समझ में आता है (के लिए के a.bरूप में कृत्रिम चीनी के बारे में सोचना a.__dict__["b"])। यदि आपके पास है d = vars(a)और कॉल करता है repr(d)तो यह repr(d["b"])रिटर्निंग के हिस्से के रूप में कॉल करेगा यह स्वयं का री-स्ट्रिंग है क्योंकि केवल वर्ग Bवास्तव में जानता है कि इसे स्ट्रिंग के रूप में कैसे दर्शाया जाना चाहिए।
नाथन

2

अजगर की वस्तुएं अपने एट्रिब्यूशन (कार्यों सहित) को एक तानाशाह कहलाती हैं __dict__। आप सीधे विशेषताओं को एक्सेस करने के लिए इसका उपयोग कर सकते हैं (लेकिन आमतौर पर ऐसा नहीं करना चाहिए)। यदि आप केवल एक सूची चाहते हैं, तो आप कॉल भी कर सकते हैं dir(obj), जो सभी विशेषता नामों के साथ एक पुनरावृत्ति देता है, जिसे आप तब पास कर सकते हैं getattr

हालांकि, चर के नाम के साथ कुछ भी करने की आवश्यकता आमतौर पर खराब डिजाइन है। उन्हें एक संग्रह में क्यों नहीं रखा गया?

class Foo(object):
    def __init__(self, **values):
        self.special_values = values

फिर आप कुंजी के साथ पुनरावृति कर सकते हैं for key in obj.special_values:


क्या आप थोड़ा और समझा सकते हैं कि जो मैं चाहता हूं उसे हासिल करने के लिए मैं संग्रह का उपयोग कैसे करूंगा?
पाब्लो मेचर

1
मैं गतिशील रूप से ऑब्जेक्ट में विशेषताएँ नहीं जोड़ रहा हूँ। मेरे पास जो चर हैं वे लंबे समय तक एक ही रहेंगे, हालांकि मुझे लगता है कि जो मैं करना चाहता हूं, वह कुछ करने में सक्षम होना अच्छा होगा।
पाब्लो मेचर

1
class someclass:
        x=1
        y=2
        z=3
        def __init__(self):
           self.current_idx = 0
           self.items = ["x","y","z"]
        def next(self):
            if self.current_idx < len(self.items):
                self.current_idx += 1
                k = self.items[self.current_idx-1]
                return (k,getattr(self,k))
            else:
                raise StopIteration
        def __iter__(self):
           return self

तो बस इसे चलने के रूप में कहते हैं

s=someclass()
for k,v in s:
    print k,"=",v

यह बहुत जटिल लगता है। अगर मेरे पास कोई विकल्प नहीं है, तो मैं अभी जो कर रहा हूं उसके साथ नहीं रहूंगा।
पाब्लो मेचर

0

इसका सही उत्तर यह है कि आपको नहीं करना चाहिए। यदि आप इस प्रकार की चीज़ चाहते हैं तो या तो केवल एक तानाशाही का उपयोग करें, या आपको कुछ कंटेनर में स्पष्ट रूप से विशेषताओं को जोड़ना होगा। आप डेकोरेटर्स के बारे में जानकर इसे स्वचालित बना सकते हैं।

विशेष रूप से, वैसे, आपके उदाहरण में Method1 एक विशेषता के रूप में अच्छा है।


2
हाँ, मुझे पता है कि मुझे नहीं करना चाहिए .. लेकिन यह मुझे समझने में मदद करता है कि चीजें कैसे काम करती हैं। मैं एक php पृष्ठभूमि से आते हैं और दैनिक बातें इस तरह करते थे
पाब्लो Mescher

आपने मुझे मना लिया। To_dict () विधि को अद्यतन रखना अब तक किसी भी उत्तर की तुलना में अधिक सीधा है।
पाब्लो मेचर

1
क्या कोई ऐसे लोग बचे हैं जो हठधर्मिता की सलाह से बचेंगे। यदि आप सावधान नहीं हैं, तो गतिशील प्रोग्रामिंग आपको जलाएगी, लेकिन उपयोग की जाने वाली भाषा में विशेषताएं हैं।
हेनरिक वेंडेल्बो

0

अजगर 3.6 के लिए

class SomeClass:

    def attr_list(self, should_print=False):

        items = self.__dict__.items()
        if should_print:
            [print(f"attribute: {k}    value: {v}") for k, v in items]

        return items

6
क्या आप अपनी पोस्ट में कुछ स्पष्टीकरण जोड़ सकते हैं, ताकि गैर-पेशेवर अजगर आपके उत्तर से लाभान्वित हो सकें?
not2qubit

-3

सभी pythonian zealots के लिए वहाँ मुझे यकीन है कि जोहान क्लीज़ आपके कुत्तेवाद का अनुमोदन करेंगे;)। मैं इस जवाब को छोड़ रहा हूं इसे ध्वस्त करते रहें यह वास्तव में मुझे अधिक विश्वासपात्र बनाता है। एक टिप्पणी छोड़ दो तुम मुर्गियों!

अजगर 3.6 के लिए

class SomeClass:

    def attr_list1(self, should_print=False):

        for k in self.__dict__.keys():
            v = self.__dict__.__getitem__(k)
            if should_print:
                print(f"attr: {k}    value: {v}")

    def attr_list(self, should_print=False):

        b = [(k, v) for k, v in self.__dict__.items()]
        if should_print:
            [print(f"attr: {a[0]}    value: {a[1]}") for a in b]
        return b

क्या इस सवाल पर आपके दो जवाब हैं?
नाथन

@ नथन इसलिए है क्योंकि एक और क्रिया है और दूसरा अधिक पायथन। मुझे यह भी पता नहीं था कि कौन सी तेजी से चलती है इसलिए मैंने पाठक को चुनने का फैसला किया।
रबर डक

@ नथन आप अजगर हैं या ओवरफ्लो पुलिस? अलग-अलग कोडिंग स्टाइल हैं। मैं एक गैर पाइथोनिक को पसंद करता हूं क्योंकि मैं कई भाषाओं और तकनीकों में काम करता हूं और मुझे लगता है कि यह आइडियलसिंक्रेटिक हो जाता है। फिर भी आइस्ट की समझ ठंडी और संक्षिप्त है। तो प्रबुद्ध पाठक दोनों को क्यों नहीं?
रबर डक

सभी pythonian zealots के लिए मुझे यकीन है कि जोहान क्लीज़ आपके हठधर्मिता को स्वीकार करेंगे;)। मैं यह उत्तर छोड़ रहा हूं, इसे ध्वस्त करते रहें यह वास्तव में मुझे अधिक विश्वासपात्र बनाता है। एक टिप्पणी छोड़ दो तुम मुर्गियों!
रबर डक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.