Aprendendo Python , e tem algumas dúvidas básicas.
1. Eu vi a declaração de variável (caminho aqui) como
class writer:
path = ""
às vezes, nenhuma declaração explícita, mas inicializa por meio __init__
.
def __init__(self, name):
self.name = name
Eu entendo o propósito de __init__
, mas é aconselhável declarar variável em qualquer outra função.
2.Como posso criar uma variável para conter um tipo personalizado?
class writer:
path = "" # string value
customObj = ??
__name__
atributo têm um "nome". Nem todos os objetos têm um__name__
atributo, mas você ainda pode ter referências a eles. Se começarmos a chamar uma "referência" de "nome", estaremos prestando um péssimo serviço aos iniciantes no futuro.Respostas:
Ok, as primeiras coisas primeiro.
Não existe "declaração de variável" ou "inicialização de variável" em Python.
Existe simplesmente o que chamamos de "atribuição", mas provavelmente deveríamos chamar apenas de "nomeação".
Atribuição significa "este nome do lado esquerdo agora se refere ao resultado da avaliação do lado direito, independentemente do que foi referido antes (se houver)".
foo = 'bar' # the name 'foo' is now a name for the string 'bar' foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar', # and starts being a name for the integer 6, resulting from the multiplication
Como tal, os nomes do Python (um termo melhor do que "variáveis", sem dúvida) não têm tipos associados; os valores sim. Você pode reaplicar o mesmo nome a qualquer coisa, independentemente de seu tipo, mas a coisa ainda tem um comportamento que depende de seu tipo. O nome é simplesmente uma forma de se referir ao valor (objeto). Isso responde à sua segunda pergunta: você não cria variáveis para conter um tipo personalizado. Você não cria variáveis para conter nenhum tipo específico. Você não "cria" variáveis. Você dá nomes aos objetos.
Segundo ponto: Python segue uma regra muito simples quando se trata de classes, que na verdade é muito mais consistente do que linguagens como Java, C ++ e C #: tudo que é declarado dentro do
class
bloco faz parte da classe . Portanto, functions (def
) escritas aqui são métodos, ou seja, parte do objeto de classe (não armazenado por instância), assim como em Java, C ++ e C #; mas outros nomes aqui também fazem parte da classe. Novamente, os nomes são apenas nomes, não têm tipos associados e as funções também são objetos em Python. Portanto:class Example: data = 42 def method(self): pass
As classes também são objetos , em Python.
Portanto, agora criamos um objeto chamado
Example
, que representa a classe de todas as coisas que sãoExample
s. Este objeto tem dois atributos fornecidos pelo usuário (em C ++, "membros"; em C #, "campos ou propriedades ou métodos"; em Java, "campos ou métodos"). Um deles é nomeadodata
e armazena o valor inteiro42
. O outro é nomeadomethod
e armazena um objeto de função. (Existem vários outros atributos que o Python adiciona automaticamente.)Porém, esses atributos ainda não fazem parte do objeto. Fundamentalmente, um objeto é apenas um pacote de mais nomes (os nomes dos atributos), até que você descubra coisas que não podem mais ser divididas. Assim, os valores podem ser compartilhados entre diferentes instâncias de uma classe, ou mesmo entre objetos de diferentes classes, se você definir isso deliberadamente.
Vamos criar uma instância:
Agora temos um objeto separado chamado
x
, que é uma instância deExample
. Osdata
emethod
não são realmente parte do objeto, mas ainda podemos procurá-los por meiox
de alguma mágica que o Python faz nos bastidores. Quando olhamos para cimamethod
, em particular, obteremos um "método vinculado" (quando o chamamos,x
é passado automaticamente como oself
parâmetro, o que não pode acontecer se olharmosExample.method
diretamente).O que acontece quando tentamos usar
x.data
?Quando o examinamos, ele é pesquisado primeiro no objeto. Se não for encontrado no objeto, o Python procura na classe.
No entanto, quando atribuímos a
x.data
, Python criará um atributo no objeto. Ele vai não substituir o atributo de classe.Isso nos permite fazer a inicialização do objeto . O Python chamará automaticamente o
__init__
método da classe em novas instâncias quando forem criadas, se houver. Neste método, podemos simplesmente atribuir a atributos para definir valores iniciais para esse atributo em cada objeto:class Example: name = "Ignored" def __init__(self, name): self.name = name # rest as before
Agora devemos especificar a
name
quando criamos umExample
, e cada instância tem a sua próprianame
. Python irá ignorar o atributo classExample.name
sempre que procurarmos o.name
de uma instância, porque o atributo da instância será encontrado primeiro.Uma última advertência: modificação (mutação) e atribuição são coisas diferentes!
Em Python, as strings são imutáveis. Eles não podem ser modificados. Quando você faz:
a = 'hi ' b = a a += 'mom'
Você não altera a string 'hi' original. Isso é impossível em Python. Em vez disso, você cria uma nova string
'hi mom'
ea
deixa de ser um nome para'hi '
, e passa a ser um nome para'hi mom'
. Fizemosb
um nome para'hi '
também, e depois de reaplicar oa
nome,b
ainda é um nome para'hi '
, porque'hi '
ainda existe e não foi alterado.Mas as listas podem ser alteradas:
a = [1, 2, 3] b = a a += [4]
Agora
b
é [1, 2, 3, 4] também, porque criamosb
um nome para a mesma coisa que oa
nomeou e então mudamos essa coisa. Não criamos uma nova lista paraa
nomear, porque Python simplesmente trata+=
de listas de forma diferente.Isso é importante para os objetos porque se você tivesse uma lista como um atributo de classe e usasse uma instância para modificar a lista, então a mudança seria "vista" em todas as outras instâncias. Isso ocorre porque (a) os dados são, na verdade, parte do objeto de classe e não qualquer objeto de instância; (b) porque você estava modificando a lista e não fazendo uma atribuição simples, você não criou um novo atributo de instância ocultando o atributo de classe.
fonte
Isso pode estar 6 anos atrasado, mas no Python 3.5 e superior, você declara um tipo de variável como este:
ou isto:
variable_name # type: shinyType
Portanto, no seu caso (se você tiver uma
CustomObject
classe definida), você pode fazer:Veja isso ou aquilo para mais informações.
fonte
Não há necessidade de declarar novas variáveis em Python. Se estamos falando sobre variáveis em funções ou módulos, nenhuma declaração é necessária. Apenas atribuir um valor a um nome de onde você precisa:
mymagic = "Magic"
. Variáveis em Python podem conter valores de qualquer tipo, e você não pode restringir isso.Porém, sua pergunta pergunta especificamente sobre classes, objetos e variáveis de instância. A maneira idiomática de criar variáveis de instância está no
__init__
método e em nenhum outro lugar - embora você possa criar novas variáveis de instância em outros métodos, ou mesmo em código não relacionado, é apenas uma má ideia. Isso tornará seu código difícil de raciocinar ou de manter.Então, por exemplo:
class Thing(object): def __init__(self, magic): self.magic = magic
Fácil. Agora, as instâncias desta classe têm um
magic
atributo:thingo = Thing("More magic") # thingo.magic is now "More magic"
A criação de variáveis no namespace da própria classe leva a um comportamento totalmente diferente. É funcionalmente diferente e você só deve fazer isso se tiver um motivo específico para isso. Por exemplo:
class Thing(object): magic = "Magic" def __init__(self): pass
Agora tente:
thingo = Thing() Thing.magic = 1 # thingo.magic is now 1
Ou:
class Thing(object): magic = ["More", "magic"] def __init__(self): pass thing1 = Thing() thing2 = Thing() thing1.magic.append("here") # thing1.magic AND thing2.magic is now ["More", "magic", "here"]
Isso ocorre porque o namespace da própria classe é diferente do namespace dos objetos criados a partir dela. Vou deixar para você pesquisar um pouco mais.
A mensagem para casa é que o Python idiomático deve (a) inicializar atributos de objeto em seu
__init__
método e (b) documentar o comportamento de sua classe conforme necessário. Você não precisa se dar ao trabalho de obter uma documentação completa no nível da Esfinge para tudo o que você escreve, mas pelo menos alguns comentários sobre quaisquer detalhes que você ou outra pessoa possa precisar para pegar.fonte
Para fins de escopo, eu uso:
custom_object = None
fonte
Variáveis têm escopo, então sim, é apropriado ter variáveis que são específicas para sua função. Você nem sempre precisa ser explícito sobre sua definição; normalmente você pode apenas usá-los. Apenas se você quiser fazer algo específico para o tipo da variável, como acrescentar para uma lista, você precisa defini-los antes de começar a usá-los. Exemplo típico disso.
list = [] for i in stuff: list.append(i)
A propósito, essa não é uma boa maneira de configurar a lista. Seria melhor dizer:
list = [i for i in stuff] # list comprehension
... mas estou divagando.
Sua outra pergunta. O objeto personalizado deve ser uma classe em si.
class CustomObject(): # always capitalize the class name...this is not syntax, just style. pass customObj = CustomObject()
fonte