আপনি কীভাবে পাইথনে ভেরিয়েবল আর্গুমেন্ট (কাওয়ার্গস) থেকে শ্রেণি বৈশিষ্ট্য নির্ধারণ করতে পারেন


119

ধরুন আমার কাছে কনস্ট্রাক্টর (বা অন্যান্য ফাংশন) সহ একটি ক্লাস রয়েছে যা একটি পরিবর্তনশীল সংখ্যক আর্গুমেন্ট গ্রহণ করে এবং তারপরে শর্ত অনুসারে শ্রেণীর বৈশিষ্ট্য হিসাবে সেট করে।

আমি সেগুলি ম্যানুয়ালি সেট করতে পারলাম, তবে মনে হচ্ছে ভেরিয়েবল প্যারামিটারগুলি অজগরের পক্ষে যথেষ্ট সাধারণ যে এটি করার জন্য একটি সাধারণ অভিবাদন থাকা উচিত। তবে কীভাবে এটি গতিশীলভাবে করা যায় তা আমি নিশ্চিত নই।

আমার কাছে উদাহরণ ব্যবহার করে ইওল ব্যবহার করা হয়েছে তবে এটি নিরাপদ নয়। আমি এটি করার সঠিক উপায়টি জানতে চাই - সম্ভবত ল্যাম্বডা দিয়ে?

class Foo:
    def setAllManually(self, a=None, b=None, c=None):
        if a!=None: 
            self.a = a
        if b!=None:
            self.b = b
        if c!=None:
            self.c = c
    def setAllWithEval(self, **kwargs):
        for key in **kwargs:
            if kwargs[param] != None
                eval("self." + key + "=" + kwargs[param])

দেখে মনে হচ্ছে এই প্রশ্নগুলোর মত অনুরূপ আছেন: stackoverflow.com/questions/3884612/... stackoverflow.com/questions/356718/... stackoverflow.com/questions/1446555/... তাই এটি আমি কি চাই দেখে মনে হচ্ছে হয়তো আপাততঃ স্ব হয় .__ dict__ [কী] = কাওয়ার্গস [কী]
ফিজিয়ারাওন

আপনার প্রশ্নের সাথে সত্যিই প্রাসঙ্গিক নয়, তবে আপনি প্রচলিত পাইথন স্টাইলিংয়ের কয়েকটি ইঙ্গিতগুলির জন্য PEP8 পরীক্ষা করতে চাইতে পারেন ।
থমাস অরোজকো

এই অ্যাটর্স নামে পরিচিতদের জন্য একটি দুর্দান্ত লাইব্রেরি রয়েছে। সহজেই pip install attrs, আপনার শ্রেণিটি দিয়ে সজ্জিত করুন @attr.sএবং আরগগুলি সেট করুন a = attr.ib(); b = attr.ib()ইত্যাদি আরও এখানে পড়ুন ।
অ্যাডাম বার্নেস

আমি কি এখানে কিছু মিস করছি? আপনাকে এখনও সেলফ.এক্স = কেয়ার্গস.জেট'এক্স করতে হবে] আপনি নিজেকে কলারের কাছ থেকে টাইপসের জন্য উন্মুক্ত করুন আপনাকে অতিরিক্ত অক্ষর সহ ক্লায়েন্ট তৈরি করতে হবে উদাহরণ = বর্গ (**}}) আপনি যদি হুপের মাধ্যমে ঝাঁপ না দেন তবে self.x = kwargs.get'x '] জাগতিকতা, পরে কি আপনাকে কামড় দিবে না? অর্থাত্ স্ব.এক্সের পরিবর্তে, আপনি নিজের সাথে শেষ হবেন __ ডিক __ ['x'] লাইনটি ঠিক নীচে? অথবা getattr () হয় স্ব এর চেয়ে বেশি টাইপিং।
JGFMK

উত্তর:


147

আপনি __dict__কীওয়ার্ড আর্গুমেন্টের সাহায্যে বৈশিষ্ট্যটি (যা অভিধানের আকারে শ্রেণীর বৈশিষ্ট্য উপস্থাপন করে) আপডেট করতে পারেন :

class Bar(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

তারপর তুমি পারো:

>>> bar = Bar(a=1, b=2)
>>> bar.a
1

এবং এর মতো কিছু সহ:

allowed_keys = {'a', 'b', 'c'}
self.__dict__.update((k, v) for k, v in kwargs.items() if k in allowed_keys)

আপনি কীগুলি আগেই ফিল্টার করতে পারেন ( আপনি যদি এখনও পাইথন ২.x ব্যবহার করছেন তবে তার iteritemsপরিবর্তে itemsব্যবহার করুন)।


2
এমনকি যদি আপনি self.__dict__.update(locals())অবস্থানগত যুক্তিগুলি অনুলিপি করতে ব্যবহার করেন তবে আরও ভাল ।
জিয়ানকার্লো স্পোর্টেলি

2
আমি মনে করি আজকাল আপনার এটি দরকার আছে .. kwargs [0] .items () kwargs.iteitems এর পরিবর্তে () - (লেখার সময় আমি পাইথনটি ৩.6.৫ ব্যবহার করছি)
JGFMK

@ জিজিএফএমকে কেন কেবল ন্যায়বিচারের kwargs[0]পরিবর্তে kwargs? kwargsএমনকি একটি পূর্ণসংখ্যা কী কী থাকতে পারে? আমি নিশ্চিত যে তারা স্ট্রিং হতে হবে।
wjandrea

145

আপনি setattr()পদ্ধতিটি ব্যবহার করতে পারেন :

class Foo:
  def setAllWithKwArgs(self, **kwargs):
    for key, value in kwargs.items():
      setattr(self, key, value)

getattr()বৈশিষ্ট্য পুনরুদ্ধার করার জন্য একটি অভিন্ন পদ্ধতি রয়েছে।


@ আলার্কস ধন্যবাদ তবে কীভাবে আমরা কেবলমাত্র একটি অভিধান কী আনপ্যাক করতে পারি তার কোনও ধারণা? stackoverflow.com/questions/41792761/...
JinSnow

আপনার কি দরকার .getattr()? অথবা আপনি বৈশিষ্ট্য অ্যাক্সেস করতে পারেন Foo.key?
স্টিভয়েসিয়াক

@ স্টেভেনভ্যাসেল্লারো আপনি অবশ্যই ব্যবহার করতে পারেন Foo.attrname। আমি মনে করি যে আমি getattrপদ্ধতিটি বিদ্যমান ছিল তা সবেমাত্র নির্দেশ করছিলাম । আপনি যখন নামযুক্ত বৈশিষ্ট্যটি উপলভ্য না হয়ে থাকে তার জন্য যদি আপনি কোনও ডিফল্ট মান সরবরাহ করতে চান তবে এটি দরকারী।
লারস্ক করে

3
গৃহীত উত্তরের সাথে পার্থক্য কী ? । তাদের উপকারিতা কি?
এডুয়ার্ডো পিগনেটেলি

15

এখানে বেশিরভাগ উত্তরগুলিতে কেবলমাত্র একটি ডিফল্ট মানতে সমস্ত অনুমোদিত বৈশিষ্ট্যকে আরম্ভ করার ভাল উপায় notাকা নেই। সুতরাং, @fqxp এবং @mmj এর দেওয়া উত্তরগুলিতে যুক্ত করতে :

class Myclass:

    def __init__(self, **kwargs):
        # all those keys will be initialized as class attributes
        allowed_keys = set(['attr1','attr2','attr3'])
        # initialize all allowed keys to false
        self.__dict__.update((key, False) for key in allowed_keys)
        # and update the given keys by their given values
        self.__dict__.update((key, value) for key, value in kwargs.items() if key in allowed_keys)

আমি মনে করি inizialization এর কারণে এটি সবচেয়ে সম্পূর্ণ উত্তর False। ভাল যুক্তি!
কিরোল

9

আমি fqxp এর উত্তরের পরিবর্তনের প্রস্তাব দিচ্ছি , যা অনুমোদিত বৈশিষ্ট্যগুলি ছাড়াও আপনাকে বৈশিষ্ট্যের জন্য ডিফল্ট মান সেট করতে দেয় :

class Foo():
    def __init__(self, **kwargs):
        # define default attributes
        default_attr = dict(a=0, b=None, c=True)
        # define (additional) allowed attributes with no default value
        more_allowed_attr = ['d','e','f']
        allowed_attr = list(default_attr.keys()) + more_allowed_attr
        default_attr.update(kwargs)
        self.__dict__.update((k,v) for k,v in default_attr.items() if k in allowed_attr)

এই পাইথন 3.x কোড, পাইথন 2.x জন্য আপনাকে অন্তত একটি সমন্বয় প্রয়োজন, iteritems()স্থানে items()


1
এই থ্রেডের অন্যান্য পদ্ধতির সংক্ষিপ্তসার হিসাবে এটি সবচেয়ে নমনীয় উত্তর। এটি বৈশিষ্ট্যগুলি সেট করে, ডিফল্ট মানগুলির জন্য অনুমতি দেয় এবং কেবল অনুমোদিত বৈশিষ্ট্যের নাম যুক্ত করে। এখানে প্রদর্শিত হিসাবে পাইথন 3.x সঙ্গে সূক্ষ্ম কাজ করে।
স্কয়ারস্পাইরাল

7

তবুও অন্য বৈকল্পিক দ্বারা চমৎকার উত্তর উপর ভিত্তি করে mmj এবং fqxp । আমরা যদি চাই

  1. অনুমোদিত বৈশিষ্ট্যের একটি তালিকা হার্ডকোডিং এড়ান
  2. কনস্ট্রাক্টরের প্রতিটি বৈশিষ্ট্যের জন্য প্রত্যক্ষ এবং স্পষ্টভাবে ডিফল্ট মান সেট করে
  3. উভয় দ্বারা পূর্বনির্ধারিত বৈশিষ্ট্যে কাওয়ারগুলিকে সীমাবদ্ধ করুন
    • নিঃশব্দে অবৈধ যুক্তি প্রত্যাখ্যান করা বা বিকল্পভাবে,
    • একটি ত্রুটি উত্থাপন

"সরাসরি" দ্বারা, আমি একটি বহির্মুখী default_attributesঅভিধান এড়ানো মানে ।

class Bar(object):
    def __init__(self, **kwargs):

        # Predefine attributes with default values
        self.a = 0
        self.b = 0
        self.A = True
        self.B = True

        # get a list of all predefined values directly from __dict__
        allowed_keys = list(self.__dict__.keys())

        # Update __dict__ but only for keys that have been predefined 
        # (silently ignore others)
        self.__dict__.update((key, value) for key, value in kwargs.items() 
                             if key in allowed_keys)

        # To NOT silently ignore rejected keys
        rejected_keys = set(kwargs.keys()) - set(allowed_keys)
        if rejected_keys:
            raise ValueError("Invalid arguments in constructor:{}".format(rejected_keys))

কোনও বড় অগ্রগতি নয়, তবে কারও পক্ষে উপকারী হতে পারে ...

সম্পাদনা: যদি আমাদের শ্রেণি @propertyগেটার এবং সেটটারগুলির সাথে "সুরক্ষিত" বৈশিষ্ট্যগুলি encapsulate করতে সজ্জকার ব্যবহার করে এবং যদি আমরা আমাদের নির্মাতার সাথে এই বৈশিষ্ট্যগুলি সেট করতে সক্ষম হতে চাই তবে আমরা নীচের allowed_keysথেকে মানগুলি সহ তালিকাটি প্রসারিত করতে চাইতে পারি dir(self):

allowed_keys = [i for i in dir(self) if "__" not in i and any([j.endswith(i) for j in self.__dict__.keys()])]

উপরের কোডটি বাদ দেয়

  • এর থেকে কোনও লুকানো পরিবর্তনশীল dir()("__" উপস্থিতির ভিত্তিতে বর্জন), এবং
  • dir()যার নাম থেকে এমন কোনও পদ্ধতি যা থেকে কোনও গুণবাচক নাম (সুরক্ষিত বা অন্যথায়) এর শেষে পাওয়া যায় না __dict__.keys(), সম্ভবত এটি কেবল @ প্রপার্টি সাজানো পদ্ধতি রাখে।

এই সম্পাদনাটি সম্ভবত পাইথন 3 এবং তারপরের জন্য বৈধ।


2
class SymbolDict(object):
  def __init__(self, **kwargs):
    for key in kwargs:
      setattr(self, key, kwargs[key])

x = SymbolDict(foo=1, bar='3')
assert x.foo == 1

আমি ক্লাসটি ডাকলাম SymbolDictকারণ এটি মূলত একটি অভিধান যা স্ট্রিংয়ের পরিবর্তে চিহ্ন ব্যবহার করে পরিচালনা করে। অন্য কথায়, আপনি x.fooপরিবর্তে করুন x['foo']কিন্তু কভারগুলির নীচে এটি আসলে একই জিনিস চলছে।


2

নিম্নলিখিত সমাধানগুলি শক্ত vars(self).update(kwargs)বা self.__dict__.update(**kwargs)শক্ত নয়, কারণ ব্যবহারকারী কোনও ত্রুটি বার্তা ছাড়াই যে কোনও অভিধানে প্রবেশ করতে পারেন। যদি আমাকে যাচাই করতে হবে যে ব্যবহারকারী নীচের স্বাক্ষর'োকান ('a1', 'a2', 'a3', 'a4', 'a5') সমাধানটি কাজ করে না। তদতিরিক্ত, ব্যবহারকারীর "অবস্থানগত পরামিতি" বা "কে-মান জোড়া প্যারামিটার" পাস করে অবজেক্টটি ব্যবহার করতে সক্ষম হওয়া উচিত।

সুতরাং আমি একটি মেটাক্লাস ব্যবহার করে নিম্নলিখিত সমাধানের পরামর্শ দিই।

from inspect import Parameter, Signature

class StructMeta(type):
    def __new__(cls, name, bases, dict):
        clsobj = super().__new__(cls, name, bases, dict)
        sig = cls.make_signature(clsobj._fields)
        setattr(clsobj, '__signature__', sig)
        return clsobj

def make_signature(names):
    return Signature(
        Parameter(v, Parameter.POSITIONAL_OR_KEYWORD) for v in names
    )

class Structure(metaclass = StructMeta):
    _fields = []
    def __init__(self, *args, **kwargs):
        bond = self.__signature__.bind(*args, **kwargs)
        for name, val in bond.arguments.items():
            setattr(self, name, val)

if __name__ == 'main':

   class A(Structure):
      _fields = ['a1', 'a2']

   if __name__ == '__main__':
      a = A(a1 = 1, a2 = 2)
      print(vars(a))

      a = A(**{a1: 1, a2: 2})
      print(vars(a))

1

এগুলি সম্ভবত আরও ভাল সমাধান হতে পারে তবে আমার মনে যা আসে তা হ'ল:

class Test:
    def __init__(self, *args, **kwargs):
        self.args=dict(**kwargs)

    def getkwargs(self):
        print(self.args)

t=Test(a=1, b=2, c="cats")
t.getkwargs()


python Test.py 
{'a': 1, 'c': 'cats', 'b': 2}

আমি যা খুঁজছি তা হচ্ছে শর্ত সাপেক্ষে বৈধতার ভিত্তিতে বৈশিষ্ট্যগুলি সেট করা। আমি বুঝতে পেরেছিলাম যে কাওয়ার্গগুলি ব্যবহার করার ক্ষেত্রে সমস্যাটি হ'ল এটি বৈধতা দেয় না (বা দস্তাবেজ) যা গুণাবলী গ্রহণযোগ্য
ফিজিয়াআরন

হ্যাঁ আমি বুঝতে পারি @ অ্যালার্কসের উত্তর আরও ভাল। প্রতিদিন নতুন কিছু শিখুন!
টম

1

লারস্কের মাধ্যমে এটিই সবচেয়ে সহজ

class Foo:
    def setAllWithKwArgs(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

আমার উদাহরণ:

class Foo:
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

door = Foo(size='180x70', color='red chestnut', material='oak')
print(door.size) #180x70

এসএমএম কি কোয়ার্গস.আইটিএম () বলতে পারে?
ওলেগ_কর্নিলভ

kwargsমূলশব্দ আর্গুমেন্টের অভিধান এবং items()এটি এমন একটি পদ্ধতি যা অভিধানের (key, value)জোড়ার তালিকার একটি অনুলিপি দেয় ।
হ্যারিস্কোলগুলি

-1

আমি সন্দেহ করি নামযুক্ত আরগগুলি ব্যবহার করার জন্য এটি বেশিরভাগ ক্ষেত্রে ভাল হতে পারে (আরও ভাল স্ব ডকুমেন্টিং কোডের জন্য) যাতে এটি দেখতে এরকম কিছু দেখায়:

class Foo:
    def setAll(a=None, b=None, c=None):
        for key, value in (a, b, c):
            if (value != None):
                settattr(self, key, value)

এই পুনরাবৃত্তিটি কাজ করে না:for key, value in (a, b, c)
পুনরায় প্রেরণ করুন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.