سؤال

هل تعرف ما إذا كانت هناك وظيفة مضمنة لبناء قاموس من كائن عشوائي؟أود أن أفعل شيئًا كهذا:

>>> class Foo:
...     bar = 'hello'
...     baz = 'world'
...
>>> f = Foo()
>>> props(f)
{ 'bar' : 'hello', 'baz' : 'world' }

ملحوظة: لا ينبغي أن تشمل الأساليب.الحقول فقط.

هل كانت مفيدة؟

المحلول

لاحظ أن أفضل الممارسات في Python 2.7 هي الاستخدام أسلوب جديد الفئات (غير مطلوبة مع Python 3)، على سبيل المثال.

class Foo(object):
   ...

هناك أيضًا فرق بين "الكائن" و"الفئة".لبناء قاموس من التعسفي هدف, ، يكفي للاستخدام __dict__.عادةً، ستعلن عن أساليبك على مستوى الفصل وسماتك على مستوى المثيل، لذلك __dict__ يجب ان يكون بخير.على سبيل المثال:

>>> class A(object):
...   def __init__(self):
...     self.b = 1
...     self.c = 2
...   def do_nothing(self):
...     pass
...
>>> a = A()
>>> a.__dict__
{'c': 2, 'b': 1}

نهج أفضل (اقترحه روبرت في التعليقات) هو المدمج vars وظيفة:

>>> vars(a)
{'c': 2, 'b': 1}

وبدلاً من ذلك، اعتمادًا على ما تريد القيام به، قد يكون من الجيد أن ترث منه dict.ثم فصلك هو بالفعل قاموس، وإذا كنت تريد يمكنك تجاوز getattr و/أو setattr للاتصال من خلال وتعيين الإملاء.على سبيل المثال:

class Foo(dict):
    def __init__(self):
        pass
    def __getattr__(self, attr):
        return self[attr]

    # etc...

نصائح أخرى

بدلاً من x.__dict__, ، إنها في الواقع أكثر استخدامًا بيثونية vars(x).

ال dir المدمج في سوف يعطيك كافة سمات الكائن، بما في ذلك أساليب خاصة مثل __str__, __dict__ ومجموعة كاملة من الآخرين الذين ربما لا تريدهم.ولكن يمكنك القيام بشيء مثل:

>>> class Foo(object):
...     bar = 'hello'
...     baz = 'world'
...
>>> f = Foo()
>>> [name for name in dir(f) if not name.startswith('__')]
[ 'bar', 'baz' ]
>>> dict((name, getattr(f, name)) for name in dir(f) if not name.startswith('__')) 
{ 'bar': 'hello', 'baz': 'world' }

لذلك يمكن توسيع هذا ليعود فقط سمات البيانات وليس الأساليب، من خلال تحديد الخاص بك props وظيفة مثل هذا:

import inspect

def props(obj):
    pr = {}
    for name in dir(obj):
        value = getattr(obj, name)
        if not name.startswith('__') and not inspect.ismethod(value):
            pr[name] = value
    return pr

لقد استقرت على مزيج من الإجابتين:

dict((key, value) for key, value in f.__dict__.iteritems() 
    if not callable(value) and not key.startswith('__'))

لبناء قاموس من التعسفي هدف, ، يكفي للاستخدام __dict__.

وهذا يفتقد السمات التي يرثها الكائن من فئته.على سبيل المثال،

class c(object):
    x = 3
a = c()

hasattr(a, 'x') صحيح، لكن 'x' لا يظهر في a.__dict__

اعتقدت أنني سأستغرق بعض الوقت لأوضح لك كيف يمكنك ترجمة كائن للإملاء من خلاله dict(obj).

class A(object):
    d = '4'
    e = '5'
    f = '6'

    def __init__(self):
        self.a = '1'
        self.b = '2'
        self.c = '3'

    def __iter__(self):
        # first start by grabbing the Class items
        iters = dict((x,y) for x,y in A.__dict__.items() if x[:2] != '__')

        # then update the class items with the instance items
        iters.update(self.__dict__)

        # now 'yield' through the items
        for x,y in iters.items():
            yield x,y

a = A()
print(dict(a)) 
# prints "{'a': '1', 'c': '3', 'b': '2', 'e': '5', 'd': '4', 'f': '6'}"

القسم الرئيسي من هذا الرمز هو __iter__ وظيفة.

كما توضح التعليقات، أول شيء نقوم به هو الاستيلاء على عناصر الفصل الدراسي ومنع أي شيء يبدأ بـ "__".

بمجرد إنشاء ذلك dict, ، ثم يمكنك استخدام update وظيفة dict وتمرير في المثيل __dict__.

سيعطيك هذا قاموسًا كاملاً للفصل + مثيل للأعضاء.الآن كل ما تبقى هو التكرار عليها والحصول على العائدات.

أيضًا، إذا كنت تخطط لاستخدام هذا كثيرًا، فيمكنك إنشاء ملف @iterable مصمم الطبقة.

def iterable(cls):
    def iterfn(self):
        iters = dict((x,y) for x,y in cls.__dict__.items() if x[:2] != '__')
        iters.update(self.__dict__)

        for x,y in iters.items():
            yield x,y

    cls.__iter__ = iterfn
    return cls

@iterable
class B(object):
    d = 'd'
    e = 'e'
    f = 'f'

    def __init__(self):
        self.a = 'a'
        self.b = 'b'
        self.c = 'c'

b = B()
print(dict(b))

إجابة متأخرة ولكن مع توفير الاكتمال والاستفادة من مستخدمي Google:

def props(x):
    return dict((key, getattr(x, key)) for key in dir(x) if key not in dir(x.__class__))

لن يُظهر هذا الأساليب المحددة في الفصل الدراسي، لكنه سيظل يُظهر الحقول بما في ذلك تلك المخصصة لـ lambdas أو تلك التي تبدأ بشرطة سفلية مزدوجة.

أعتقد أن أسهل طريقة هي إنشاء ملف تحصل على البند السمة للفئة.إذا كنت بحاجة إلى الكتابة إلى الكائن، يمكنك إنشاء مخصص setattr .هنا مثال ل تحصل على البند:

class A(object):
    def __init__(self):
        self.b = 1
        self.c = 2
    def __getitem__(self, item):
        return self.__dict__[item]

# Usage: 
a = A()
a.__getitem__('b')  # Outputs 1
a.__dict__  # Outputs {'c': 2, 'b': 1}
vars(a)  # Outputs {'c': 2, 'b': 1}

قاموس ينشئ سمات الكائنات في القاموس ويمكن استخدام كائن القاموس للحصول على العنصر الذي تحتاجه.

إذا كنت تريد إدراج جزء من سماتك، فقم بتجاوزها __dict__:

def __dict__(self):
    d = {
    'attr_1' : self.attr_1,
    ...
    }
    return d

# Call __dict__
d = instance.__dict__()

وهذا يساعد كثيرا إذا كان لديك instance احصل على بعض بيانات الكتلة الكبيرة وتريد الدفع d إلى Redis مثل قائمة انتظار الرسائل.

الجانب السلبي للاستخدام __dict__ هو أنها ضحلة.لن يقوم بتحويل أي فئات فرعية إلى قواميس.

إذا كنت تستخدم Python3.5 أو أعلى، فيمكنك استخدام jsons:

>>> import jsons
>>> jsons.dump(f)
{'bar': 'hello', 'baz': 'world'}

بايثون 3:

class DateTimeDecoder(json.JSONDecoder):

   def __init__(self, *args, **kargs):
        JSONDecoder.__init__(self, object_hook=self.dict_to_object,
                         *args, **kargs)

   def dict_to_object(self, d):
       if '__type__' not in d:
          return d

       type = d.pop('__type__')
       try:
          dateobj = datetime(**d)
          return dateobj
       except:
          d['__type__'] = type
          return d

def json_default_format(value):
    try:
        if isinstance(value, datetime):
            return {
                '__type__': 'datetime',
                'year': value.year,
                'month': value.month,
                'day': value.day,
                'hour': value.hour,
                'minute': value.minute,
                'second': value.second,
                'microsecond': value.microsecond,
            }
        if isinstance(value, decimal.Decimal):
            return float(value)
        if isinstance(value, Enum):
            return value.name
        else:
            return vars(value)
    except Exception as e:
        raise ValueError

يمكنك الآن استخدام الكود أعلاه داخل فصلك الدراسي:

class Foo():
  def toJSON(self):
        return json.loads(
            json.dumps(self, sort_keys=True, indent=4, separators=(',', ': '), default=json_default_format), cls=DateTimeDecoder)


Foo().toJSON() 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top