У большинства встроенных классов Python нет __dict__?Каковы причины? - PullRequest
1 голос
/ 12 апреля 2019

Это общее правило, что нативные классы Python, например, os.stat_result, не имеют атрибута __dict__ (как, например, предложено в , как избежать, чтобы класс имел __dict __ )?

Каковы технические причины, по которым встроенным классам (например, os.stat_result) не хватает этой функции?

1 Ответ

4 голосов
/ 14 апреля 2019

Я не знаю, есть ли «правильный» ответ на это - причина в том, что для большинства из этих объектов можно жить счастливо, не прикрепляя дополнительные атрибуты к их экземплярам, ​​- и стоимость наличия __dict__ это просто не стоит.

Можете ли вы представить, что у int s у Python __dict__ с? Для каждого числа, кроме 80-байтовых байтов, будет создан еще один 200-байтовый объект, чтобы можно было иметь атрибуты, привязанные к их «42»?

Кроме того, для неизменяемых классов, таких как кортежи, строки и т. Д., Один и тот же экземпляр может быть повторно использован в разных контекстах - __dict__ в одном случае может создать, казалось бы, не связанный экземпляр одного и того же объекта для внезапного появления атрибутов .

Кроме того, указанный вами класс os.stat_result является именованным кортежем - он должен быть неизменным и компактным.

Таким образом, помимо размера и стоимости ресурсов для создания __dict__ для большинства объектов, существует также проблема кодирования: они обычно изначально кодируются (т.е. записываются на C) - и атрибут e __dict__ должен быть явно созданные - так что в отличие от классов, написанных на Python - нужно стараться изо всех сил, чтобы разрешить __dict__ в этих классах, в то время как для кода Python обход заключается в том, чтобы избежать __dict__.

И, наконец, когда сообщество, разрабатывающее язык, приходит к выводу, что в объекте, имеющем __dict__, будет какое-то явное преимущество, он может быть включен. Это произошло с самим типом объекта Function некоторое время назад - и теперь функции могут иметь атрибуты, прикрепленные к ним декораторами, и это может найти хорошее применение.

Хотя если вам нужен код, прикрепляющий дополнительные атрибуты к одному классу, вы можете сделать это по старинке, просто наследовать этот класс и преобразовать в него свой объект. (Я только что обнаружил, что os.stat_result - это , а не named_tuple, и его нельзя использовать в качестве базового класса - извините за это - так что завернуть его в простой класс может быть самой простой вещью, которую нужно сделать :

class MyStatResult:
    def __init__(self, stat_result):
         self.stat = stat_result

    def __repr__(self):
         return "Wrapper for" + repr(self.stat)

Теперь, если ваша цель - извлечь заголовки / значения полей как диктовку, а не добавлять к ней дополнительные атрибуты - самоанализируемая часть этих объектов задается dir - в случае os.stat_result fieds у этого вопроса есть хороший префикс:

stat = os.stat(path)

stat_dict = lambda path: {name: getattr(stat, field)  for field in dir(stat) if field.startswith("st_")}

В Python 3.8, благодаря PEP 572, можно написать это как хороший вкладчик:

stat_dict = lambda path: {name: getattr(stat, field)  for field in dir(stat:=os.stat(path)) if field.startswith("st_")}
...