Как узнать, определено ли свойство у подкласса Expando?

Я создаю приложение, в котором хочу иметь расширяемый набор свойств (каждое из которых RatingProperty). Я также хочу проверить, что все динамические свойства относятся к типу RatingProperty.

В документации Expando сказано:

Совет: Если вы хотите проверить значение динамического свойства с помощью класса Property, вы можете создать экземпляр класса Property и вызвать его метод validate() для значения.

Поэтому, если я хочу проверить динамическое свойство, мне нужно знать, каковы нединамические свойства класса. Как я могу спросить свой класс, каковы его определенные свойства?

Я рассматривал возможность создания метода класса, который принимает строку и возвращает true, если эта строка находится в списке имен свойств, которые я создаю и поддерживаю, но это похоже на хак. Я искал в Google советы, но безуспешно.

Спасибо, Пэт


person pat    schedule 06.01.2009    source источник
comment
Будет полезно, если вы пометите свои сообщения на подходящем языке.   -  person Nick Johnson    schedule 06.12.2011


Ответы (4)


После еще немного исследований (черт возьми, lazyweb!) Я нашел решение, которое я считаю приемлемым:

Динамическое свойство не может иметь тип подкласса базы данных. Таким образом, необходимо предпринять два отдельных шага. Сначала вам нужно создать экземпляр вашего класса свойств и проверить ваше значение:

test = db.RatingProperty()
if test.validate(valueToSave):
    #do your thing

Затем вам нужно проверить, является ли свойство, которое вы хотите сохранить, объявленным свойством:

if valueToSaveKey not in myObject.properties():
    #if not save it as desired
    myObject.valueToSaveKey = valueToSave

Недостатком здесь является то, что значение, которое вы сохраняете, не сохраняется как тип свойства, который вы хотите.

person pat    schedule 07.01.2009
comment
Строка выше, которая гласит: myObject.valueToSaveKey = valueToSave Следует читать: myObject.__setattr__(valueToSaveKey, valueToSave) - person pat; 11.01.2009
comment
Вероятно, в следующий раз лучше отредактировать свой ответ - таким образом люди, которые читают только ответ (а это случается чаще, чем вы думаете :)), не пропускают возможно важные детали из комментариев. - person icyrock.com; 19.11.2010

http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model_properties

В db.Model есть методы, позволяющие узнать все свойства экземпляра.

Класс предоставляет список объектов Property: db.Model.properties().

Экземпляр предоставляет только динамические имена: instance.dynamic_properties()

Вы хотите пройтись по списку и построить объекты Property, а затем запустить p.validate().

for p_name in instance.dynamic_properties():
    p = db.RatingProperty()
    p.validate() # raises BadValueError, etc.
person Andrew    schedule 02.12.2011

Я могу неправильно понять ваш вопрос, но если у вас есть список свойств, которые вы ожидаете найти, почему бы просто не использовать стандартную модель db.Model вместо Expando? Вы можете добавить дополнительные свойства в класс модели, если вы либо предоставляете значения по умолчанию, либо не делаете их обязательными.

person Nick Johnson    schedule 07.01.2009
comment
У меня есть список свойств, которые я хочу сохранить, и неопределенное количество свойств, которые, как я знаю, будут определенного типа. Когда я пытаюсь добавить свойство, я хочу сначала проверить, является ли оно объявленным свойством, и, если нет, проверить, что его значение имеет требуемый тип. - person pat; 07.01.2009
comment
Но добавляются ли «неопределенные» свойства во время выполнения или просто в более поздних версиях приложения? Если первое, вы можете использовать ArrayProperty. Если последнее, просто добавьте их как новые свойства. - person Nick Johnson; 11.01.2009
comment
Если вы поместите их в массив, вы не сможете фильтровать по их значению. Я рассматривал возможность простого добавления свойств в модель, но не уверен, что так будет проще. - person pat; 11.01.2009
comment
Вы можете фильтровать на основе их значения, но только на основе значения по одному за раз. Я все еще не понимаю ваших точных требований. Знаете ли вы во время выполнения, каков (текущий) набор возможных свойств? - person Nick Johnson; 13.01.2009
comment
Пользователи могут устанавливать значения многих различных свойств, хотя ни одно из них не является обязательным, и для них нет разумного значения по умолчанию. У меня есть группа предлагаемых свойств для редактирования, хотя я предполагаю, что пользователь может добавлять свойства, которые они считают подходящими. - person pat; 28.01.2009

Это на самом деле довольно легко!

ExpandoObject реализует (IDictionary<String, Object>), поэтому вам просто нужно сделать это:

 dynamic person = new ExpandoObject();
 person.FirstName = "Barack";
 person.LastName = "Obama"

 (((IDictionary<String, Object>)person).Keys  
    => { "FirstName", "LastName" }

 (((IDictionary<String, Object>)person).ContainsKey("FirstName")  
    => true

Примечание. Вам нужно явно привести к (IDictionary<string, object>, потому что ExpandoObject явно реализует этот интерфейс, а сам экземпляр не имеет ContainsKey() или Keys.

Не ожидайте, что этот метод будет работать со всеми динамическими объектами — только с ExpandoObject и всем остальным, реализующим этот интерфейс.

person Simon_Weaver    schedule 22.12.2010