検索
ホームページバックエンド開発Python チュートリアル開発中によく遭遇する Python の落とし穴と注意事項

最近、Python を使用しているときに、変数オブジェクト datetime.datetime.now() を関数のデフォルト パラメーターとして使用したり、モジュールの循環依存関係など、いくつかの落とし穴に遭遇しました。

今後の問い合わせや追加のためにここに記録してください。

可変オブジェクトをデフォルトパラメータとして使用しないようにします

関数を使用するプロセスでは、デフォルトパラメータが関係することがよくあります。 Python では、可変オブジェクトをデフォルトのパラメーターとして使用すると、予期しない結果が発生する可能性があります。

以下の例を見てみましょう:

def append_item(a = 1, b = []):
    b.append(a)
    print b
     
append_item(a=1)
append_item(a=3)
append_item(a=5)


結果は次のようになります:

[1]

[1, 3]

[1, 3, 5]


append_item 関数が次の 2 回呼び出されるとき、関数パラメーター b は [] に初期化されず、前の関数呼び出しの値が保持されます。

この結果が得られる理由は、Python では関数パラメーターのデフォルト値が関数の定義時に 1 回だけ初期化されるためです。

Python のこの機能を証明する例を見てみましょう:


class Test(object):  
    def __init__(self):  
        print("Init Test")  
           
def arg_init(a, b = Test()):  
    print(a)  
arg_init(1)  
arg_init(3)  
arg_init(5)


結果は次のようになります:

Init Test

1

3

5


この例からできることは、 Test クラスは 1 回だけインスタンス化されることに注意してください。つまり、デフォルトのパラメーターは関数呼び出しの回数とは関係がなく、関数の定義時に 1 回だけ初期化されることになります。

変数のデフォルト パラメーターの正しい使用方法

変数のデフォルト パラメーターについては、次のパターンを使用して上記の予期しない結果を回避できます:

def append_item(a = 1, b = None):
    if b is None:
        b = []
    b.append(a)
    print b
     
append_item(a=1)
append_item(a=3)
append_item(a=5)


結果は次のようになります:

[1]

[3 ]

[5]


Python のスコープ

Python のスコープ解決順序は、ローカル、エンクロージング、グローバル、組み込みです。これは、Python インタープリターがこの順序に従って変数を解析することを意味します。

簡単な例を見てください:

global_var = 0
def outer_func():
    outer_var = 1
     
    def inner_func():
        inner_var = 2
         
        print "global_var is :", global_var
        print "outer_var is :", outer_var
        print "inner_var is :", inner_var
         
    inner_func()
     
outer_func()


結果は次のようになります:


global_var is : 0

outer_var is : 1

inner_var is : 2


Python についてスコープに関して注意すべき点の 1 つは、スコープ内の変数に値を割り当てるとき、Python はその変数を現在のスコープのローカル変数と見なすことです。


これも比較的理解しやすいです。次のコードでは、var_func が num 変数に値を代入するため、ここでの num は var_func スコープ内のローカル変数です。


num = 0
def var_func():
    num = 1
    print "num is :", num
     
var_func()


質問1

しかし、次の方法で変数を使用すると、問題が発生します:


num = 0
def var_func():
    print "num is :", num
    num = 1
     
var_func()

結果は次のとおりです:


UnboundLocalError: local variable 'num' referenced before assignment


このエラーが発生する理由は、var_func の num 変数に値を割り当てたため、Python インタプリタは num が var_func スコープ内のローカル変数であると認識しますが、コードが実行されて「num は」と表示されるためです。 : "、num ステートメントを実行するとき、num はまだ未定義です。


質問 2

上記のエラーは比較的明白ですが、次のようなより微妙なエラー形式もあります:

   
li = [1, 2, 3]
def foo():
    li.append(4)
    print li
foo()
def bar():
    li +=[5]
    print li
bar()


コードの結果は次のとおりです:



[ 1, 2, 3, 4]

UnboundLocalError: local variable 'li' referenced before assignment


foo 関数では、Python のスコープ解決順序に従って、この関数ではグローバル li 変数が使用されますが、bar 関数では li 変数が使用されます。は代入なので、li は bar のスコープ内の変数として扱われます。


bar 関数のこの問題では、グローバル キーワードを使用できます。

li = [1, 2, 3]
def foo():
    li.append(4)
    print li
     
foo()
def bar():
    global li
    li +=[5]
    print li
     
bar()


クラス属性の非表示

Pythonにはクラス属性とインスタンス属性があります。クラス属性はクラス自体に属し、すべてのクラス インスタンスによって共有されます。

クラス属性は、クラス名またはクラス インスタンスを通じてアクセスおよび変更できます。ただし、インスタンスがクラスと同じ名前の属性を定義している場合、クラス属性は非表示になります。

次の例を見てください:

class Student(object):
    books = ["Python", "JavaScript", "CSS"]
    def __init__(self, name, age):
        self.name = name
        self.age = age
    pass
     
wilber = Student("Wilber", 27)
print "%s is %d years old" %(wilber.name, wilber.age)
print Student.books
print wilber.books
wilber.books = ["HTML", "AngularJS"]
print Student.books
print wilber.books
del wilber.books
print Student.books
print wilber.books

コードの結果は次のとおりです。最初は、wilber インスタンスはクラスの Books 属性に直接アクセスできますが、wilber インスタンスが Books という名前のインスタンス属性を定義すると、 、 wilber インスタンスの Books 属性 " クラスの Books 属性は非表示になります。wilber インスタンスの Books 属性が削除された後、wilber.books は再びクラスの Books 属性に対応します。

Wilber is 27 years old
['Python', 'JavaScript', 'CSS']
['Python', 'JavaScript', 'CSS']
['Python', 'JavaScript', 'CSS']
['HTML', 'AngularJS']
['Python', 'JavaScript', 'CSS']
['Python', 'JavaScript', 'CSS']


Python 値で継承を使用する場合は、クラス属性の非表示にも注意する必要があります。クラスの場合、クラスの __dict__ 属性を通じてすべてのクラス属性を表示できます。

クラス名を通じてクラス属性にアクセスすると、まずクラスの __dict__ 属性が検索され、クラス属性が見つからない場合は、親クラスの検索が続けられます。ただし、サブクラスが親クラスと同じ名前のクラス属性を定義している場合、サブクラスのクラス属性は親クラスのクラス属性を隠します。

例を見てください:

class A(object):
    count = 1
     
class B(A):
    pass    
     
class C(A):
    pass        
     
print A.count, B.count, C.count      
B.count = 2
print A.count, B.count, C.count      
A.count = 3
print A.count, B.count, C.count     
print B.__dict__
print C.__dict__

結果は次のようになります。クラスBがクラス属性countを定義すると、親クラスのcount属性は非表示になります

1 1 1
1 2 1
3 2 3
{'count': 2, '__module__': '__main__', '__doc__': None}
{'__module__': '__main__', '__doc__': None}


タプルは「変数」です

在Python中,tuple是不可变对象,但是这里的不可变指的是tuple这个容器总的元素不可变(确切的说是元素的id),但是元素的值是可以改变的。

tpl = (1, 2, 3, [4, 5, 6])
print id(tpl)
print id(tpl[3])
tpl[3].extend([7, 8])
print tpl
print id(tpl)
print id(tpl[3])

代码结果如下,对于tpl对象,它的每个元素都是不可变的,但是tpl[3]是一个list对象。也就是说,对于这个tpl对象,id(tpl[3])是不可变的,但是tpl[3]确是可变的。

36764576
38639896
(1, 2, 3, [4, 5, 6, 7, 8])
36764576
38639896

Python的深浅拷贝

在对Python对象进行赋值的操作中,一定要注意对象的深浅拷贝,一不小心就可能踩坑了。

当使用下面的操作的时候,会产生浅拷贝的效果:

使用切片[:]操作

使用工厂函数(如list/dir/set)

使用copy模块中的copy()函数

使用copy模块里面的浅拷贝函数copy():

import copy
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.copy(will)
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]


使用copy模块里面的深拷贝函数deepcopy():

import copy
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.deepcopy(will)
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]


模块循环依赖

在Python中使用import导入模块的时候,有的时候会产生模块循环依赖,例如下面的例子,module_x模块和module_y模块相互依赖,运行module_y.py的时候就会产生错误。  

# module_x.py
import module_y
     
def inc_count():
    module_y.count += 1
    print module_y.count
     
     
# module_y.py
import module_x
count = 10
def run():
    module_x.inc_count()
     
run()

其实,在编码的过程中就应当避免循环依赖的情况,或者代码重构的过程中消除循环依赖。

当然,上面的问题也是可以解决的,常用的解决办法就是把引用关系搞清楚,让某个模块在真正需要的时候再导入(一般放到函数里面)。

对于上面的例子,就可以把module_x.py修改为如下形式,在函数内部导入module_y:

# module_x.py
def inc_count():
    import module_y
    module_y.count += 1
声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Python vs. C:曲線と使いやすさの学習Python vs. C:曲線と使いやすさの学習Apr 19, 2025 am 12:20 AM

Pythonは学習と使用が簡単ですが、Cはより強力ですが複雑です。 1。Python構文は簡潔で初心者に適しています。動的なタイピングと自動メモリ管理により、使いやすくなりますが、ランタイムエラーを引き起こす可能性があります。 2.Cは、高性能アプリケーションに適した低レベルの制御と高度な機能を提供しますが、学習しきい値が高く、手動メモリとタイプの安全管理が必要です。

Python vs. C:メモリ管理とコントロールPython vs. C:メモリ管理とコントロールApr 19, 2025 am 12:17 AM

PythonとCは、メモリ管理と制御に大きな違いがあります。 1。Pythonは、参照カウントとガベージコレクションに基づいて自動メモリ管理を使用し、プログラマーの作業を簡素化します。 2.Cには、メモリの手動管理が必要であり、より多くの制御を提供しますが、複雑さとエラーのリスクが増加します。どの言語を選択するかは、プロジェクトの要件とチームテクノロジースタックに基づいている必要があります。

科学コンピューティングのためのPython:詳細な外観科学コンピューティングのためのPython:詳細な外観Apr 19, 2025 am 12:15 AM

科学コンピューティングにおけるPythonのアプリケーションには、データ分析、機械学習、数値シミュレーション、視覚化が含まれます。 1.numpyは、効率的な多次元配列と数学的関数を提供します。 2。ScipyはNumpy機能を拡張し、最適化と線形代数ツールを提供します。 3. Pandasは、データ処理と分析に使用されます。 4.matplotlibは、さまざまなグラフと視覚的な結果を生成するために使用されます。

PythonとC:適切なツールを見つけるPythonとC:適切なツールを見つけるApr 19, 2025 am 12:04 AM

PythonまたはCを選択するかどうかは、プロジェクトの要件に依存するかどうかは次のとおりです。1)Pythonは、簡潔な構文とリッチライブラリのため、迅速な発展、データサイエンス、スクリプトに適しています。 2)Cは、コンピレーションと手動メモリ管理のため、システムプログラミングやゲーム開発など、高性能および基礎となる制御を必要とするシナリオに適しています。

データサイエンスと機械学習のためのPythonデータサイエンスと機械学習のためのPythonApr 19, 2025 am 12:02 AM

Pythonは、データサイエンスと機械学習で広く使用されており、主にそのシンプルさと強力なライブラリエコシステムに依存しています。 1)Pandasはデータ処理と分析に使用され、2)Numpyが効率的な数値計算を提供し、3)SCIKIT-LEARNは機械学習モデルの構築と最適化に使用されます。これらのライブラリは、Pythonをデータサイエンスと機械学習に理想的なツールにします。

Pythonの学習:2時間の毎日の研究で十分ですか?Pythonの学習:2時間の毎日の研究で十分ですか?Apr 18, 2025 am 12:22 AM

Pythonを1日2時間学ぶだけで十分ですか?それはあなたの目標と学習方法に依存します。 1)明確な学習計画を策定し、2)適切な学習リソースと方法を選択します。3)実践的な実践とレビューとレビューと統合を練習および統合し、統合すると、この期間中にPythonの基本的な知識と高度な機能を徐々に習得できます。

Web開発用のPython:主要なアプリケーションWeb開発用のPython:主要なアプリケーションApr 18, 2025 am 12:20 AM

Web開発におけるPythonの主要なアプリケーションには、DjangoおよびFlaskフレームワークの使用、API開発、データ分析と視覚化、機械学習とAI、およびパフォーマンスの最適化が含まれます。 1。DjangoandFlask Framework:Djangoは、複雑な用途の迅速な発展に適しており、Flaskは小規模または高度にカスタマイズされたプロジェクトに適しています。 2。API開発:フラスコまたはdjangorestFrameworkを使用して、Restfulapiを構築します。 3。データ分析と視覚化:Pythonを使用してデータを処理し、Webインターフェイスを介して表示します。 4。機械学習とAI:Pythonは、インテリジェントWebアプリケーションを構築するために使用されます。 5。パフォーマンスの最適化:非同期プログラミング、キャッシュ、コードを通じて最適化

Python vs. C:パフォーマンスと効率の探索Python vs. C:パフォーマンスと効率の探索Apr 18, 2025 am 12:20 AM

Pythonは開発効率でCよりも優れていますが、Cは実行パフォーマンスが高くなっています。 1。Pythonの簡潔な構文とリッチライブラリは、開発効率を向上させます。 2.Cのコンピレーションタイプの特性とハードウェア制御により、実行パフォーマンスが向上します。選択を行うときは、プロジェクトのニーズに基づいて開発速度と実行効率を比較検討する必要があります。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境