2014-01-15 2 views
2

У меня есть экземпляр cx_Oracle.Connection называется x, и я пытаюсь printx.clientinfo или x.module и получение:Только атрибут python? Невозможно напечатать объект

attribute 'module' of 'cx_Oracle.Connection' objects is not readable

(Что странно, что я могу сделать Распечатайте x.username)

Я все еще могу сделать dir(x) с успехом, и у меня нет времени, чтобы посмотреть на исходный код cx_Oracle (многие из них реализованы на C), поэтому мне интересно, как разработчик смог это сделать? Было ли это с помощью дескрипторов? или что-то связанное с __getitem__? Какова была бы мотивация для этого?

+0

Вы хотите знать способ сделать это в чистом Python, способ сделать это в чистом Python или C, все возможные способы сделать это с обоих языков, как это делает 'cx_Oracle', ...? – abarnert

+0

Я хочу знать, как это сделать в Python, получить его на C было бы неплохо. –

ответ

2

Вы можете сделать это довольно легко в Python с пользовательским дескриптором.

Посмотрите на Descriptor Example в HOWTO. Если вы просто измените метод __get__, чтобы поднять AttributeError ... вот и все. Мы могли бы также переименовать его и вырезать материал для ведения журнала, чтобы сделать его проще.

class WriteOnly(object): 
    """A data descriptor that can't be read. 
    """ 

    def __init__(self, initval=None, name='var'): 
     self.val = initval 
     self.name = name 

    def __get__(self, obj, objtype): 
     raise AttributeError("No peeking at attribute '{}'!".format(self.name)) 

    def __set__(self, obj, val): 
     self.val = val 

class MyClass(object): 
    x = WriteOnly(0, 'x') 

m = MyClass() 
m.x = 20 # works 
print(m.x) # raises AttributeError 

Обратите внимание, что в 2.x, если вы забыли (object) и создать классический класс, дескрипторы не будет работать. (Я считаю, что дескрипторы сами могут быть классическими классами ... но не делайте этого.) В 3.x нет классических классов, так что это не проблема.

Итак, если значение только для записи, как бы вы его читали?

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


Но вам даже не нужны дескрипторы. Если вы хотите, атрибут, который никогда писать только независимо от того, какой класс вы приложите его к, это одна вещь, но если вы просто хотите, чтобы заблокировать доступ на чтение определенных членов определенного класса, есть более простой способ:

class MyClass(object): 
    def __getattribute__(self, name): 
     if name in ('x', 'y', 'z'): 
      raise AttributeError("No! Bad user! You cannot see my '{}'!".format(name)) 
     return super().__getattribute__(self, name) 

m = MyClass() 
m.x = 20 
m.x # same exception 

Для получения дополнительной информации см. Документацию __getattr__ и __getattribute__ в главе data model в документах.

В 2.x, если вы оставите (object) и создадите классический класс, правила поиска атрибутов полностью разные и не полностью документированы, и вы действительно не хотите их изучать, если вы не планируете потратить много времени в 90-х, поэтому ... не делайте этого. Кроме того, 2.x, очевидно, понадобится явный вызов super в стиле 2.x вместо магии типа 3.x super().


С API-интерфейса API у вас есть большинство одинаковых крючков, но они немного разные. См PyTypeObject с для деталей, но в основном:

  • tp_getset позволяет автоматически создавать дескрипторы из получения и установки функций, который похож на @property, но не идентичны.
  • tp_descr_get и tp_descr_set предназначены для дескрипторов зданий отдельно.
  • tp_getattro и tp_setattro подобны __getattr__ и __setattr__, за исключением того, что правила, когда они получают называется немного по-другому, и вы обычно называют PyObject_GenericGetAttr вместо делегируя super(), когда вы знаете, у вас нет базовых классов, которые нужно подключить атрибут доступ.

Тем не менее, почему бы вы сделаете это?

Лично я делал такие вещи, чтобы узнать больше о модели и дескрипторах данных Python, но это вряд ли повод помещать ее в опубликованную библиотеку.

Я предполагаю, что чаще всего кто-то это делает, потому что они пытаются заставить ошибочное понятие инкапсуляции OO (на основе традиционной модели C++) на Python или, что еще хуже, пытаются создать Java- (что не работает без безопасного загрузчика классов и всего, что с ним связано).

Но могут быть случаи, когда есть общий код, который использует эти объекты через интроспекцию, и «обманывая» этот код может быть полезен таким образом, что попытки обмануть человеческих пользователей не являются. Например, представьте себе библиотеку сериализации, которая пыталась рассортировать или JSON-ify или все атрибуты. Вы можете легко записать его, игнорируя нечитаемые атрибуты. (Конечно, вы могли бы так же легко сделать это, скажем, игнорировать атрибуты с префиксом _ ...)

Что касается того, почему cx_Oracle сделал это ... Я даже не смотрел на него, поэтому понятия не имею.

+0

Большое вам спасибо. –

Смежные вопросы