Capítulo 6: Usando Funções e Módulos
Consulte os artigos anteriores:
Capítulo 1: Python inicial
Capítulo 2: Elementos da linguagem
Capítulo 3: Estrutura de ramificação
Capítulo 4: Estrutura de loop
Capítulo 5: Construindo a lógica do programa
Ou vá para a coluna "Tutorial Python" para visualizar
Diretório de recursos: Código (6)
Download de recursos do artigo: (1-15 capítulos)
Link: https://pan.baidu.com/s/1Mh1knjT4Wwt__7A9eqHmng?pwd=t2j3
Código de extração: t2j3
Antes de explicar o conteúdo deste capítulo, vamos primeiro estudar um problema matemático. Por favor, diga quantos conjuntos de soluções inteiras positivas a seguinte equação tem.
Na verdade, o problema acima é equivalente a quantas maneiras existem de dividir 8 maçãs em quatro grupos com pelo menos uma maçã em cada grupo. A resposta a esta pergunta é iminente.
Este valor pode ser calculado com um programa Python, o código é o seguinte.
"""
输入M和N计算C(M,N)
Version: 0.1
Author: 骆昊
"""
m = int(input('m = '))
n = int(input('n = '))
fm = 1
for num in range(1, m + 1):
fm *= num
fn = 1
for num in range(1, n + 1):
fn *= num
fm_n = 1
for num in range(1, m - n + 1):
fm_n *= num
print(fm // fn // fm_n)
O que a função faz
Não sei se você percebeu que no código acima, fizemos 3 vezes para achar o fatorial, tal código na verdade é um código repetido. O mestre de programação Sr. Martin Fowler disse uma vez: " O código tem muitos cheiros ruins, e a repetição é o pior! " Para escrever código de alta qualidade, a primeira coisa a resolver é o problema do código repetido. Para o código acima, podemos encapsular a função de cálculo fatorial em um módulo de função chamado "função". Onde precisamos calcular fatorial, precisamos apenas "chamar" essa "função".
definir função
Em Python, def
palavras-chave podem ser usadas para definir funções.Assim como as variáveis, cada função também tem um nome famoso e as regras de nomenclatura são consistentes com as regras de nomenclatura das variáveis. Os parâmetros passados para a função podem ser colocados entre parênteses após o nome da função, que é muito semelhante à função em matemática. Os parâmetros da função no programa são equivalentes aos argumentos da função em matemática, e após a função é executado, podemos retornar um valor através return
da palavra-chave, que é equivalente à variável dependente da função em matemática.
Depois de entender como definir funções, podemos refatorar o código acima. A chamada refatoração é ajustar a estrutura do código sem afetar os resultados da execução do código. O código refatorado é o seguinte.
"""
输入M和N计算C(M,N)
Version: 0.1
Author: 骆昊
"""
def fac(num):
"""求阶乘"""
result = 1
for n in range(1, num + 1):
result *= n
return result
m = int(input('m = '))
n = int(input('n = '))
# 当需要计算阶乘的时候不用再写循环求阶乘而是直接调用已经定义好的函数
print(fac(m) // fac(n) // fac(m - n))
Explicação:
math
Na verdade, já existe uma função chamada function no módulo Pythonfactorial
que implementa a operação fatorial. Na verdade, você não precisa definir a função para calcular o fatorial. No exemplo a seguir, as funções das quais estamos falando já foram implementadas na biblioteca padrão do Python. Vamos implementá-las novamente aqui para explicar a definição e o uso das funções. No desenvolvimento real, não é recomendável fazer essas repetições de baixo nível trabalho .
parâmetros de função
Uma função é um "bloco de construção" de código suportado pela maioria das linguagens de programação, mas ainda existem muitas diferenças entre funções em Python e funções em outras linguagens. No Python, os parâmetros das funções podem ter valores padrão, e também suportam o uso de parâmetros variáveis, então o Python não precisa suportar sobrecarga de função como outras linguagens , pois quando definimos uma função, podemos fazer com que ela tenha muitos métodos diferentes uso, a seguir estão dois pequenos exemplos.
from random import randint
def roll_dice(n=2):
"""摇色子"""
total = 0
for _ in range(n):
total += randint(1, 6)
return total
def add(a=0, b=0, c=0):
"""三个数相加"""
return a + b + c
# 如果没有指定参数那么使用默认值摇两颗色子
print(roll_dice())
# 摇三颗色子
print(roll_dice(3))
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
# 传递参数时可以不按照设定的顺序进行传递
print(add(c=50, a=100, b=200))
Definimos valores padrão para os parâmetros das duas funções acima, o que significa que, se o valor do parâmetro correspondente não for passado ao chamar a função, o valor padrão do parâmetro será usado, portanto, no código acima As funções podem ser chamadas de várias maneiras add
, o que é consistente com o efeito de sobrecarga de funções em muitas outras linguagens.
Na verdade, há uma implementação melhor da add
função acima, porque podemos adicionar 0 ou mais parâmetros, e o número específico de parâmetros é determinado pelo chamador. Como projetista da função, não sabemos nada, portanto, quando o número de parâmetros é incerto, podemos usar parâmetros variáveis, o código é o seguinte.
# 在参数名前面的*表示args是一个可变参数
def add(*args):
total = 0
for val in args:
total += val
return total
# 在调用add函数时可以传入0个或多个参数
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
print(add(1, 3, 5, 7, 9))
Gerenciar funções com módulos
Para qualquer linguagem de programação, nomear identificadores como variáveis e funções é uma dor de cabeça, porque encontraremos a situação embaraçosa de conflitos de nomes. O cenário mais simples é definir duas funções com o mesmo nome no mesmo arquivo .py. Como o Python não possui o conceito de sobrecarga de função, a última definição substituirá a definição anterior, o que significa que duas funções com o mesmo nome são, na verdade, apenas Um existe.
def foo():
print('hello, world!')
def foo():
print('goodbye, world!')
# 下面的代码会输出什么呢?
foo()
Claro, podemos facilmente evitar a situação acima, mas se o projeto for desenvolvido por uma equipe de várias pessoas, pode haver vários programadores na equipe que definiram a função nomeada, então como resolver esse conflito de nomenclatura Tecido de lã foo
? A resposta é realmente muito simples. Cada arquivo em Python representa um módulo. Podemos ter funções com o mesmo nome em diferentes módulos. Ao usar uma função, podemos importar o módulo especificado por palavra-chave para distinguir entre os módulos a serem usados. import
Qual module é foo
a função in, o código é o seguinte.
module1.py
def foo():
print('hello, world!')
module2.py
def foo():
print('goodbye, world!')
test.py
from module1 import foo
# 输出hello, world!
foo()
from module2 import foo
# 输出goodbye, world!
foo()
Você também pode distinguir qual foo
função usar conforme mostrado abaixo.
test.py
import module1 as m1
import module2 as m2
m1.foo()
m2.foo()
Mas se o código for escrito da seguinte maneira, o último importado será chamado no programa foo
, porque o foo importado posteriormente substituirá o importado anterior foo
.
test.py
from module1 import foo
from module2 import foo
# 输出goodbye, world!
foo()
test.py
from module2 import foo
from module1 import foo
# 输出hello, world!
foo()
Deve-se observar que se o módulo que importamos tiver código executável além de definir funções, o interpretador Python executará esses códigos ao importar este módulo. Na verdade, podemos não querer isso, portanto, se estivermos no módulo A execução código é escrito em , é melhor colocar esses códigos de execução nas condições mostradas abaixo, de modo que, a menos que o módulo seja executado diretamente, o código sob a condição if não será executado, porque apenas o nome do módulo executado diretamente é "__principal__".
module3.py
def foo():
pass
def bar():
pass
# __name__是Python中一个隐含的变量它代表了模块的名字
# 只有被Python解释器直接执行的模块的名字才是__main__
if __name__ == '__main__':
print('call foo()')
foo()
print('call bar()')
bar()
test.py
import module3
# 导入module3时 不会执行模块中if条件成立时的代码 因为模块的名字是module3而不是__main__
prática
Exercício 1: Realize a função de cálculo do máximo divisor comum e mínimo múltiplo comum.
Resposta de referência:
def gcd(x, y):
"""求最大公约数"""
(x, y) = (y, x) if x > y else (x, y)
for factor in range(x, 0, -1):
if x % factor == 0 and y % factor == 0:
return factor
def lcm(x, y):
"""求最小公倍数"""
return x * y // gcd(x, y)
Exercício 2: Realizar a função de julgar se um número é um palíndromo.
Resposta de referência:
def is_palindrome(num):
"""判断一个数是不是回文数"""
temp = num
total = 0
while temp > 0:
total = total * 10 + temp % 10
temp //= 10
return total == num
Exercício 3: Implemente uma função para julgar se um número é primo ou não.
Resposta de referência:
def is_prime(num):
"""判断一个数是不是素数"""
for factor in range(2, int(num ** 0.5) + 1):
if num % factor == 0:
return False
return True if num != 1 else False
Exercício 4: Escreva um programa para julgar se o inteiro positivo de entrada é um número primo palíndromo.
Resposta de referência:
if __name__ == '__main__':
num = int(input('请输入正整数: '))
if is_palindrome(num) and is_prime(num):
print('%d是回文素数' % num)
Observação : como pode ser visto no programa acima, quando extraímos funções recorrentes e relativamente independentes no código para funções , podemos usar essas funções em combinação para resolver problemas mais complexos, e é por isso que definimos e usamos função para uma função muito importante razão.
escopo variável
Finalmente, vamos discutir o escopo das variáveis em Python.
def foo():
b = 'hello'
# Python中可以在函数内部再定义函数
def bar():
c = True
print(a)
print(b)
print(c)
bar()
# print(c) # NameError: name 'c' is not defined
if __name__ == '__main__':
a = 100
# print(b) # NameError: name 'b' is not defined
foo()
O código acima pode ser executado sem problemas e imprimir 100, hello e True, mas notamos que não há duas variáveis bar
definidas dentro da função , então de onde vem a soma. Definimos uma variável no branch do código acima , que é uma variável global (variável global) e pertence ao escopo global porque não é definida em nenhuma função. Na função acima, definimos uma variável , que é uma variável local (local variables) definida na função, que pertence ao escopo local e não pode ser acessada fora da função; mas para a função dentro da função , a variável pertence ao escopo aninhado e podemos acessá-lo na função. Variáveis em funções pertencem ao escopo local e não podem ser acessadas fora da função. Na verdade, quando o Python procura por uma variável, ele buscará na ordem de "escopo local", "escopo aninhado", "escopo global" e "escopo interno". Os três primeiros vimos no código acima Chegaram , o chamado "escopo embutido" são os identificadores embutidos do Python, usamos antes , ,, etc. pertencem ao escopo embutido.a
b
a
b
if
a
foo
b
foo
foo
bar
b
bar
bar
c
bar
input
print
int
Observe o código a seguir novamente, esperamos modificar a
o valor da variável global por meio de uma chamada de função, mas na verdade o código a seguir não pode ser feito.
def foo():
a = 200
print(a) # 200
if __name__ == '__main__':
a = 100
foo()
print(a) # 100
Após chamar foo
a função, a
o valor que encontramos ainda é 100. Isso porque quando escrevemos foo
na função a = 200
, redefinimos uma variável local chamada , que não é a mesma variável a
do escopo global , portanto, a função não pesquisa mais o escopo global . Se quisermos modificar o escopo global na função , o código é o seguinte.a
a
foo
a
foo
a
def foo():
global a
a = 200
print(a) # 200
if __name__ == '__main__':
a = 100
foo()
print(a) # 200
Podemos usar global
palavras-chave para indicar que foo
as variáveis na função a
vêm do escopo global.Se não houver escopo global a
, a seguinte linha de código definirá a variável a
e a colocará no escopo global. Da mesma forma, se quisermos que a função dentro da função seja capaz de modificar variáveis no escopo aninhado, podemos usar nonlocal
palavras-chave para indicar que a variável vem do escopo aninhado, tente você mesmo.
No desenvolvimento real, devemos minimizar o uso de variáveis globais, porque o escopo e a influência das variáveis globais são muito amplos e podem ocorrer modificações e usos inesperados. Além disso, as variáveis globais têm uma vida útil mais longa do que as variáveis locais. O ciclo de vida pode fazer com que a memória ocupada pelo objeto não possa ser coletada por muito tempo . De fato, reduzir o uso de variáveis globais também é uma medida importante para diminuir o acoplamento entre os códigos, sendo também uma prática da lei de Dimiter . Reduzir o uso de variáveis globais significa que devemos tentar manter o escopo das variáveis dentro da função, mas se quisermos estender o ciclo de vida de uma variável local para que seu valor ainda possa ser usado após o término da chamada da função que a define , você precisa usar encerramentos neste momento , o que explicaremos no conteúdo de acompanhamento.
Explicação: Muitas pessoas costumam confundir "fechamento" e "função anônima" , mas na verdade não são a mesma coisa. Se você quiser entender esse conceito, pode ler a explicação da Wikipedia ou a discussão de Zhihu sobre esse conceito .
Dito isso, a conclusão é realmente muito simples. A partir de agora, podemos escrever o código Python de acordo com o seguinte formato. Essa pequena melhoria é, na verdade, um grande passo com base em nossa compreensão de funções e escopo.
def main():
# Todo: Add your code here
pass
if __name__ == '__main__':
main()