Pythonスタディノート6:関数とモジュールの使用、および変数スコープの説明

1.機能の使い方

今日、私はLuo Haoのブログ投稿を学び、彼の関連する知識のポイントを要約しました。それがあなたのお役に立てば幸いです。
GitHubの元のリンク

  • 求解:CMN = M!N!(M − N)!、(M = 7、N = 3)C_M ^ N = \ frac {M!} {N!(MN)!}、\ text {(M = 7、N = 3)}CMN=N MN M (M = 7、N = 3)
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
fmn = 1
for num in range(1, m - n + 1):
    fmn *= num
    
print("求得值为 = {}".format(fm/fn/fmn))

m = 7
n = 3
は値= 35.0を見つけます

1.1機能の役割

  • 上記の例では、3つのforループを使用したため、プログラムが何度も繰り返されました。プログラミングマスターのMartin Fowler氏は、「コードには悪臭が多く、繰り返しは最悪です!」と言ったことがあります。
  • これらの同じ機能をカプセル化するためのレターを作成する必要があります

1.2関数を定義する

  • defキーワードを使用して関数を定義します
  • 関数が実行された後、returnキーワードを使用して値を返すことができます。これは、数学における関数の従属変数に相当します。
def factorial(num): # factorial:阶乘
    result = 1
    for n in range(1, num + 1):
        result *= n
    return result

m = int(input("m = "))
n = int(input("n = "))

print(factorial(m)/factorial(n)/factorial(m - n))

# 在Python的math模块中已经有一个factorial函数
# 就不需要自己定义函数了

import math

m = int(input("M = "))# 注意要将str强制转换为int
n = int(input("N = "))

c = math.factorial(m)/ \
    math.factorial(n)/ \
    math.factorial(m - n)
print(c)

m = 7
n = 3
35.0
M = 7
N = 3
35.0

上記の関数を使用して定義すると、プログラムがより簡潔でシンプルになります

1.3機能パラメータ

  • 関数のパラメーターはデフォルト値を持つことができ、変数パラメーターの使用もサポートします
  • パラメータ設定は柔軟で、使い方はたくさんあります
from random import randint

def rollDice(n = 2):
    """摇色子"""
    total = 0
    for i in range(n):
        total += randint(1, 6)
    return total

def add(a=0, b=0, c=0):
    """三个数相加"""
    return a + b + c

# 如果没有指定参数那么使用默认值摇两颗色子
print(rollDice()) # 4

# 摇三颗色子
print(rollDice(3)) # 14
print(add())       # 0
print(add(1))      # 1
print(add(1, 2))   # 3
print(add(1, 2, 3))# 6

# 传递参数时可以不按照设定的顺序进行传递
print(add(c=50, a=100, b=200))   # 350


1.4関数のオーバーロード(同じ関数を使用して異なる関数を完了します)

  • 上記の2つの関数のパラメーターにデフォルト値を設定します。つまり、関数が呼び出されたときに対応するパラメーターの値が渡されない場合、パラメーターのデフォルト値が使用されるため、上記のコードでは__add__関数はさまざまな方法で呼び出すことができます。これは、他の多くの言語での関数のオーバーロードの影響と一致しています。
  • 上記の__add__関数では、パラメーターの数を指定していますが、パラメーターの数が不明な場合は、どうすればよいですか?
    • パラメータの前に*を追加して、パラメータが可変であることを示すことができます
def add(*args):
    total = 0
    for i in args:
        total += i
    return total


# 在调用add函数时可以传入0个或多个参数
print(add())          	# 0
print(add(1))			# 1
print(add(1, 2))		# 3		
print(add(1, 2, 3))		# 6


2.モジュール管理機能を使用する

  • どのプログラミング言語でも、変数や関数などの識別子に名前を付けることは、名前の競合という厄介な状況に遭遇するため、頭痛の種です。最も単純なシナリオは、同じ.pyファイルに同じ名前の2つの関数を定義することです。Pythonには関数のオーバーロードの概念がないため、次の定義は前の定義をオーバーライドします。つまり、同じ名前の2つの関数は実際には1つしか存在しません
  • 単純な理解は、繰り返される関数名は後者によって上書きされるということです
def sayHi():
    print("hello")
    return None
    
def sayHi():
    print('hello,world!')
    return None

sayHi()

こんにちは世界!

2.1上記の問題を解決する方法

  • module1.py、module2.pyなどのモジュールごとにファイルを作成します。
  • すべて、異なるファイル(モジュール)で、同じ名前の関数が許可されます
  • 使用する場合は、__ import__キーワードを使用して指定したモジュールをインポートします
from module1 import sayHi

sayHi()

from module2 import sayHi

sayHi()


# 也可以使用下面的方法来区分使用了哪个 sayHi 函数
import module1 as m1
import module2 as m2

m1.sayHi()
m2.sayHi()
  • コードが次のように記述されている場合、最後にインポートされたsayHiがプログラムで呼び出されます。これは、後でインポートされたsayHiが以前にインポートされたsayHiを上書きするためです。
from module1 import sayHi
from module2 import sayHi

sayHi()# 输出hello

from module2 import sayHi
from module1 import sayHi

sayHi()# 输出hello, world!

注意:
  • インポートするモジュールに関数の定義に加えて実行可能コードがある場合、Pythonインタープリターはこのモジュールをインポートするときにこれらのコードを実行します。実際、これは必要ない場合があるため、モジュールコードで実行を記述する場合は最適です。これらの実行コードを以下の条件に入れて、モジュールを直接実行しない限り、直接実行されるモジュール名のみが「__ main __」であるため、if条件でのこれらのコードは実行されません。
module3.py:
def foo():
    pass


def bar():
    pass


# __name__是Python中一个隐含的变量它代表了: 模块的名字
# 只有被Python解释器直接执行的模块的名字才是: __main__
if __name__ == '__main__':
    print('call foo()')
    foo()
    print('call bar()')
    bar()

foo()を
呼び出すbar()を呼び出す

import module3

# 导入module3时, 不会执行模块中if条件成立时的代码 
# 因为模块的名字是module3而不是__main__

ケース1:最大公約数と最小公倍数を計算する関数を実現します

def gcd(x, y):
    
    # 求最大公约数:两个或多个整数共有约数中最大的一个
    # (x, y) = (y, x) if x > y else (x, y)
    for factor in range(y, 0 , -1):
        if x % factor == 0 and y % factor == 0:
            return factor

        
def lcm(x, y):
    # 求最小公倍数
    return x * y // gcd(x, y)


gcd(200, 45)
lcm(7, 7)

ケース2:数値が回文数であるかどうかを判断する関数を実装する

  • 例:1234321
def isPal(num):
    temp = num
    total = 0
    while temp > 0:
        total = total * 10 + temp % 10
        temp //= 10
    return total == num

isPal(1234321)


ケース3:数が素数であるかどうかを判断する関数を実現する

def isPrime(num):
    # 判断一个数是不是素数
    for factor in range(2, num):
        if num % factor == 0:
            return False
    return True if num != 1 else False
注意:
  • 上記のプログラムから、コード内の反復的で比較的独立した関数を関数に抽出すると、これらの関数を組み合わせて使用​​して、より複雑な問題を解決できることがわかります。これが、関数を定義して使用する理由です。非常に重要な理由です。

3.Pythonの変数スコープに関する問題

  • 変数を探すときの順序:
    • ローカルスコープ:c
    • ネストされたスコープ:b
    • グローバルスコープ:a
    • 一部の組み込み識別子、input、print、intなどの組み込みスコープ。
def foo():
    b = 'hello'  # 局部变量,在foo函数的外部并不能访问到它
                 # 对于foo函数内部的bar函数来说,变量b属于嵌套作用域
                 # 在bar函数中,可以访问到它
    
    # Python中可以在函数内部再定义函数
    def bar():
        
        #nonlocal b
        #b = "nonlocal" # 修改嵌套变量的值
        
        c = True # 局部作用域,在bar函数之外是无法访问
        print(a)
        print(b)
        print(c)

    bar()
    print(b)  
    print(c)     # NameError: name 'c' is not defined

if __name__ == '__main__':
    a = 100      # 全局变量,属于全局作用域
    foo()
    # print(b)   # NameError: name 'b' is not defined

100
hello
True
hello
35.0

# 案例1:
def foo():
    a = 200
    print(a)         # 200


if __name__ == '__main__':
    a = 100
    foo()
    print(a)         # 100
上記の例から、aの最終出力は100のままであることがわかります。これは、Pythonの検索順序に従って、ローカル変数が見つかると、他の変数を検索しなくなるためです。
3.1。グローバル変数でローカル変数の値を使用する場合は、次を使用できます。グローバルキーワード
3.2。関数内の関数でネストされたスコープ内の変数を変更できるようにする場合は、次を使用できます。nonlocalキーワード
# 案例2:
def foo():
    global a
    a = 200
    print(a)  # 200


if __name__ == '__main__':
    a = 100
    foo()
    print(a)  # 200
    

総括する:

  • 実際の開発では、グローバル変数のスコープと影響が広すぎて、予期しない変更や使用が発生する可能性があるため、グローバル変数の使用を最小限に抑える必要があります。さらに、グローバル変数はローカル変数よりも長いライフサイクルがメモリを引き起こす可能性があります長期間ガベージコレクションを行うことができないオブジェクトによって占有されています
  • 実際、グローバル変数の使用を減らすことは、コード間の結合度を減らすための重要な手段でもありDimitの法則の実践でもあります。
  • グローバル変数の使用を減らすということは、内部の関数で変数のスコープを作成する必要があることを意味しますが、ローカル変数のライフサイクル拡張が必要な​​場合は、最終的には関数呼び出しの定義であり、引き続き使用できます。その値、今回はクロージャを使用する必要があります

おすすめ

転載: blog.csdn.net/amyniez/article/details/104415925