मैं एक वस्तु कैसे बना सकता हूं और उसमें विशेषताएँ कैसे जोड़ सकता हूं?


310

मैं पायथन में एक गतिशील वस्तु (किसी अन्य वस्तु के अंदर) बनाना चाहता हूं और फिर उसमें विशेषताएँ जोड़ना चाहता हूं।

मैंने कोशिश की:

obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')

लेकिन यह काम नहीं किया।

कोई विचार?

संपादित करें:

मैं forलूप से उन विशेषताओं को सेट कर रहा हूं, जो मानों की सूची के माध्यम से लूप करता है, जैसे

params = ['attr1', 'attr2', 'attr3']
obj = someobject
obj.a = object()

for p in params:
   obj.a.p # where p comes from for loop variable

ऊपर के उदाहरण मैं मिलेगा में obj.a.attr1, obj.a.attr2, obj.a.attr3

मैंने setattrफ़ंक्शन का उपयोग किया क्योंकि मुझे नहीं पता था कि लूप obj.a.NAMEसे कैसे करना है for

मैं pउपरोक्त उदाहरण में मूल्य के आधार पर विशेषता कैसे निर्धारित करूंगा ?


4
"काम नहीं किया" से आपका क्या मतलब है? मुझे लगता है कि यह एक विशेषता अपवाद है, सही उठाया?
जोश राइट

1
हाँ। 'ऑब्जेक्ट' ऑब्जेक्ट की कोई विशेषता नहीं है 'somefield'
जॉन

6
आप यह क्यों कर रहे हैं? एक सामान्य "वस्तु" का कोई वास्तविक अर्थ नहीं है । आपके द्वारा बनाई जा रही चीज़ का अर्थ क्या है ? यह एक उचित वर्ग या नामांकित क्यों नहीं है?
S.Lott

1
उदाहरण मेरे लिए न्यूनतम और भ्रामक नहीं है या मैं यह नहीं देखता कि आप कुछ के साथ काम क्यों नहीं करते हैं a = object()और आपको जरूरत है obj.a = object()। फिर से मैं उदाहरण के बारे में बात कर रहा हूं, आपके वास्तविक कोड में एक वस्तु के अंदर एक वस्तु उपयोगी हो सकती है।
कोन साइक

जवाबों:


215

आप मेरी प्राचीन बंच रेसिपी का उपयोग कर सकते हैं , लेकिन यदि आप " बंच क्लास" नहीं बनाना चाहते हैं, तो पाइथन में एक बहुत ही सरल पहले से ही मौजूद है - सभी कार्यों में मनमाने गुण (लंबोदर फ़ंक्शन सहित) हो सकते हैं। तो, निम्नलिखित काम करता है:

obj = someobject
obj.a = lambda: None
setattr(obj.a, 'somefield', 'somevalue')

क्या आदरणीय Bunchनुस्खा की तुलना में स्पष्टता का नुकसान ठीक है, एक शैली निर्णय है जो मैं निश्चित रूप से आपके ऊपर छोड़ दूंगा।


25
@FogleBird, एक शैली निर्णय, जैसा कि मैंने उल्लेख किया है। चर्च के लैम्ब्डा कैलकुलस में प्रशिक्षित कुछ सीएस विशेषज्ञों का उपयोग फ़ंक्शंस (लैम्ब्डा) के बारे में सोचने के लिए किया जाता है, जो कि सभी डेटा के मूल प्रकार (पूर्णांक 23, उदाहरण के लिए, इसके बराबर के रूप में देखे जा सकते हैं lambda: 23), इसलिए ऐसे विशेषज्ञ lambdaइस उद्देश्य के लिए उपयोग कर रहे हैं। संभवतः "हैक" जैसा कुछ भी महसूस नहीं होगा। निजी तौर पर, मैं lambda पायथन में बहुत पसंद नहीं करता हूं - लेकिन यह व्यक्तिगत स्वाद का एक मुद्दा है।
एलेक्स मार्टेली

और कुछ मामलों में, इस बात पर विचार करना कि lambdaआपके उपयोग के मामले में पैटर्न फिट बैठता है या नहीं, आपको एहसास हो सकता है कि आपके द्वारा मूल रूप से डेटा के बारे में सोचा गया कुछ भी वास्तव में एक फ़ंक्शन की तरह अधिक है - या, किसी भी मामले में, एक फ़नकार।
काइल स्ट्रैंड

5
@ naught101, एक समारोह है तो अपने आपत्ति अथाह है, एक वस्तु, पायथन में।
एलेक्स मार्टेली

6
@ naught101, एक नए प्रकार के निर्माण से बचना (किसी मौजूदा का पुन: उपयोग करना) जटिल नहीं है, यह सरल करता है। आजकल पर वास्तव में पसंद कर सकते हैं from argparse import Namespaceहालांकि मैं चाहता हूँ कि यह कहीं और रहता है * उदा, collection) - फिर से अब एक मौजूदा प्रकार का पुन: उपयोग करना, बस एक बेहतर, और अभी भी नए प्रकार के निर्माण से बचना। लेकिन, यह तब नहीं था :-)।
एलेक्स मार्टेली 14

1
प्रकार मॉड्यूल से SimpleNamespace के बारे में "JF सेबस्टियन" से नीचे का जवाब देखें। अगर अजगर का आपका संस्करण इसका समर्थन करता है, तो यह सबसे अच्छा समाधान है (और वास्तव में सिंपलनेमैपेस के लिए क्या डिज़ाइन किया गया है)
टिम रिचर्डसन

333

बिल्ट-इन objectको तत्काल किया जा सकता है, लेकिन इस पर कोई विशेषता सेट नहीं की जा सकती है। (मुझे लगता है कि यह इस सटीक उद्देश्य के लिए कर सकता है।) यह __dict__विशेषताओं को रखने के लिए नहीं है ।

मैं आम तौर पर सिर्फ यही करता हूं:

class Object(object):
    pass

a = Object()
a.somefield = somevalue

जब मैं कर सकता हूं, तो मैं Objectकक्षा को एक अधिक सार्थक नाम देता हूं , जो इस बात पर निर्भर करता है कि मैं किस तरह का डेटा डाल रहा हूं।

कुछ लोग एक अलग काम करते हैं, जहां वे एक उप-वर्ग का dictउपयोग करते हैं जो कुंजी तक पहुंचने के लिए विशेषता पहुंच की अनुमति देता है। (के d.keyबजाय d['key'])

संपादित करें : अपने प्रश्न के अतिरिक्त के लिए, का उपयोग setattrकरना ठीक है। आप सिर्फ उदाहरणों setattrपर उपयोग नहीं कर सकते object()

params = ['attr1', 'attr2', 'attr3']
for p in params:
    setattr(obj.a, p, value)

9
इसे तुरंत किया जा सकता है, बस एक बार काम करने के बाद इसका उपयोग नहीं किया जाता है। foo = object()काम करता है, लेकिन आप इसके साथ ज्यादा कुछ नहीं कर सकते हैं
डैनियल डायपोलो

नमस्ते। जवाब के लिए धन्यवाद। मैंने ऊपर अपनी समस्या अपडेट की है। संपादन देखें। क्या आप इसका उत्तर जानते हैं?
जॉन

क्षमा करें, मैं अभी भी इसे ऑब्जेक्ट पर सेट करना चाहता हूं। ऊपर अद्यतन देखें।
जॉन

मैं वास्तव में आपके उत्तर को पसंद करता हूं और मुझे लगता है कि मैं भविष्य में इस दिशा में झुकूंगा। मैंने इस पोस्ट पर इस सरल, समझने योग्य और पठनीय कार्यप्रणाली को छोड़कर बाकी सब के बारे में उपयोग किया है। type....मेरे कोड में टेक्स्ट उल्टी की तरह लैंबडा का उपयोग करना या मेरा फेव कभी नहीं था। लेकिन गुणों को धारण करने के लिए वस्तुओं का उपयोग करने के लिए यह विचार महान है। कोड को अधिक पठनीय बी / सी छोड़ता है जब मैं लंबोदर को देखता हूं तो मैं अपने पढ़ने को 25% तक धीमा कर देता हूं जबकि आपका तरीका कुल समझ में आता है! धन्यवाद।
मार्क

महान जवाब, केवल एक चीज जो मैंने बदली वह थी Structकक्षा के नाम के रूप में उपयोग करना और अधिक स्पष्ट करना। मुझे टाइपिंग का एक टन बचाया ["और "], चीयर्स!
प्राग्मैन

137

नहीं है types.SimpleNamespaceपायथन में 3.3+ वर्ग :

obj = someobject
obj.a = SimpleNamespace()
for p in params:
    setattr(obj.a, p, value)
# obj.a.attr1

collections.namedtuple, typing.NamedTupleअपरिवर्तनीय वस्तुओं के लिए इस्तेमाल किया जा सकता है। PEP 557 - डेटा कक्षाएं एक परस्पर विकल्प का सुझाव देती हैं।

एक समृद्ध कार्यक्षमता के लिए, आप पैकेज की कोशिशattrs कर सकते हैं । एक उदाहरण उपयोग देखें ।


3
अगर आपको पाइथन 2.7 के साथ काम करने वाली कोई चीज़ चाहिए, तो आप argparse.Namespaceक्लास को भी आज़मा सकते हैं
RolKau

सहमत - मैं उत्सुक हूँ अगर यहाँ एक नकारात्मक पक्ष है, लेकिन यह एक अविश्वसनीय रूप से आसान अजगर 3.3+ खर्च है।
घुकिल

अरे नहीं! यह 2.7 पर उपलब्ध नहीं है?
Roel

@ रील attrsपैकेज पायथन 2.7 का समर्थन करता है
jfs

यह मुझे unittest.mock से बेहतर समाधान लगता है; उत्तरार्द्ध थोड़ा भारी है और थोड़ा अधिक निंदनीय है। एक नकली वस्तु के साथ, बस एक विशेषता को असाइन करने से यह अस्तित्व में वसंत का कारण होगा; SimpleNamespace कि विरोध करेगा।
jdzions

32

इस लक्ष्य तक पहुंचने के लिए कुछ तरीके हैं। मूल रूप से आपको एक वस्तु की आवश्यकता होती है जो विस्तार योग्य हो।

obj.a = type('Test', (object,), {})  
obj.a.b = 'fun'  

obj.b = lambda:None

class Test:
  pass
obj.c = Test()

14
obj.a = type('', (), {})
iman

26

mockमॉड्यूल मूल रूप से उस के लिए किया जाता है।

import mock
obj = mock.Mock()
obj.a = 5

3
नुकसान यह है कि एक बाहरी निर्भरता है
कांगुर

5
unittest.Mockपायथन 3.3 के बाद से मानक पुस्तकालय का एक हिस्सा है ( docs.python.org/3/library/unittest.mock.html )
इलग्रेनन

2
मुझे लगता है कि आपके कोड के उपयोग पर निर्भर करता है यदि यह उत्पादन कोड है, तो मैं mockइसमें कुछ नहीं चाहूंगा । बस मुझे अजीब लगता है।
माइक डे क्लार्क

21

अब आप कर सकते हैं (यह सुनिश्चित नहीं है कि अगर यह badpie के रूप में एक ही जवाब है):

MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42

@ badpie के उत्तर सेट की विशेषता सीधे MyObject (कक्षा) पर है, न कि आपकी तरह इसका उदाहरण।
jfs

18

नीचे दिए गए कोड को आज़माएं:

$ python
>>> class Container(object):
...     pass 
...
>>> x = Container()
>>> x.a = 10
>>> x.b = 20
>>> x.banana = 100
>>> x.a, x.b, x.banana
(10, 20, 100)
>>> dir(x)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__',     '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'banana']

1
क्या आप इस बारे में अधिक बता सकते हैं कि यह क्या करता है? जबकि कोड इस समस्या को हल करने के लिए उपयोगी हो सकता है, यह समझाया गया है कि यह सिर्फ एक समस्या से बहुत आगे जा सकता है।
डेडचेक्स

1
@DeadChex स्पष्ट रूप से यह एक नया वर्ग (ऑब्जेक्ट) बनाता है जो ऑब्जेक्ट गुणों के साथ एक खाली वर्ग है, और वर्ग के अंदर विशेषताओं को संग्रहीत करता है। यह अधिक मॉड्यूल स्थापित करने, या लैम्ब्डा में भरोसा करने से भी बेहतर है।
m3nda

2
सुनिश्चित नहीं हैं कि यह अधिक upvotes क्यों नहीं है। क्या एक बुनियादी कंटेनर वर्ग के लिए इसका उपयोग नहीं करने का एक कारण है? Python 2.7, 2.6 और 3.4 में ठीक काम करने लगता है
user5359531

17

आप सीधे एक क्लास ऑब्जेक्ट का भी उपयोग कर सकते हैं; यह एक नामस्थान बनाता है:

class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')


2

परीक्षण के दौरान ये समाधान बहुत सहायक हैं। बाकी सभी के जवाबों के आधार पर मैं इसे पायथन 2.7.9 में कर रहा हूं (स्टैमेथेथोड के बिना मुझे एक टाइपर (अनबाउंड विधि ...) मिलता है:)

In [11]: auth = type('', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4

1

आप किन वस्तुओं का उपयोग कर रहे हैं? बस एक नमूना वर्ग के साथ कोशिश की और यह ठीक काम किया:

class MyClass:
  i = 123456
  def f(self):
    return "hello world"

b = MyClass()
b.c = MyClass()
setattr(b.c, 'test', 123)
b.c.test

और मुझे मिल गया 123 जवाब के रूप में ।

केवल एक ही स्थिति जहाँ मैं यह असफलता देख रहा हूँ यदि आप setattrएक बिलियन ऑब्जेक्ट पर कोशिश कर रहे हैं ।

अद्यतन: टिप्पणी से यह एक पुनरावृत्ति है: आप अजगर में ऑब्जेक्ट के लिए विशेषताओं को क्यों नहीं जोड़ सकते हैं?


bc ऑब्जेक्ट पर सेट है () एक परिभाषित वर्ग नहीं
जॉन

0

दिन में देर से आना लेकिन यहाँ एक वस्तु के साथ मेरा पैसा है जो सिर्फ एक ऐप में कुछ उपयोगी रास्तों को रखने के लिए होता है, लेकिन आप इसे किसी भी चीज़ के लिए अनुकूलित कर सकते हैं जहाँ आप एक सूचना की एक तरह से जानकारी चाहते हैं जिसे आप getattr और डॉट राशन से एक्सेस कर सकते हैं। (जो मुझे लगता है कि यह सवाल वास्तव में है):

import os

def x_path(path_name):
    return getattr(x_path, path_name)

x_path.root = '/home/x'
for name in ['repository', 'caches', 'projects']:
    setattr(x_path, name, os.path.join(x_path.root, name))

यह अच्छा है क्योंकि अब:

In [1]: x_path.projects
Out[1]: '/home/x/projects'

In [2]: x_path('caches')
Out[2]: '/home/x/caches'

इस का उपयोग करता है तो इसके बाद के संस्करण जवाब लेकिन जैसे समारोह वस्तु मूल्यों (आप अभी भी उपयोग कर सकते हैं पाने के लिए समारोह का उपयोग करता है (getattr, x_path, 'repository')के बजाय x_path('repository')अगर आप पसंद करते हैं)।


0

यदि हम नेस्टेड ऑब्जेक्ट बनाने से पहले सभी विशेषताओं और मूल्यों को एक साथ निर्धारित और एकत्र कर सकते हैं, तो हम एक नया वर्ग बना सकते हैं जो निर्माण पर एक डिक्शनरी तर्क लेता है।

# python 2.7

class NestedObject():
    def __init__(self, initial_attrs):
        for key in initial_attrs:
            setattr(self, key, initial_attrs[key])

obj = someobject
attributes = { 'attr1': 'val1', 'attr2': 'val2', 'attr3': 'val3' }
obj.a = NestedObject(attributes)
>>> obj.a.attr1
'val1'
>>> obj.a.attr2
'val2'
>>> obj.a.attr3
'val3'

हम खोजशब्द तर्क भी दे सकते हैं। इस पोस्ट को देखें ।

class NestedObject(object):
    def __init__(self, *initial_attrs, **kwargs):
        for dictionary in initial_attrs:
            for key in dictionary:
                setattr(self, key, dictionary[key])
        for key in kwargs:
            setattr(self, key, kwargs[key])


obj.a = NestedObject(attr1='val1', attr2='val2', attr3= 'val3')

-2
di = {}
for x in range(20):
    name = '_id%s' % x
    di[name] = type(name, (object), {})
    setattr(di[name], "attr", "value")

-2

अन्य तरीके से मैं देख रहा हूँ, इस तरह से:

import maya.cmds

def getData(objets=None, attrs=None):
    di = {}
    for obj in objets:
        name = str(obj)
        di[name]=[]
        for at in attrs:
            di[name].append(cmds.getAttr(name+'.'+at)[0])
    return di

acns=cmds.ls('L_vest_*_',type='aimConstraint')
attrs=['offset','aimVector','upVector','worldUpVector']

getData(acns,attrs)

आप इस नाम को जोड़ सकते हैं जैसे कि यह di [name] .append ([at, cmds.getAttr (नाम + '।' + at) [0]])
पाब्लो इमैनुअल डी लियो

1
यह एक बहुत बड़ी गैर-मानक निर्भरता को जोड़ रहा है जबकि एक सरल class a: passसभी आवश्यक शक्ति देता है।
एलेक्सिस पेस ने
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.