print("Hello folks")

Nós vamos usar Python3 neste tutorial, pois é amplamente usado. A maioria das estruturas e bibliotecas suporta esta versão.

Nota: Qualquer versão acima do 3.5.2 suporta a maioria das bibliotecas e estruturas.


Índice:

  1. Introdução
  2. Instalação
  3. Shell Python
  4. Comente
  5. Impressão
  6. Indentação
  7. Variáveis
  8. Operadores
  9. Declarações condicionais
  10. Para Loops
  11. Enquanto loops
  12. Entrada do Usuário
  13. Typecasting
  14. Dicionários
  15. Listas
  16. Tuplas
  17. Conjuntos
  18. Funções e argumentos
  19. Args
  20. palavra-chave Argumentos
  21. Argumentos padrão
  22. kwargs
  23. Escopo
  24. Declaração de retorno
  25. Expressão Lambda
  26. Compreensão da lista
  27. Conceitos OOPS
  28. Aulas
  29. Métodos
  30. Objetos
  31. Construtor
  32. Atributo de instância
  33. Atributos de classe
  34. Auto
  35. Herança
  36. Super
  37. Herança múltipla
  38. Polimorfismo
  39. Encapsulamento
  40. Decoradores
  41. Exceções
  42. Importação de Pacotes
  43. Manipulação JSON

Nota: O tópico explicado no início é considerado para iniciantes. Se você tem experiência intermediária em python, pode pular para a parte de seu interesse.


Introdução:

De acordo com o Github’s octoverso, Python é a segunda linguagem mais usada pelos desenvolvedores em 2019.

Gráfico octoverso de Como os idiomas evoluíram

Antes de aprender qualquer idioma, é mais útil saber como o idioma surgiu. Foi desenvolvido por Guido van Rossum, um programador holandês, e lançado em 1991.

Python é uma linguagem interpretada. Usa CPython Intérprete para compilar o código python em código de bytes. Para um iniciante, você não precisa saber muito sobre o CPython, mas deve estar ciente de como o python funciona internamente.

A filosofia por trás do python é que o código deve ser legível. Consegue isso com a ajuda do recuo. Ele suporta muitos paradigmas de programação, ou seja, funcional e orientado a objetos. Nós os entenderemos à medida que avançarmos no artigo.

A pergunta básica que o iniciante tem em mente é o que uma língua pode fazer. Aqui estão alguns dos casos de uso do python:

  • Desenvolvimento do lado do servidor (Django, Flask)
  • Ciência de dados (Pytorch, fluxo tensor)
  • Análise / Visualização de dados (Matplotlib)
  • Script (sopa bonita)
  • Desenvolvimento incorporado

Nota: Não endosso nenhuma das bibliotecas ou estruturas mencionadas acima. Eles são populares e amplamente utilizados em seus respectivos domínios.


Instalação:

O primeiro passo para aprender qualquer linguagem de programação é saber como instalá-lo. Atualmente, o Python é incluído na maioria dos sistemas operacionais. Use o seguinte comando no seu terminal para verificar se o python está disponível:

python3 --version

Você verá a seguinte saída:

Python 3.7.0

Se você tem muitas versões disponíveis do python em seu sistema, poderá ver uma versão diferente. Se você possui o python instalado e a versão está acima da 3.5.2, você pode pular a seção. Para aqueles que não possuem o python instalado, siga as etapas abaixo:

Usuário do Windows:

  • Vou ao Site oficial do Python.
  • Clique no botão de download (Download Python 3.8.2)[[[[Nota: A versão pode diferir quando você está lendo este artigo]
  • Vá para o caminho em que o pacote foi baixado e clique duas vezes no instalador.
  • Marque a caixa indicando “Adicionar Python 3.x ao PATH” e clique em “Instalar agora”.
  • Uma vez feito, você receberá um aviso dizendo “A instalação foi bem-sucedida”. Verifique novamente se o python está configurado corretamente usando o comando acima.
  • Para confirmar se o python está instalado e configurado corretamente, use o comando python3 --version.

Usuário Mac:

  • Primeiro instale o xcode da loja de aplicativos.
  • Se você deseja instalar o Xcode usando o terminal, use o seguinte comando:

xcode-select --install

  • Depois disso, para instalar o python, usaremos o gerenciador de pacotes brew. Para instalar e configurar preparar use o seguinte comando:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

  • Depois que a configuração de preparação estiver concluída, use o seguinte comando para atualizar qualquer pacote desatualizado:

brew update

  • Para instalar o python, use o seguinte comando:

brew install python3

  • Para confirmar se o python está instalado e configurado corretamente, use o comando python3 --version.

Usuário Linux:

  • Para instalar o python usando apt, use o seguinte comando:

sudo apt install python3

  • Para instalar o python usando yum, use o seguinte comando:

sudo yum install python3

  • Para confirmar se o python está instalado e configurado corretamente, use o comando python3 --version.


Shell Python:

É uma das ferramentas mais úteis que você encontrará. O shell python nos dá o poder de testar rapidamente qualquer conceito antes de integrá-lo ao nosso aplicativo.

Vá para o terminal ou prompt da linha de comando. Entrar python3 comando e você obterá a seguinte saída:

➜ python3.7
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 26 2018, 23:26:24)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

Neste tutorial, aprenderemos alguns conceitos com a ajuda do python3 shell, que você pode ver acima. A partir de agora, sempre que eu mencionar vá para o shell python isso significa que você tem que usar python3 comando.

Enquanto para aprender os conceitos restantes, criaremos um arquivo com uma extensão .py. Para executar este arquivo, usamos o seguinte comando:

python3 testing.py

Vamos para o shell python. Tipo 10 + 12 depois disto >>> marca. Você obterá a saída 22:

>>> 10 + 12
22


Os comentários facilitam a escrita do código, pois ajudam a entender por que um determinado código é gravado. Outra coisa impressionante sobre o comentário é que ele ajuda a melhorar a legibilidade do código.

# Stay Safe

Quando você adiciona a seguinte sintaxe, o interpretador python entende que é um comentário. As linhas dentro disso não são executadas.

Você pode estar se perguntando por que usar comentários. Imagine que você é um desenvolvedor e foi designado para um tremendo projeto. O projeto possui mais de mil linhas de código. Agora, para entender como o código funciona, você precisará ir linha por linha e entendê-lo.

Qual a melhor solução para isso? Ahh! aqui vêm os comentários. Os comentários nos ajudam a entender por que um código específico é escrito e o que ele retorna ou faz. Considere isso como documentação para cada pedaço de código.


Acredite, além de ferramentas de depuração do editor, qualquer coisa que ajude o desenvolvedor a resolver o problema é uma declaração impressa. A impressão é uma das sintaxes subestimadas da programação e você descobrirá que será a mais útil ao depurar os problemas.

Então, como isso ajuda na depuração do problema? Bem, considere que você tem um módulo e deseja verificar o fluxo de execução para entendê-lo ou depurar um bug. Existem duas opções. Você pode usar um depurador ou adicionar uma declaração de impressão.

Nem sempre é possível definir um depurador. Por exemplo, se você estiver usando um shell python, um depurador não estará disponível. Nesse cenário, a impressão nos ajuda. Outro cenário é que, quando o aplicativo está sendo executado, você pode adicionar uma declaração de impressão que será exibida nos logs do seu aplicativo. Você pode monitorá-los em tempo de execução.

O Python fornece um método de impressão embutido com a seguinte sintaxe:

print("Stay safe...")


Recuo:

Outra parte interessante dessa linguagem é o recuo. Por quê? Bem, a resposta é simples: torna o código legível e bem formatado. É obrigatório em python seguir a regra do recuo. Se o recuo não for seguido, você receberá o seguinte erro:

IndentationError: unexpected indent

Veja até os erros em python são tão legíveis e fáceis de entender. No começo, você pode ficar aborrecido com a compulsão de indentação. Mas com o tempo você entenderá que o recuo é amigo do desenvolvedor.


Variáveis:

Como o nome indica, uma variável é algo que pode mudar. Uma variável é uma maneira de se referir a um local de memória usado por um programa de computador.

Bem, na maioria das linguagens de programação, você precisa atribuir o tipo a uma variável, mas em python, você não precisa. Por exemplo, na linguagem C para declarar um número inteiro, a seguinte sintaxe é usada int num = 5; enquanto em python num = 5 .

Vá para o shell python e execute a operação passo a passo:

  • Integer: Como o nome sugere, nada mais é do que um valor numérico que pode ser positivo, negativo ou zero sem um ponto decimal.

>>> num = 5
>>> print(num)
5
>>> type(num)

Como você pode ver aqui, declaramos um num variável e atribuído 5 como um valor. O Python está embutido type O método pode ser usado para verificar o tipo de variável. Quando verificamos o tipo de num, estamos vendo a saída . Por enquanto, concentre-se apenas no int nessa saída. Int representa um número inteiro.

  • Float: É o mesmo que um número inteiro, mas com uma pequena diferença, um valor numérico com uma casa decimal.

>>> num = 5.0
>>> print(num)
5.0
>>> type(num)

Aqui atribuímos um número com um único decimal ao num. Quando verificamos o tipo de num, podemos ver que é flutuante.

  • String: Nada mais é do que uma formação de caracteres ou números inteiros. Eles podem ser representados usando aspas duplas ou simples.

>>> greet = "Hello user"
>>> print(greet)
Hello user
>>> type(greet)

Aqui atribuímos uma string para greet. O tipo de saudação é uma string, como você pode ver na saída.

  • Boolean: Eles são um operador binário com um valor Verdadeiro ou Falso.

>>> is_available = True
>>> print(is_available)
True
>>> type(is_available)

Aqui atribuímos um valor True para is_available. O tipo dessa variável é booleano. Você só pode atribuir Verdade ou Falso. Lembrar T e F deve ser maiúsculo ou ocorrerá um erro da seguinte maneira:

>>> is_available = true
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'true' is not defined

  • NoneType: É usado quando não temos o valor da variável.

>>> num = None
>>> print(num)
None
>>> type(num)


Operadores:

Consulte a imagem abaixo para entender todo o operador aritmético disponível em python com os seguintes exemplos:

Tabela de operadores

Vamos entender os operadores um por um.

Operadores aritméticos: Sob esse operador, vem adição, subtração, exclusão, exponenciação, módulo e divisão de piso. Também a sintaxe abreviada.

Primeiro, declararemos duas variáveis ​​a e b.

>>> a = 6 # Assignment
>>> b = 2

Vamos tentar nossas operações aritméticas básicas:

>>> a + b # Addition
8
>>> a - b # Subtraction
4
>>> a * b # Multiplication
12
>>> a / b # Division
3.0
>>> a ** b # Exponentiation
36

Para testar outras operações aritméticas, vamos alterar o valor de a e b.

>>> a = 7
>>> b = 3
>>> a % b # Modulus
1
>>> a // b # Floor division
2

Operações aritméticas abreviadas também estão disponíveis em python. Consulte a imagem e você pode testá-la da mesma maneira que acima. Para imprimir, a saída da operação abreviada usa a instrução print.

Operadores de comparação: Sob esse operador, vem igual, maior que, menor que.

>>> a = 5 # Assign
>>> b = 2 # Assign
>>> a > b # Greater than
True
>>> a < b # less then
False
>>> a == b # Equal to
False
>>> a >= 5 # Greater than or equal to
True
>>> b <= 1 # Less than or equal to
False

Operadores lógicos: Sob este operador não vem, e, ou.

>>> a = 10
>>> b = 2
>>> a == 2 and b == 10 # and
False
>>> a == 10 or b == 10 # or
True
>>> not(a == 10) # not
False
>>> not(a == 2)
True


Declarações condicionais:

Como o nome sugere, instruções condicionais são usadas para avaliar se uma condição é verdadeira ou falsa. Muitas vezes, ao desenvolver um aplicativo, é necessário verificar uma determinada condição e, dependendo da execução, é necessário executar ou você deve pular essa parte ou encerrar. Nesses cenários, declarações condicionais são úteis. If, elif e else são as instruções condicionais usadas em python.

Podemos comparar a variável, verificar se a variável tem algum valor ou se é um booleano e depois verificar se é verdadeira ou falsa. Vá para o shell python e execute a operação passo a passo:

Número da condição 1: Temos um número inteiro e três condições aqui. O primeiro é o if doença. Está verificando se o número é igual a 10. O segundo é o elif doença. Aqui estamos verificando se o número é menor que 10. A última condição é else. Essa condição é executada quando nenhuma das condições acima corresponde.

>>> number = 5
>>> if number == 10:
...     print("Number is 10")
... elif number < 10:
...     print("Number is less than 10")
... else:
...     print("Number is more than 10")
...

Resultado:

Number is less than 10

Nota: Não é obrigatório verificar se duas condições são iguais no if doença. Você pode fazer isso no elif Ademais.

Número da condição 2: Temos duas condições booleanas e duas aqui. Você notou como estamos verificando se a condição é verdadeira. E se is_available depois imprima disponível ou imprima não disponível.

>>> is_available = True
>>> if is_available:
...     print("Yes it is available")
... else:
...     print("Not available")
...

Resultado:

Yes it is available

Número da condição 3: Aqui, revertemos o número da condição 2 com a ajuda de não operador.

>>> is_available = True
>>> if not is_available:
...     print("Not available")
... else:
...     print("Yes it is available")
...

Resultado:

Yes it is available

Número da condição 4: Aqui estamos declarando os dados como Nenhum e verificando se os dados estão disponíveis ou não.

>>> data = None
>>> if data:
...     print("data is not none")
... else:
...     print("data is none")
...

Resultado:

data is none

Número da condição 5: Você também pode usar inline se estiver em python. A sintaxe para conseguir isso é a seguinte:

>>> num_a = 10
>>> num_b = 5
>>> if num_a > num_b: print("num_a is greater than num_b")
...

Resultado:

num_a is greater than num_b

Número da condição 6: Você também pode usar o inline, caso contrário, em python. A sintaxe para conseguir isso é a seguinte:

expression_if_true if condition else expression_if_false

Exemplo:

>>> num = 5
>>> print("Number is five") if num == 5 else print("Number is not five")

Resultado:

Number is five

Número condicional 7: Você também pode usar if-else aninhado em python. A sintaxe para conseguir isso é a seguinte:

>>> num = 25
>>> if num > 10:
...     print("Number is greater than 10")
...     if num > 20:
...             print("Number is greater than 20")
...     if num > 30:
...             print("Number is greater than 30")
... else:
...     print("Number is smaller than 10")
...

Resultado:

Number is greater than 10
Number is greater than 20

Número da condição 8: Você também pode usar and operador em uma declaração condicional. Ele declara se a condição1 e a condição2 são verdadeiras, então execute-a.

>>> num = 10
>>> if num > 5 and num < 15:
...     print(num)
... else:
...     print("Number may be small than 5 or larger than 15")
...

Resultado:

10

Como nosso número está entre 5 e 15, obtemos a saída 10.

Número da condição 9: Você também pode usar or operador em uma declaração condicional. Ele afirma que, se a condição1 ou a condição2 for verdadeira, execute-a.

>>> num = 10
>>> if num > 5 or num < 7:
...     print(num)
...

Resultado:

10

Você está confuso porque o valor de num é 10 e nossa segunda condição afirma que num é menor que 7? Então, por que obtemos a saída como 10? É por causa do or doença. Quando uma das condições corresponder, ela será executada.


Para loops:

Outro método útil em qualquer linguagem de programação é um iterador. Considere que você precisa implementar algo várias vezes, o que você fará?

print("Hello")
print("Hello")
print("Hello")

Bem, essa é uma maneira de fazer isso. Mas imagine que você precise fazer isso cem ou mil vezes. Bem, são muitas as declarações impressas que temos que escrever. Espere, há uma solução disponível. É chamado de iteradores ou loops. Nós podemos usar um for ou while ciclo.

Aqui estamos usando o método range. Ele especifica o intervalo até o qual o loop deve ser repetido. Por padrão, o ponto inicial é 0.

>>> for i in range(3):
...     print("Hello")
...

Resultado:

Hello
Hello
Hello

Você também pode especificar o intervalo dessa maneira range(1,3).

>>> for i in range(1,3):
...     print("Hello")
...

Resultado:

Hello
Hello

Veja Olá é impresso apenas duas vezes, conforme especificamos o intervalo aqui. Considere que tem Number on right - Number on left equação.

Bem, você também pode adicionar uma instrução else no loop for.

>>> for i in range(3):
...     print("Hello")
... else:
...     print("Finished")

Resultado:

Hello
Hello
Hello
Finished

Veja nosso loop iterado 3 vezes (3 - 0) e, uma vez feito isso, ele executou a instrução else.

Também podemos aninhar um loop for dentro de outro loop for.

>>> for i in range(3):
...     for j in range(2):
...             print("Inner loop")
...     print("Outer loop")
...

Resultado:

Inner loop
Inner loop
Outer loop
Inner loop
Inner loop
Outer loop
Inner loop
Inner loop
Outer loop

Como você pode ver, a instrução de impressão do loop interno é executada duas vezes. Após essa instrução de impressão do loop externo ser executada. Novamente, o loop interno é executado duas vezes. Então o que está acontecendo aqui? Se você está confuso, considere isso para resolvê-lo:

  • Nosso intérprete vem e vê ahh! existe um for ciclo. Desce novamente e verifica se há outra for ciclo.
  • Então agora ele irá executar o interior for loop duas vezes e saia. Uma vez feito isso, ele sabe que o loop for externo o instruiu a repetir mais duas vezes.
  • Começa novamente e vê o loop for interno e se repete.

Bem, você também pode optar por passar um certo for condição de loop. O que significa pass aqui? Bem, sempre que esse loop for ocorrer e o intérprete vir o pass declaração não o executará e passará para a próxima linha.

>>> for i in range(3):
...     pass
...

Você não obterá nenhuma saída no shell.


Enquanto loops:

Outro loop ou iterador disponível em python é while ciclo. Podemos obter alguns resultados com a ajuda de um while loop como alcançamos com o for ciclo.

>>> i = 0
>>> while i < 5:
...     print("Number", i)
...     i += 1
...

Resultado:

Number 0
Number 1
Number 2
Number 3
Number 4

Lembre-se sempre que você usa um loop while, é importante adicionar uma instrução de incremento ou uma instrução que levará ao fim do loop while em algum momento. Caso contrário, o loop while será executado para sempre.

Outra opção é adicionar um break declaração em um while ciclo. Isso vai quebrar o ciclo.

>>> i = 0
>>> while i < 5:
...     if i == 4:
...             break
...     print("Number", i)
...     i += 1
...

Resultado:

Number 0
Number 1
Number 2
Number 3

Aqui estamos quebrando o while loop se encontrarmos o valor de i ser 4.

Outra opção é adicionar um else declaração em while ciclo. A instrução será executada após o loop while ser concluído.

>>> i = 0
>>> while i < 5:
...     print("Number", i)
...     i += 1
... else:
...     print("Number is greater than 4")
...

Resultado:

Number 0
Number 1
Number 2
Number 3
Number 4
Number is greater than 4

o continue A instrução pode ser usada para pular a execução atual e prosseguir para a próxima.

>>> i = 0
>>> while i < 6:
...     i += 1
...     if i == 2:
...             continue
...     print("number", i)
...

Resultado:

number 1
number 3
number 4
number 5
number 6


Entrada do usuário:

Imagine que você está construindo um aplicativo de linha de comando. Agora você tem que pegar a entrada do usuário e agir de acordo. Aí vem o método embutido do python input.

A sintaxe para conseguir isso é a seguinte:

variable = input(".....")

Exemplo:

>>> name = input("Enter your name: ")
Enter your name: Sharvin

Quando você usa o input método e pressione enter. Você será solicitado com o texto digitado no input método. Vamos verificar se nossa tarefa está funcionando ou não?

>>> print(name)
Sharvin

Aí está!! está funcionando perfeitamente. Aqui Sharvin é do tipo string.

>>> type(name)

Vamos tentar mais um exemplo em que atribuiremos um número inteiro ao invés de uma string e verificaremos o tipo.

>>> date = input("Today's date: ")
Today's date: 12
>>> type(date)

Você está confuso?? Nós inserimos um número inteiro 12 e ele ainda está nos dando seu tipo como uma string. Não é um bug. É como a entrada se destina a funcionar. Para converter a string em número inteiro, usaremos typecast.


Typecasting:

Vimos que o input O método retorna uma sequência para o número inteiro também. Agora, queremos comparar essa saída com outro número inteiro, então precisamos de uma maneira de convertê-la novamente em um número inteiro. Aí vem a tipografia em jogo.

>>> date_to_int = int(date)
>>> type(date_to_int)

Aqui pegamos a data que declaramos acima na seção de entrada do usuário e a convertemos em número inteiro usando o método int embutido do python. Isso é chamado de conversão de tipo.

Basicamente, você pode fazer a seguinte conversão com a ajuda da conversão de tipo:

  • inteiro para string: str()
  • string para inteiro: int()
  • número inteiro para flutuar: float()

Nota: A conversão de float para inteiro também é possível.

>>> type(date)


# Converting from string to float
>>> date_to_float = float(date)
>>> type(date_to_float)


# Converting from float to string
>>> date_to_string = str(date_to_float)
>>> type(date_to_string)


# Converting from float to integer
>>> date_to_int = int(date_to_float)
>>> type(date_to_int)


Dicionários:

Imagine que você deseja armazenar alguns detalhes do usuário. Então, como você pode armazenar esses detalhes? Sim, podemos usar a variável para armazená-los da seguinte maneira:

>>> fname = "Sharvin"
>>> lname = "Shah"
>>> profession = "Developer"

Para acessar esse valor, podemos acessá-los da seguinte maneira:

>>> print(fname)
Sharvin

Mas essa é uma maneira elegante e otimizada de acessá-lo? A resposta é não. Para torná-lo mais amigável e armazenar os dados em um dicionário de valores-chave, vem em nosso socorro.

O que é um dicionário? Um dicionário é uma coleção desordenada e mutável (ou seja, pode ser atualizada).

A seguir está o formato do dicionário:

data = {
	"key" : "value"
}

Vamos entender o dicionário ainda mais com um exemplo:

>>> user_details = {
...     "fname": "Sharvin",
...     "lname": "Shah",
...     "profession": "Developer"
... }

Valor de acesso no dict: Podemos acessar o valor dentro de um dicionário de duas maneiras. Primeiro entenderemos os dois caminhos e, em seguida, iremos depurar para descobrir qual caminho é melhor.

Caminho_No_1: Para acessar o valor de fname chave de user_details No dicionário, podemos usar a seguinte sintaxe:

>>> user_details["fname"]
'Sharvin'

Way_No_2: Também podemos acessar o valor de fname chave de user_details dicionário usando get.

>>> user_details.get("fname")
'Sharvin'

Eu sei que Way_No_1 parece mais fácil de entender. O problema dessa maneira é quando tentamos acessar os dados que não estão disponíveis em nosso dicionário.

>>> user_details["age"]
Traceback (most recent call last):
  File "", line 1, in 
KeyError: 'age'

Temos um KeyError que indica que a chave não está disponível. Vamos tentar o mesmo cenário com o Way_No_2.

>>> user_details.get("age")

Não temos nada impresso em nosso console. Vamos depurar ainda mais para saber por que isso aconteceu? Atribua uma idade variável ao nosso get operação e vamos imprimi-lo em nosso console.

>>> age = user_details.get("age")
>>> print(age)
None

Ahh !! Então quando get não encontra a chave que define o valor como None e, por isso, não obtemos nenhum erro. Agora você pode estar se perguntando qual é o certo? Na maioria das vezes, o uso do Way_No_2 faz mais sentido, mas para algumas condições rigorosas de verificação, precisamos usar o Way_No_1.

Verifique se a chave existe: Você pode estar se perguntando como verificar se o dicionário é uma chave específica ou não em python. Python fornece um método embutido keys() para resolver esse problema.

>>> if "age" in user_details.keys():
...     print("Yes it is present")
... else:
...     print("Not present")
...

Obteremos a seguinte saída:

Not present

E se quisermos verificar se o dicionário está vazio ou não? Para entender isso, vamos declarar um dicionário vazio da seguinte maneira:

>>> user_details = {}

Quando usamos o if-else diretamente em um dicionário, ele retorna true se os dados estiverem presentes ou false se estiver vazio.

>>> if user_details:
...     print("Not empty")
... else:
...     print("Empty")
...

Resultado:

Empty

Também podemos usar o método embutido do python bool para verificar se o dicionário está vazio ou não. Lembre-se de que bool retorna False se o dicionário estiver vazio e True se estiver preenchido.

>>> bool(user_details)
False

>>> user_details = {
...     "fname" : "Sharvin"
... }
>>> bool(user_details)
True

Atualize o valor da chave existente: Então agora sabemos como obter uma chave específica e descobrir se ela existe, mas como atualizá-la no dicionário?

Declare um dicionário da seguinte maneira:

>>> user_details = {
...     "fname":"Sharvin",
...     "lname": "Shah",
...     "profession": "Developer"
... }

Para atualizar o valor, use a seguinte sintaxe:

>>> user_details["profession"] = "Software Developer"
>>> print(user_details)
{'fname': 'Sharvin', 'lname': 'Shah', 'profession': 'Software Developer'}

Atualizar um valor de chave no dicionário é o mesmo que atribuir um valor à variável.

Adicionando par de valores-chave: A próxima pergunta é como adicionar um novo valor ao dicionário? Vamos adicionar um age chave com um valor de 100.

>>> user_details["age"] = "100"
>>> print(user_details)
{'fname': 'Sharvin', 'lname': 'Shah', 'profession': 'Software Developer', 'age': '100'}

Como você pode ver, um novo valor-chave é adicionado em nosso dicionário.

Removendo o par de valores-chave: Para remover um valor-chave do dicionário, o python fornece um método embutido chamado pop.

>>> user_details.pop("age")
'100'

>>> print(user_details)
{'fname': 'Sharvin', 'lname': 'Shah', 'profession': 'Software Developer'}

Isso remove o par de valores-chave de idade do dicionário user_details. Também podemos usar um del operador para excluir o valor.

>>> del user_details["age"]

>>> print(user_details)
{'fname': 'Sharvin', 'lname': 'Shah', 'profession': 'Software Developer'}

o del O método também pode ser usado para excluir dicionário completo. Use a seguinte sintaxe para excluir o dicionário completo del user_details.

Copie um dicionário: Um dicionário não pode ser copiado da maneira tradicional. Por exemplo, você não pode copiar o valor de dictA para dictB da seguinte maneira:

dictA = dictB

Para copiar os valores, você precisa usar o copy método.

>>> dictB = user_details.copy()

>>> print(dictB)
{'fname': 'Sharvin', 'lname': 'Shah', 'profession': 'Software Developer'}


Listas:

Considere que você tem um monte de dados que não são rotulados (ou seja, ele não tem uma chave que os define). Então, como você os armazenará? E aqui vem Listas em nosso socorro. Eles estão definidos da seguinte forma:

data = [ 1, 5, "xyz", True ]

Uma lista é uma coleção de dados aleatórios, ordenados e mutáveis ​​(ou seja, podem ser atualizados).

Elementos da lista de acesso: Vamos tentar acessar o primeiro elemento:

>>> data[1]
5

Espera o que aconteceu aqui? Estamos tentando acessar o primeiro elemento, mas estamos recebendo o segundo elemento. Por quê? A indexação da lista começa do zero. Então, o que quero dizer com isso? A indexação da posição dos elementos começa do zero. A sintaxe para acessar um elemento é a seguinte:

list[position_in_list]

Para acessar o primeiro elemento, precisamos acessá-lo da seguinte maneira:

>>> data[0]
1

Você também pode especificar um intervalo para acessar o elemento entre essas posições.

>>> data[2:4]
['xyz', True]

Aqui o primeiro valor representa o início, enquanto o último valor representa a posição até a qual queremos o valor.

Adicione um item à lista: Para adicionar um item na lista, precisamos usar o método append fornecido pelo python.

>>> data.append("Hello")

>>> data
[1, 5, 'abc', True, 'Hello']

Alterar valor do item: Para alterar o valor de um item, use a seguinte sintaxe:

>>> data[2] = "abc"

>>> data
[1, 5, 'abc', True]

Remova o item da lista: Para remover um item de uma lista, podemos usar os recursos embutidos do python remove método.

>>> data.remove("Hello")
>>> data
[1, 5, 'abc', True]

Percorra uma lista: Também podemos percorrer a lista para encontrar um determinado elemento e operá-lo.

>>> for i in data:
...     print(i)
...

Resultado:

1
5
abc
True

Verifique se o item existe ou não: Para verificar se um item específico existe ou não está na lista, podemos usar o loop if da seguinte maneira:

>>> if 'abc' in data:
...     print("yess..")
...
yess..

Cópia de: Para copiar os dados de uma lista de uma lista para outra, precisamos usar copy método.

>>> List2 = data.copy()
>>> List2
[1, 5, 'abc', True]

Comprimento: Também podemos verificar o tamanho da lista usando o recurso embutido do Python len método.

>>> len(data)
4

Junte-se a duas listas: Para juntar duas listas, podemos usar + operador.

>>> list1 = [1, 4, 6, "hello"]
>>> list2 = [2, 8, "bye"]
>>> list1 + list2
[1, 4, 6, 'hello', 2, 8, 'bye']

O que acontece se tentarmos acessar uma posição do elemento que não está disponível na lista? Temos um list index out of range error em tal condição.

>>> list1[6]
Traceback (most recent call last):
  File "", line 1, in 
IndexError: list index out of range


Tuplas:

A tupla é de um tipo de dados que é ordenado e imutável (ou seja, os dados não podem ser alterados)

Vamos criar uma tupla:

>>> data = ( 1, 3 , 5, "bye")
>>> data
(1, 3, 5, 'bye')

Acesse o elemento da tupla: Podemos acessar elementos na tupla da mesma maneira que acessamos na lista:

>>> data[3]
'bye'

Podemos acessar o intervalo de índice da seguinte maneira:

>>> data[2:4]
(5, 'bye')

Alterar o valor da tupla: Se você está pensando em como podemos alterar o valor da tupla, você está certo, meu amigo. Não podemos alterar o valor da tupla, pois é imutável. Obtemos o seguinte erro se tentarmos alterar o valor da tupla:

>>> data[1] = 8
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'tuple' object does not support item assignment

Existe uma solução alternativa disponível para alterar o valor da tupla:

>>> data = ( 1, 3 , 5, "bye")
>>> data_two = list(data) # Convert data to list
>>> data_two[1] = 8 # Update value as list is mutable
>>> data = tuple(data_two) # Convert again to tuple
>>> data
(1, 8, 5, 'bye')

Todos os outros métodos que vimos na lista também são aplicáveis ​​à tupla.

[ Note: Once a tuple is created a new value cannot be added in it. ].


Conjuntos:

Sets é outro tipo de dados em python que não é ordenado e não indexado. Os conjuntos são declarados da seguinte maneira:

>>> data = { "hello", "bye", 10, 15 }
>>> data
{10, 15, 'hello', 'bye'}

Valor de acesso: Como os conjuntos não são indexados, não podemos acessar diretamente o valor em um conjunto. Portanto, para acessar o valor no conjunto, você precisa usar um loop for.

>>> for i in data:
...     print(i)
...

10
15
hello
bye

Alterar valor: Depois que o conjunto é criado, os valores não podem ser alterados.

Adicionar Item: Para adicionar um item ao conjunto, o python fornece um método embutido chamado add.

>>> data.add("test")
>>> data
{10, 'bye', 'hello', 15, 'test'}

Verifique o comprimento: Para verificar a duração do conjunto, usamos o len método.

>>> len(data)
5

Remover item: Para remover um item, use o remove método:

>>> data.remove("test")
>>> data
{10, 'bye', 'hello', 15}


Funções e argumentos:

As funções são uma maneira útil de declarar uma operação que queremos executar. Com a ajuda da função, você pode separar a lógica de acordo com a operação.

Eles são um bloco de código que nos ajuda na reutilização da lógica repetitiva. As funções podem ser incorporadas e definidas pelo usuário.

Para declarar uma função, usamos o def palavra-chave A seguir, é apresentada a sintaxe das funções:

>>> def hello_world():
...     print("Hello world")
...

Aqui estamos declarando uma função que, quando chamada, imprime uma declaração Hello world. Para chamar uma função, usamos a seguinte sintaxe.

>>> hello_world()

Obteremos a seguinte saída:

Hello world

Lembrar () suporte em uma chamada de função significa executá-lo. Remova os colchetes e tente a chamada novamente.

>>> hello_world

Você obterá a seguinte saída:

Quando removemos o colchete da chamada de função, ele nos fornece uma referência de função. Aqui acima, como você pode ver a referência de function hello_world aponta para este endereço de memória 0x1083eb510.

Considere que você deve executar uma operação de adição. Você pode fazer isso declarando aeb executando a adição.

>>> a = 5
>>> b = 10
>>> a + b
15

Este é um caminho a percorrer, mas agora considere o valor de a e b mudaram e você precisa fazê-lo novamente.

>>> a = 5
>>> b = 10
>>> a + b
15
>>> a = 2
>>> b = 11
>>> a + b
13

Isso ainda parece factível. Agora imagine que precisamos adicionar um conjunto de dois números cem vezes. Os números dentro do conjunto são diferentes para cada cálculo. Isso é muito o que fazer. Não se preocupe, temos uma função à nossa disposição para resolver esse problema.

>>> def add(a,b):
...     print(a+b)
...

Aqui estamos adicionando a e b como argumento obrigatório ao add função. Para chamar essa função, usaremos a seguinte sintaxe:

>>> add(10,5)

Resultado:

15

Veja como é fácil definir uma função e usá-la. Então, o que acontece se não aprovarmos uma discussão?

>>> add()
Traceback (most recent call last):
  File "", line 1, in 
TypeError: add() missing 2 required positional arguments: 'a' and 'b'

Python lança um TypeError e nos informa que a função requer dois argumentos.

Você consegue adivinhar o que acontecerá se aprovarmos um terceiro argumento?

>>> add(10,5,1)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: add() takes 2 positional arguments but 3 were given

Bem, o python nos informará que passamos 3 argumentos, mas existem apenas 2 argumentos posicionais.

Então, o que podemos fazer quando não sabemos quantos argumentos uma função pode levar? Para resolver esse problema, usamos args e kwargs.


Args:

Quando você não sabe quantos argumentos serão passados ​​para a função, args e kwargs são usados ​​nesse cenário.

Para passar n número de argumentos para uma função, usamos args. Nós adicionamos um * por trás da discussão.

Lembre-se de quando você anexa um * na frente, você receberá uma tupla de argumentos.

>>> def add(*num):
...     print(num)
...

Aqui *num é um argumento. Agora, quando chamamos a função add podemos passar n número de argumentos e não lançará um TypeError.

>>> add(1,2,3)
(1, 2, 3)

>>> add(1,2,3,4)
(1, 2, 3, 4)

Agora, para executar a operação de adição, usaremos a função interna do Python sum

>>> def add(*num):
...     print(sum(num))
...

Agora, quando chamamos a função add, obteremos a seguinte saída:

>>> add(1,2,3) # Function call
6
>>> add(1,2,3,4) # Function call
10


Argumentos de palavras-chave:

Há alguma condição em que não sabemos a ordem de como os argumentos serão transmitidos para a função quando forem chamados. Nesse cenário, usamos argumentos de palavras-chave porque você pode transmiti-los em qualquer ordem em sua chamada e nossa função saberá o valor. Vamos entender esse conceito por exemplo.

>>> def user_details(username, age):
...     print("Username is", username)
...     print("Age is", age)
...

Vamos chamar essa função da seguinte maneira:

>>> user_details("Sharvin", 100)

Obteremos a seguinte saída:

Username is Sharvin
Age is 100

Bem, isso parece correto, mas imagine se chamamos nossa função dessa maneira:

>>> user_details(100, "Sharvin")

Obteremos a seguinte saída:

Username is 100
Age is Sharvin

Isso não parece certo. O que aconteceu é username assumiu o valor de 100 enquanto age tomou o valor de Sharvin. Em cenários como este, onde não sabemos a ordem dos argumentos, podemos usar argumentos de palavras-chave ao chamar a função da seguinte maneira:

>>> user_details(age=100, username="Sharvin")

Resultado:

Username is Sharvin
Age is 100

Veja que isso é mágico, temos nossa saída correta.


Argumento padrão:

Suponha que exista uma condição em que não tenhamos certeza se um argumento específico obterá um valor ou não quando a função for chamada. Nesse cenário, podemos usar argumentos padrão da seguinte maneira:

>>> def user_details(username, age = None):
...     print("Username is", username)
...     print("Age is", age)
...

Aqui estamos atribuindo um None ao nosso argumento da idade. Se não passarmos o segundo argumento enquanto chamamos a função, será usado None como valor padrão.

Vamos chamar a função:

>>> user_details("Sharvin")

Resultado:

Username is Sharvin
Age is None

Lembre-se de que quando passamos o segundo argumento, nesse cenário, ele substituirá o Nenhum e o utilizará como valor.

>>> user_details("Sharvin", 200)
Username is Sharvin
Age is 200

O que acontecerá se for atribuído o primeiro argumento em nossa função como padrão e o segundo como argumento obrigatório? Vá para o shell python e tente isso.

>>> def user_details(username=None, age):
...     print("Username is", username)
...     print("Age is", age)
...

Você receberá o seguinte erro:

  File "", line 1
SyntaxError: non-default argument follows default argument

Lembrar: Todos os argumentos obrigatórios devem ser declarados primeiro e, em seguida, o argumento padrão deve ser declarado.


kwargs:

Pode haver uma situação em que você não sabe quantos argumentos de palavras-chave serão passados ​​para a função. Nesse cenário, podemos usar o Kwargs.

Para usar kwargs, colocamos ** na frente do argumento.

Lembrar: Quando você anexa um ** na frente, você receberá um dicionário de argumentos.

Vamos entender isso por exemplo. Declararemos uma função que aceita nome de usuário como argumento com ** na frente dele.

>>> def user(**username):
...     print(username)
...

Quando chamamos o user funcionar da seguinte maneira, receberemos um dicionário.

>>> user(username1="xyz",username2="abc")

Resultado:

{'username1': 'xyz', 'username2': 'abc'}

Então, o que está acontecendo aqui? Parece o mesmo que Args, certo? Não, não é. Nos argumentos, você não pode acessar um valor específico por seu nome, pois ele está na forma de uma tupla. Aqui obtemos os dados na forma de um dicionário. Para que possamos acessar facilmente o valor. Considere este exemplo:

>>> def user(**user_details):
...     print(user_details['username'])
...

Vamos chamar nossa função:

>>> user(username="Sharvin",age="1000")

E você obterá a seguinte saída:

Sharvin


Escopo:

Um escopo define onde uma variável ou função está disponível. Existem dois tipos de escopo em python, ou seja, Global e Local.

Âmbito global: Uma variável ou função criada no corpo principal do código python é chamada de variável ou função global e faz parte do escopo global. Vamos entender esse conceito por exemplo:

>>> greet = "Hello world"
>>> def testing():
...     print(greet)
...
>>> testing()
Hello world

Aqui, a variável greet está disponível globalmente porque é declarada no corpo do python.

Escopo local: Uma variável ou função criada dentro de uma função é chamada de variável ou função local e faz parte do escopo local. Vamos entender esse conceito por exemplo:

>>> def testing():
...     greet = "Hello world"
...     print(greet)
...
>>> testing()
Hello world

Aqui o greet é criado dentro da função de teste e está disponível apenas lá. Vamos tentar acessá-lo em nosso corpo principal e ver o que acontece.

>>> print(greet)
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'greet' is not defined

Lembrar: Para testar a condição acima, lembre-se de reiniciar o console python clicando em ctrl + d e iniciando novamente o shell python usando python3 comando. A razão por trás disso é que já declaramos greet variáveis ​​em nosso escopo global e está disponível em nossa memória.

Como o greet não está disponível globalmente, obtemos o erro de que ele não está definido.


Declaração de retorno:

Até agora, nossas funções são praticamente estúpidas. Eles estão recebendo os dados, processando-os e imprimindo-os. Mas no mundo real, você precisa de uma função para fornecer saída. Para que essa saída possa ser usada em diferentes operações.

Para isso, são utilizadas instruções de retorno. Lembre-se de que as instruções de retorno são apenas parte de funções e métodos. A sintaxe para a declaração de retorno é bastante fácil.

>>> def add(a, b):
...     return a + b
...
>>> add(1,3)
4

Em vez de imprimir nossa adição, estamos retornando a saída. O valor da saída retornada também pode ser armazenado em uma variável.

>>> sum = add(5,10)
>>> print(sum)
15


Expressão Lambda:

Considere uma situação em que você não deseja executar muita computação em uma função. Em tal situação, escrever uma função completa não faz sentido. Para resolver isso, usamos uma expressão lambda.

Então, o que é uma função lambda? É uma função anônima e eles estão restritos a uma única expressão. A função lambda pode receber n número de argumentos.

A sintaxe da função lambda é:

variable = lambda arguments: operation

Vamos entender mais por exemplo:

>>> sum = lambda a: a + 10

Aqui declaramos uma variável sum que estamos usando para chamar a função lambda. a representa o argumento que é passado para essa função.

Vamos chamar nossa função:

>>> x(5)
15


Compreensão da lista:

Considere uma situação em que você deseja uma lista de quadrados. Normalmente você declarará um squares lista e, em um loop for, você quadrará os números.

>>> squares = []
>>> for x in range(10):
...     squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Bem, isso é possível, mas podemos conseguir isso em uma única linha com a ajuda da compreensão da lista.

Existem duas maneiras de conseguir isso. Vamos entender os dois.

>>> squares = list(map(lambda x: x**2, range(10)))
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Aqui estamos usando list construtor para criar uma lista e dentro dessa função lambda que esquadrinha o número. Outra maneira de obter o mesmo resultado é a seguinte:

>>> squares = list(x**2 for x in range(10))
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Eu prefiro assim porque é mais fácil de entender devido à sua legibilidade e concisão.

E quando temos uma condição em que queremos um conjunto de dois números iguais. Bem, precisamos escrever dois para loops e um se.

Vamos ver como isso será:

>>> num_list = []
>>> for i in range(10):
...     for j in range(10):
...             if i == j:
...                     num_list.append((i,j))
...
>>> num_list
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)]

Isso dá muito trabalho e, em termos de legibilidade, é difícil de entender.

Vamos usar a compreensão da lista para obter o mesmo resultado.

>>> num_list = list((i,j) for i in range(10) for j in range(10) if i == j)

>>> num_list
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)]

Consulte Como é fácil obter a mesma saída em uma única expressão. Bem, esse é o poder da compreensão da lista. Ao iniciar o desenvolvimento de um aplicativo, você descobrirá que a compreensão da lista é poderosa.


Conceitos OOPS:

Python é uma linguagem de programação com vários paradigmas. Isso significa que o python pode usar abordagens diferentes para resolver o problema. Um dos paradigmas é a programação processual ou funcional. Ele estrutura o código como uma receita; conjunto de etapas na forma de função e bloco de código.

Outra abordagem para resolver o problema é criar classes e objetos. Isso é conhecido como programação orientada a objetos. Um objeto é uma coleção de dados (variáveis) e métodos que atuam sobre esses dados. E, a classe é um modelo para o objeto.

The important part to understand in object-oriented programming is that objects are at the center of the paradigm, not only representing the data but it also represents the structure of the program.

You can choose the paradigm that best suits the problem at hand, mix different paradigms in one program, and/or switch from one paradigm to another as your program evolves.

Advantages of object oriented programming:

  • Inheritance: This is one of the most useful concepts in oops. It specifies that the child object will have all the properties and behavior of the parent object. Thus Inheritance allows us to define a class that inherits all the methods and properties from another class.
  • Polymorphism: To understand polymorphism let’s divide the word into two parts. The first part poly means many and morph means to form or shape. Thus in simple one-word polymorphism means one task can be performed in many different ways. For example, you have a class animal, and all animals speak. But they speak differently. Here, the “speak” behavior is polymorphic and depends on the animal. So, the abstract “animal” concept does not actually “speak”, but specific animals (like dogs and cats) have a concrete implementation of the action “speak”. Polymorphism means the same function name or method name being used for different types.
  • Encapsulation: In object-oriented programming you can restrict access to methods and variables; we can make the methods and variables private. This can prevent the data from being modified by accident and is known as encapsulation.

First, we will understand classes, objects, constructor and after that, we will look into the above properties again. If you know about the classes, object, and constructor you can skip to the section that you want to read.


Classes:

There are primitive data structures available in python for example numbers, strings, and lists that can be used for simple representation like name, place or cost, etc.

But what if we have a condition where we have complex data. There is a pattern in the repetition of the properties of that data in that scenario what can we do?

Suppose we have a data of 100 different animals. Every animal has a name, age, legs, etc. What if we want to add other properties to animal or one more animal gets added to that list. To manage all such complex scenario’s we need classes.

According to official python documentation, Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made.

Each class instance can have attributes attached to it for maintaining its state. Class instances can also have methods (defined by its class) for modifying its state.

Syntax of class:

class ClassName:

    
    .
    .
    .
    

Nós usamos class keyword to define a class. We will define a class Car.

class Car:
    pass


Methods:

Methods look the same like function only difference is that methods are dependent on the object. A function can be invoked by name while methods need to be invoked by using their class reference. They are defined inside the class.

In our example, let's create 2 methods. One is an engine and another is a wheel. These 2 methods define the parts available in our car.

The below program will give us a better idea of classes:

>>> class Car:
...     def engine(self):
...             print("Engine")
...

>>> Car().engine()
Engine

Here we are calling the engine method by using the Car() reference.

To summarise, the class provides a blueprint of what should be defined but it does not provide any real content. o Car class above defines the engine but it will not state what a specific car’s engine is. It is specified by the object.


Objects:

If you are fully clear with classes and method we will move to objects. If you still have any doubt reread both the sections again.

The object is an instance of the class. Let’s consider the above example of a car. Here Car is our class and toyota is the object of the car. We can create multiple copies of the object. Every object must be defined using the class.

The syntax for creating an object is:

toyota = Car()

Let’s consider our Car example for understanding the objects more better.

class Car:

    def engine(self):
        print("Engine")

    def wheel(self):
        print("Wheel")

toyota = Car()

The above toyota = Car() é um class object. Class objects support two kinds of operations: attribute references and instantiation.

Class instantiation uses function notation. The instantiation operation (“calling” a class object) creates an empty object.

Now we can call different methods from our class Car using the object toyota that we have created. let’s call the method engine e wheel.

Open your editor and create a file named mycar.py. In that file copy the code below:

class Car:

    def engine(self):
        print("Engine")

    def wheel(self):
        print("Wheel")

if __name__ == "__main__":
    toyota = Car()
    toyota.engine()
    toyota.wheel()

Save the above code. Let's under our program.

Here we are creating a toyota object with the help of Car classe. o toyota.engine() is a method object. What exactly happens when a method object is called? In the call toyota.engine() doesn't take any argument but if you see the method declaration we can see that it takes a self argumento. You may be confused about why it is not throwing an error. Well whenever we use a method object, the call toyota.engine() is converted to Car.engine(toyota). We will understand more about the self in the upcoming section.

Run the program using the following command.

python mycar.py

You'll get the following output:

Engine
Wheel


Constructor:

o __init__ method is the constructor method in python. The constructor method is used to initialize the data.

Go to the python shell and test the below example:

>>> class Car():
...     def __init__(self):
...             print("Hello I am the constructor method.")
...

When we will call our class we will get the following output:

>>> toyota = Car()
Hello I am the constructor method.

Nota: You will never have to call the init() method; it gets called automatically when you create a class instance.


Instance attributes:

All the classes have objects and all the objects have attributes. Attributes are the properties. Nós usamos __init__() method to specify an object’s initial attribute.

Let’s consider our car example:

class Car():
    def __init__(self, model): 
        self.model = model  #instance attribute

In our example, each Car() has a specific model. Thus instance attributes are unique data to each instance.


Class attributes:

We saw that instance attributes are specific to each object but class attributes are the same for all the instances. Let us look at the example of the car with the help of class attributes.

class Car():

    no_of_wheels = 4 #class attribute

So each car can have different models but all the cars will have 4 wheels only.


Self:

Now let’s understand what does self means and how we use it in object-oriented programming. o self represents the instance of a class. Using the self keyword we can access the data initialize in the constructor and methods of a class.

Let us look at an example of how the self can be used. Let’s create a method named brand under our class Car.

Inside that __init__ method, we will pass a model by passing our car’s model name when we are instantiating our object. This name can be accessed anywhere in the class for example self.model in our case.

Go to the file named mycar.py and replace old code with this code:

class Car(): 

  def __init__(self, model): 
    self.model = model
  		
  def brand(self): 
    print("The brand is", self.model)  

if __name__ == "__main__":
  car = Car("Bmw")
  car.brand()

Now when we run our above program using the following command:

python mycar.py

We will get the following output:

The brand is Bmw

Nota:self is a convention and not a real python keyword. UMA self is a argument in method and we can use another name in place of it. But it is recommended to use self because it increases the readability of code.


Inheritance:

When a class inherits the property of another class then this scenario is called inheritance.

The class from which properties are inherited is called the base class. The class which inherits the property of another class is called the derived class.

Inheritance can be defined as a parent and child relationship. The child inherits the properties of the parent. Thus making the child a derived class while parent as a base class. Here term property refers to attributes and methods.

The syntax for a derived class definition looks like this:

class DerivedClassName(BaseClassName):
    
    .
    .
    .
    

It’s important to note that child classes override or extend the attributes and behaviors of parent class methods. In other words, child classes inherit all of the parent’s attributes and behaviors but can also specify different behavior to follow.

The most basic type of class is an object, which generally all other classes inherit as their parent. Let’s modify our previous example to understand how inheritance works.

We will create a base class named vehicle:

class Vehicle:
    def __init__(self, name):
        self.name = name
    
    def getName(self):
        return self.name

We have created a class Vehicle and instantiated a constructor with self.name which we are using in getName método. Whenever this method will be called, it will return the name that has been passed when an object is instantiated for that class.

Now let’s create a child class Car:

class Vehicle:
    def __init__(self, name):
        self.name = name
    
    def getName(self):
        return self.name

class Car(Vehicle):
  pass

Car is a child class of Vehicle. It inherits all the method and attributes of parent class.

Now let’s use methods and attribute from the Vehicle class in our child class Car.

class Vehicle:

    def __init__(self, name, color='silver'):
        self.name = name
        self.color = color
    
    def get_name(self):
        return self.name
    
    def get_color(self):
        return self.color

class Car(Vehicle):
  pass

audi = Car("Audi r8")
print("The name of our car is", audi.get_name(), "and color is", audi.get_color())

Let's understand what we have done here. We have declared a class named Vehicle with a constructor that takes name as an argument while color has default argument. We have two methods inside it. o get_name returns name while the get_color returns the color. We have instantiated a object and passed the car name.

One thing you'll notice here that we are using base class methods in our child class declaration.

Run the above program using the following command:

python mycar.py

Resultado:

The name of our car is Audi r8 and color is silver

We can also override a parent method or attribute. In the above example, we have defined our vehicle color has silver. But what if the color of our car is black?

Now for every child class, we can’t make changes in the parent class. There comes the overriding functionality.

class Vehicle:

    def __init__(self, name, color='silver'):
        self.name = name
        self.color = color
    
    def get_name(self):
        return self.name
    
    def get_color(self):
        return self.color

class Car(Vehicle):

    def get_color(self):
        self.color = 'black'
        return self.color

audi = Car("Audi r8")
print("The name of our car is", audi.get_name(), "and color is", audi.get_color()

As you can see in the above program, I have not instantiated a constructor. The reason behind this is that our child class Car is only using attributes from the Vehicle class and it is already inheriting them. So in such a scenario, there is no need to re-instantiate these attributes.

Now When we run the above program we will get the following output:

The name of our car is Audi r8 and color is black


Super:

o super() returns a temporary object of the superclass that then allows us to call that superclass’s methods. Calling the previously built methods with super() saves us from needing to rewrite those methods in our subclass, and allows us to swap out superclasses with minimal code changes. Thus super extends the functionality of the inherited method.

Let’s extend our car example using super(). We will instantiate a constructor with brand_name e color in the parent class; Vehicle. Now we will call this constructor from our child class (Car) using super. We will create a get_description method which is returning self.model de Car class and self.brand_name, self.color de Vehicle classe.

class Vehicle:
 
    def __init__(self, brand_name, color):
        self.brand_name = brand_name
        self.color = color
 
    def get_brand_name(self):
        return self.brand_name
 
class Car(Vehicle):
 
    def __init__(self, brand_name, model, color):  
        super().__init__(brand_name, color)       
        self.model = model
 
    def get_description(self):
        return "Car Name: " + self.get_brand_name() + self.model + " Color:" + self.color
 
c = Car("Audi ",  "r8", " Red")
print("Car description:", c.get_description())
print("Brand name:", c.get_brand_name())

When we run the above program we get following output:

Car description: Car Name: Audi r8 Color: Red
Brand name: Audi


Multiple Inheritance:

When a class inherits the method and attributes from multiple parent class then it is called multiple inheritance. This allows us to use the property from multiple base classes or parent classes in a derived or child class.

The general syntax of Multiple Inheritance is as follows:

class DerivedClassName(Base1, Base2, Base3):
    
    .
    .
    .
    

Let’s extend our vehicle example using multiple inheritance property. Here in this example, we will create 3 classes i.e. Vehicle, Cost e Car

Classe Vehicle e Cost will be the Parent class. UMA Vehicle class represents the general property while the Cost class represents its pricing.

Enquanto o Car has a general property and costing both it will have 2 parent classes. Thus we will inherit multiple parent classes.

class Vehicle:

    def __init__(self, brand_name):
        self.brand_name = brand_name
    
    def get_brand_name(self):
        return self.brand_name


class Cost:		

    def __init__(self, cost):
        self.cost = cost
    
    def get_cost(self):
        return self.cost

 
class Car(Vehicle, Cost):	

    def __init__(self, brand_name, model, cost): 
        self.model = model 
        Vehicle.__init__(self, brand_name) 
        Cost.__init__(self, cost) 

    def get_description(self):
        return self.get_brand_name() + self.model + " is the car " + "and it's cost is " + self.get_cost()
		
c = Car("Audi ",  "r8", "2 cr")
print("Car description:", c.get_description())

Here you will find one difference in the above program than other programs from above. I have used Vehicle.__init__(self, brand_name) in the constructor of Car classe. This is one way of calling attributes from the parent class. Another being super which I have explained above. When we run the above program we will get the following output:

Car description: Audi r8 is the car and it's cost is 2 cr

Though it can be used effectively, multiple inheritance should be done with care so that our programs do not become ambiguous and difficult for other programmers to understand.


Polymorphism:

The word polymorphism means having many forms. In programming, polymorphism means same function name (but different signatures) being uses for different types.

Let’s extend our car program using polymorphism. We will create 2 classes Car e Bike. Both the classes have common method or function but they are printing different data. The program is pretty much self-explanatory.

class Car: 

    def company(self): 
        print("Car belongs to Audi company.")
   
    def model(self): 
        print("The Model is R8.") 
   
    def color(self): 
        print("The color is silver.") 
   
class Bike: 

    def company(self): 
        print("Bike belongs to pulsar company.") 
   
    def model(self): 
        print("The Model is dominar.") 
   
    def color(self): 
        print("The color is black.") 
  
def func(obj): 
    obj.company() 
    obj.model() 
    obj.color() 
   
car = Car() 
bike = Bike() 
   
func(car) 
func(bike)

When we run the above code we will get the following output:

Car belongs to Audi company.
The Model is R8.
The color is silver.
Bike belongs to pulsar company.
The Model is dominar.
The color is black.


Encapsulation:

In most of the object-oriented programming, we can restrict access to methods and variables. This can prevent the data from being modified by accident and is known as encapsulation. This is also available in python.

Let’s integrate encapsulation into our car example. Now consider we have a super-secret engine. In the first example, we will hide our engine using a private variable. In the second example, we will hide our engine using a private method.

Example 1:

class Car:

  def __init__(self): 
    self.brand_name = 'Audi '
    self.model = 'r8'
    self.__engine = '5.2 L V10'
    
  def get_description(self):
        return self.brand_name + self.model + " is the car"
  
c = Car()
print(c.get_description)
print(c.__engine)

In this example self.__engine is a private attribute. When we run this program we will get the following output.

Audi r8 is the car
AttributeError: 'Car' object has no attribute '__engine'

We get an error that Car object doesn't have _engine because it is a private object.

Example 2:

We can also define a private method by adding __ in front of the method name. Following is the example of how we can define a private method.

class Car:

  def __init__(self):
      self.brand_name = 'Audi '
      self.model = 'r8'

  def __engine(self):
      return '5.2 L V10'

  def get_description(self):
      return self.brand_name + self.model + " is the car"
    
    
c = Car()
print(c.get_description())
print(c.__engine()) 

In this example def __engine(self) is a private method. When we run this program we will get the following output.

Audi r8 is the car
AttributeError: 'Car' object has no attribute '__engine'

Now suppose we want to access the private attribute or method we can do it in the following way:

class Car:

  def __init__(self):
      self.brand_name = 'Audi '
      self.model = 'r8'
      self.__engine_name = '5.2 L V10'

  def __engine(self):
      return '5.2 L V10'

  def get_description(self):
      return self.brand_name + self.model + " is the car"
    
    
c = Car()
print(c.get_description())
print("Accessing Private Method: ", c._Car__engine()) 
print("Accessing Private variable: ", c._Car__engine_name)

The output of following program is:

Audi r8 is the car
Accessing Private Method:  5.2 L V10
Accessing Private variable:  5.2 L V10

Encapsulation gives you more control over the degree of coupling in your code, it allows a class to change its implementation without affecting other parts of the code.


Decorator:

Imagine you have to extend the functionality of multiple functions. How will you do that? Well, one way is you can make functional calls and in that function, you can handle it. Making changes in 30 to 40 function calls and remembering where to place the call is a messy task. But there is a more elegant way provided by python and that is Decorator.

What is a decorator? A decorator is a function that takes a function and extends its functionality without modifying explicitly. Well, I understand if you are still confused about what decorators are. Don't worry we have a tool named example to explain it.

Let's try an example to understand the decorator. There are 2 ways to write a decorator.

Way 1: We declare a decorator function and in the arguments of the function we expect the function to be passed as an argument. Inside that, we write a wrapper function where operations are carried out and it is returned.

>>> def my_decorator(func):
...     def wrapper():
...             print("Line Number 1")
...             func()
...             print("Line Number 3")
...     return wrapper
...
>>> def say_hello():
...     print("Hello I am line Number 2")
...

To call the function we assign the decorator with say_hello as an argument.

>>> say_hello = my_decorator(say_hello)

We can also check the reference using say_hello. We will get the output that informs us it has been wrapped by the my_decorator function.

.wrapper at 0x10dc84598>

Let's call our say_hello function:

>>> say_hello()
Line Number 1
Hello I am line Number 2
Line Number 3

See the magic the line "Hello I am line Number 2" gets printed in between Line Number 1 and 3 because the function call get's executed there.

The way no 1 is clunky and because of that many people prefer way no 2. Let's understand it.

Way No 2: Here our decorator declaration remains same but we change how the call is assign to that decorator. Whichever function require that decorator wraps it self with @decorator_name.

>>> def my_decorator(func):
...     def wrapper():
...             print("Line Number 1")
...             func()
...             print("Line Number 3")
...     return wrapper
...
>>> @my_decorator
... def say_hello():
...     print("Hello I am line Number 2")
...
>>> say_hello()

Output is the same:

Line Number 1
Hello I am line Number 2
Line Number 3

A decorator is a powerful tool and it is used in the following development scenario of an application:

  • Setup logger
  • Setup configuration
  • Setup Error catching
  • Extending common functionality for all function and classes


Exceptions:

When we were learning various syntax we came around various errors. Those were the error because of the syntax. But in a real-world application, errors or commonly known as a bug not only occur due to the syntax issue but also because of network error or some other cause.

To handle these issues we use Try - Except. No try block, we write the expression that we want to be executed while in except block we catch the error. Try-Except block looks as follows:

try:
	expression
except:
	catch error

Let's understand this by an example:

>>> try:
...     print(value)
... except:
...     print("Something went wrong")
...

Here we are trying to print value variable but it is not defined. So we get the following output:

Something went wrong

You may be wondering the line "something went wrong" is not that helpful. So how can I know what went wrong here?

We can the exception and use it to find out what went wrong. Let's test this in our example:

>>> try:
...     print(value)
... except Exception as e:
...     print(e)
...

And the result is:

name 'value' is not defined

Wooh!! that's magic. It is notifying me that 'value' is not defined.

Python also provides a tool named raise. Suppose you don't want certain condition to occur and if it occurs you want to raise it. In such condition you can use it. Consider the example above:

>>> i = 5
>>> if i < 6:
...     raise Exception("Number below 6 are not allowed")
...

The output we get is as follows:

Traceback (most recent call last):
  File "", line 2, in 
Exception: Number below 6 are not allowed

There are many sub type of Exception and I would recommend you to go through Python Documentation to understand them.


Package Import:

You have learned python and now you are all ready to build awesome applications. But before that wait for my friend. We are still missing some important topics.

Without package import, you will be forced to write everything in one single file. Imagine what a mess it will be.

Create two files named main.py e hello.py. Remember both file needs to be in same directory.

Under hello.py copy paste the following code:

def say_hello():
    print("Hello world")

Under main.py copy paste the following code:

import hello

if __name__ == "__main__":
    hello.say_hello()

No hello.py we have declared a say_hello() function which prints "Hello world". No main.py you'll see a import statement. We are importing the hello module and calling say_hello() function from that module.

Run our program using the following command:

➜ python main.py

Resultado:

Hello world

Now let's understand how to import a module which is in another directory.

Let's create a directory named data and move our hello.py inside that directory.

Vou ao main.py and change the previous import statement.

from data import hello

if __name__ == "__main__":
    hello.say_hello()

There are two ways to import from a directory.

  • Way1: from data import hello
  • Way2: import data.hello

I prefer way1 because of its readability. You can choose any way which you like.

Let's run our application using the following command:

➜ python main.py

And error occurs. Wait why did this happened? We did everything right. Let's see go through the error:

Traceback (most recent call last):
  File "main.py", line 1, in 
    from data import hello
ImportError: No module named data

Well python is telling us that it doesn't know a module named data. To solve this issue create a __init__.py inside data directory. Leave the file blank and run the program again and you'll get the following output:

Hello world

Well python by default does not treat a directory as module. To inform python to treat a directory as module, __init__.py is required.


JSON Handling:

If you worked previously with web development or app development you may be aware that all the API calls take place in JSON format. JSON looks similar to a dictionary in python. Remember JSON is not a dictionary.

To handle the JSON python provides a builtin json package. To use this package we need to import it as follows:

import json

This library provides two methods which help us in handling the JSON. Let's understand them one by one.

JSON loads:

If you have JSON string and want to convert it back to the dictionary you need to use a loads método. Let's understand them by example. Go to the python shell and copy-paste the following code:

>>> import json
>>> json_string = '{ "user_name":"Sharvin", "age":1000}' #JSON String
>>> type(json_string)

>>> data = json.loads(json_string)
>>> type(data)

>>> data
{'user_name': 'Sharvin', 'age': 1000}

JSON dumps:

Now let's convert our data back to the JSON string format using the dumps método.

>>> jsonString = json.dumps(data)
>>> type(jsonString)

>>> jsonString
'{"user_name": "Sharvin", "age": 1000}'

To know more about JSON Manipulation go through the Python's Documentation.


And we're done! I hope you have completely understood python from basics and a very big congratulations to you on this achievement.

Feedbacks are welcomed. Also if you want to learn about any topic you can tweet the topic name on twitter and include my twitter handle.[[[[@sharvinshah26 ]

Feel free to connect with me on Twitter e Github.