You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: online/cap22.adoc
+42-13Lines changed: 42 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,10 +5,10 @@
5
5
6
6
[quote, Martelli, Ravenscroft & Holden, Why properties are important (Porque propriedades são importantes)]
7
7
____
8
-
A importância crucial das propriedades é que sua existência torna perfeitamente seguro, e de fato aconselhável, expor atributos públicos de dados como parte da interface pública de sua classe.footnote:[Alex Martelli, Anna Ravenscroft & Steve Holden, https://fpy.li/pynut3[Python in a Nutshell, Third Edition] (EN) (O'Reilly), p. 123.]
8
+
A importância crucial das propriedades é que sua existência torna perfeitamente seguro, e de fato aconselhável, expor atributos de dados públicos como parte da interface pública de sua classe.footnote:[Alex Martelli, Anna Ravenscroft & Steve Holden, https://fpy.li/pynut3[Python in a Nutshell, Third Edition] (EN) (O'Reilly), p. 123.]
9
9
____
10
10
11
-
No Python((("dynamic attributes and properties", "dynamic versus virtual attributes"))), atributos de dados e métodos são conhecidos conjuntamente como _atributos_ .
11
+
No Python((("dynamic attributes and properties", "dynamic versus virtual attributes"))), métodos e atributos de dados (ou campos) são conhecidos conjuntamente como _atributos_ .
12
12
Um método é um atributo _invocável_.
13
13
_Atributos dinâmicos_ apresentam a mesma interface que os atributos de dados—isto é, `obj.attr`—mas são computados sob demanda.
14
14
Isso atende ao _Princípio de Acesso Uniforme_ de Bertrand Meyer:
@@ -213,15 +213,32 @@ No Python, `+__init__+` recebe `self` como primeiro argumentos, portanto o objet
213
213
Além disso, `+__init__+` não pode devolver nada.
214
214
Então, na verdade, esse método é um inicializador, não um construtor.
215
215
216
-
Quando uma classe é chamada para criar uma instância, o método especial chamado pelo Python naquela classe para construir a instância é `+__new__+`. É um método de classe, mas recebe tratamento especial, então o decorador `@classmethod` não é aplicado a ele.
217
-
Python recebe a instância devolvida por `+__new__+`, e daí a passa como o primeiro argumento (`self`) para `+__init__+`. Raramente precisamos escrever um `+__new__+`, pois a implementação herdada de `object` é suficiente na vasta maioria dos casos.
216
+
Quando uma classe é invocada para criar uma instância, Python invoca o método especial
217
+
`+__new__+` da classe para construir a instância.
218
218
219
-
Se necessário, o método `+__new__+` pode também devolver uma instância de uma classe diferente. Quando isso acontece, o interpretador não invoca `+__init__+`.
219
+
É um método de classe, mas recebe tratamento especial,
220
+
então o decorador `@classmethod` não é aplicado a ele.
221
+
Python recebe a instância devolvida por `+__new__+`,
222
+
e daí a passa como o primeiro argumento (`self`) para `+__init__+`.
223
+
Raramente precisamos escrever um `+__new__+`,
224
+
pois a implementação herdada de `object` atende todos os casos comuns.
225
+
226
+
Se necessário, o método `+__new__+` pode devolver uma instância de uma classe diferente.
227
+
Quando isso acontece, o interpretador não invoca `+__init__+`.
220
228
Em outras palavras, a lógica de Python para criar um objeto é similar a esse pseudo-código:
<4> A propriedade `event.speakers` devolve uma lista de instâncias de `Record`.
284
301
285
-
Como sempre, vamos criar o código passo a passo, começando com a classe `Record` e uma função para ler dados JSON e devolver um `dict` com instâncias de `Record`.
302
+
Como sempre, vamos criar o código passo a passo,
303
+
começando com a classe `Record` e uma função para
304
+
ler dados JSON e devolver um `dict` com instâncias de `Record`.
286
305
287
306
==== Passo 1: criação de atributos baseados em dados
288
307
289
-
O <<ex_schedule_v1_demo>> mostra((("computed properties", "data-driven attribute creation", id="CPdatadriven22"))) o doctest para orientar esse primeiro passo.
308
+
O <<ex_schedule_v1_demo>> mostra((("computed properties",
<1> Isso é um atalho comum para construir uma instância com atributos criados a partir de argumentos nomeados (a explicação detalhada está abaixo) .
337
+
315
338
<2> Usa o campo `serial` para criar a representação customizada de `Record` exibida no <<ex_schedule_v1_demo>>.
339
+
316
340
<3> `load` vai por fim devolver um `dict` de instâncias de `Record`.
341
+
317
342
<4> Analisa o JSON, devolvendo objetos Python nativos: listas, dicts, strings, números, etc.
343
+
318
344
<5> Itera sobre as quatro listas principais, chamadas `'conferences'`, `'events'`, `'speakers'`, e `'venues'`.
345
+
319
346
<6> `record_type` é o nome da lista sem o último caractere, então `speakers` se torna `speaker`. No Python ≥ 3.9, podemos fazer isso de forma mais explícita com `collection.removesuffix('s')`—veja a
320
347
https://fpy.li/pep616[PEP 616—String methods to remove prefixes and suffixes (Métodos de string para remover prefixos e sufixos_)].
348
+
321
349
<7> Cria a `key` no formato `'speaker.3471'`.
350
+
322
351
<8> Cria uma instância de `Record` e a armazena em `records` com a chave `key`.
323
352
324
353
325
-
O método `+Record.__init__+` ilustra um antigo truque de Python. Lembre-se que o `+__dict__+` de um objeto é onde são guardados seus atributos--a menos que `+__slots__+` seja declarado na classe, como vimos na <<slots_sec>>.
354
+
O método `+Record.__init__+` ilustra um velho truque. Lembre-se que o `+__dict__+` de um objeto é onde são guardados seus atributos--a menos que `+__slots__+` seja declarado na classe, como vimos na <<slots_sec>>.
326
355
Daí, atualizar o `+__dict__+` de uma instância é uma maneira fácil de criar um punhado de atributos naquela instância.footnote:[`Bunch` ou "punhado" é o nome da classe usada por Alex Martelli para compartilhar essa dica em uma receita de 2001 intitulada https://fpy.li/22-4["The simple but handy ‘collector of a bunch of named stuff’ class" (_Uma classe simples mas prática 'coletora de um punhado de coisas nomeadas'_)].]
327
356
328
357
[NOTE]
@@ -475,7 +504,7 @@ do `+__dict__+` da instância, para evitar uma chamada recursiva à propriedade
475
504
Dentro do método `speakers`, uma tentativa de ler `self.speakers` invocará a
476
505
mesma propriedade, gerando rapidamente um `RecursionError`. Entretanto,
477
506
acessando via `+self.__dict__['speakers']+`, evitamos o algoritmo de Python para
478
-
busca de atributos, a propriedade não é chamada e evitamos a recursão. Por esta
507
+
busca de atributos, a propriedade não é invocada e evitamos a recursão. Por esta
479
508
razão, ler ou escrever dados diretamente no `+__dict__+` de um objeto é um
480
509
truque comum em metaprogramação no Python.
481
510
@@ -943,7 +972,7 @@ As partes do <<lineitem_class_v2prop>> que merecem um estudo mais cuidadoso gira
943
972
944
973
Quando programamos um propriedade da maneira tradicional, o nome do atributo onde um valor será armazenado está definido explicitamente nos métodos _getter_ e _setter_.
945
974
Mas aqui as funções `qty_getter` e `qty_setter` são genéricas, e dependem da variável `storage_name` para saber onde ler/escrever o atributo gerenciado no `+__dict__+` da instância.
946
-
Cada vez que a fábrica `quantity` é chamada para criar uma propriedade, `storage_name` precisa ser definida com um valor único.
975
+
Cada vez que a fábrica `quantity` é invocada para criar uma propriedade, `storage_name` precisa ser definida com um valor único.
947
976
948
977
As funções `qty_getter` e `qty_setter` serão encapsuladas pelo objeto `property`, criado na última linha da função fábrica. Mais tarde, quando forem chamadas para cumprir seus papéis, essas funções lerão a `storage_name` de suas clausuras para determinar de onde ler ou onde escrever os valores dos atributos gerenciados.
949
978
@@ -1100,10 +1129,10 @@ Para cada um destes métodos especiais, não importa se o acesso ao atributo é
1100
1129
Se `attr` for uma propriedade, seu método de exclusão nunca será invocado se a classe implementar
1101
1130
`+__delattr__+`.
1102
1131
1103
-
`+__dir__(self)+`:: Chamado((("__dir__"))) quando `dir` é invocado sobre um objeto, para fornecer uma lista de atributos; por exemplo, `dir(obj)` dispara
1132
+
`+__dir__(self)+`:: Invocado((("__dir__"))) quando `dir` é invocado sobre um objeto, para fornecer uma lista de atributos; por exemplo, `dir(obj)` dispara
1104
1133
`+Class.__dir__(obj)+`. Também usado pelo recurso de auto-completar em todos os consoles modernos de Python.
1105
1134
1106
-
`+__getattr__(self, name)+`:: Chamado((("__getattr__"))) apenas quando uma tentativa de obter o atributo nomeado falha, após `obj`, `Class` e suas superclasses serem pesquisadas. As expressões `+obj.no_such_attr+`, `getattr(obj, 'no_such_attr')` e `hasattr(obj, 'no_such_attr')` podem disparar `+Class.__getattr__(obj, 'no_such_attr')+`, mas apenas se um atributo com aquele nome não for encontrado em `obj` ou em `Class` e suas superclasses.
1135
+
`+__getattr__(self, name)+`:: Invocado((("__getattr__"))) apenas quando uma tentativa de obter o atributo nomeado falha, após `obj`, `Class` e suas superclasses serem pesquisadas. As expressões `+obj.no_such_attr+`, `getattr(obj, 'no_such_attr')` e `hasattr(obj, 'no_such_attr')` podem disparar `+Class.__getattr__(obj, 'no_such_attr')+`, mas apenas se um atributo com aquele nome não for encontrado em `obj` ou em `Class` e suas superclasses.
1107
1136
1108
1137
`+__getattribute__(self, name)+`:: Sempre((("__getattribute__"))) chamado quando há uma tentativa de obter o atributo nomeado diretamente a partir de código Python (o interpretador pode ignorar isso em alguns casos, por exemplo para obter o método `+__repr__+`). A notação de ponto e as funções embutidas `getattr` e `hasattr` disparam esse método. `+__getattr__+` só é invocado após `+__getattribute__+`, e apenas quando `+__getattribute__+` gera uma `AttributeError`. Para acessar atributos da instância `obj` sem entrar em uma recursão infinita, implementações de `+__getattribute__+` devem usar `+super().__getattribute__(obj, name)+`.
0 commit comments