Python 記述子の入門

Dec 15, 2016 am 09:13 AM

長い間 Flask のコードについて書いていなかったのですが、思い出すと本当に恥ずかしいです。それでも今回は書きません。受け入れられない場合は、私に叩きに来てください。あなたはとてもビッチです、できるなら噛んでください)

今回はそれをやります Python で非常に重要なこと、つまり Descriptor について書きましょう

最初のディスクリプタの紹介

古いルール、話は安い、見せてください。まずはコードを見てみましょう

classPerson(object):
""""""
  
#----------------------------------------------------------------------
def__init__(self, first_name, last_name):
"""Constructor"""
 self.first_name = first_name
 self.last_name = last_name
  
#----------------------------------------------------------------------
 @property
deffull_name(self):
"""
 Return the full name
 """
return"%s %s"% (self.first_name, self.last_name)
  
if__name__=="__main__":
 person = Person("Mike","Driscoll")
 print(person.full_name)
# 'Mike Driscoll'
 print(person.first_name)
# 'Mike'
ログイン後にコピー
ログイン後にコピー


プロパティについて知らない人はいないでしょう。しかし、プロパティの実装メカニズムについてはご存知ですか? Pythonを勉強してみませんか? ああ。 。 。冗談ですが、次のコードを見てみましょう

classProperty(object):
"Emulate PyProperty_Type() in Objects/descrobject.c"
def__init__(self, fget=None, fset=None, fdel=None, doc=None):
 self.fget = fget
 self.fset = fset
 self.fdel = fdel
ifdocisNoneandfgetisnotNone:
 doc = fget.__doc__
 self.__doc__ = doc
  
def__get__(self, obj, objtype=None):
ifobjisNone:
returnself
ifself.fgetisNone:
raiseAttributeError("unreadable attribute")
returnself.fget(obj)
  
def__set__(self, obj, value):
ifself.fsetisNone:
raiseAttributeError("can't set attribute")
 self.fset(obj, value)
  
def__delete__(self, obj):
ifself.fdelisNone:
raiseAttributeError("can't delete attribute")
 self.fdel(obj)
  
defgetter(self, fget):
returntype(self)(fget, self.fset, self.fdel, self.__doc__)
  
defsetter(self, fset):
returntype(self)(self.fget, fset, self.fdel, self.__doc__)
  
defdeleter(self, fdel):
returntype(self)(self.fget, self.fset, fdel, self.__doc__)
ログイン後にコピー

複雑そうに見えますか? 大丈夫、ステップバイステップで見てみましょう。しかし、ここで最初に結論を示します。記述子は、__get__ を実装する特別な種類のオブジェクトです。 __set__、__delete__ これら 3 つの特別なメソッド。

ディスクリプタの詳しい説明

Propertyについて話しましょう

上記ではPropertyの実装コードを紹介しましたが、ここからは詳しく説明していきます

classPerson(object):
""""""
  
#----------------------------------------------------------------------
def__init__(self, first_name, last_name):
"""Constructor"""
 self.first_name = first_name
 self.last_name = last_name
  
#----------------------------------------------------------------------
 @property
deffull_name(self):
"""
 Return the full name
 """
return"%s %s"% (self.first_name, self.last_name)
  
if__name__=="__main__":
 person = Person("Mike","Driscoll")
 print(person.full_name)
# 'Mike Driscoll'
 print(person.first_name)
# 'Mike'
ログイン後にコピー
ログイン後にコピー

まず、デコレータについて知らない方のためにつまり、コードを正式に実行する前に、インタプリタがコードをスキャンし、デコレータに関係する部分を置き換えます。クラスデコレータについても同様です。上記では、このコード

@Property
deffull_name(self): 
""" 
 Return the full name 
 """
return"%s %s"% (self.first_name, self.last_name)
ログイン後にコピー

がそのようなプロセス、つまり full_name=Property(full_name) をトリガーします。次に、オブジェクトをインスタンス化した後、後で呼び出します person.full_name このようなプロセスは、実際には person.full_name.__get__(person) と同等であり、__get__() をトリガーします。 メソッド内に記述された return self.fget(obj) は、最初に記述した def full_name の実行コードです。

この時点で、同志はgetter()、setter()、deleter()について考えることができます 具体的な動作メカニズム =. =まだ質問がある場合は、コメントでお気軽にご相談ください。

記述子について

前に説明した定義を覚えていますか: 記述子は、 __get__ 、 __set__ 、 __delete__ を実装する特別な種類のオブジェクトです。 この3つの特別な方法です。そして、Python の公式ドキュメントの説明には、記述子の重要性を反映するために、次の段落があります。「記述子の背後にあるメカニズムです。 プロパティ、メソッド、静的メソッド、クラスメソッド、および super() が使用されます。 Python 自体全体で、 で導入された新しいスタイル クラスを実装します。 バージョン 2.2 」 つまり、最初に記述子があり、次に空があり、毎秒空気が存在します。 。新しいスタイルのクラスでは、属性、メソッド呼び出し、静的メソッド、クラス メソッドなどはすべて、記述子の特定の使用法に基づいています。

OK、なぜ記述子がそれほど重要なのかと疑問に思うかもしれません。心配しないで、引き続き

記述子の使用

を見てみましょう

まず、次のコード部分を見てください


classA(object): #注意: Python 3.xバージョンでは、明示的に指定する必要はありません。新しいクラスの使用からのオブジェクトは、クラスを継承します。 Python 2 のバージョンでは何が起こったのでしょうか?

いいですか?もう分かりましたか?いいえ?さて、続けましょう

まず第一に、属性を呼び出すとき、それがメンバーであってもメソッドであっても、そのようなメソッドをトリガーして属性 __getattribute__() を呼び出します。 __getattribute__() メソッドでは、呼び出そうとする属性が記述子プロトコルを実装している場合、そのような呼び出しプロセスが発生します。 type(a).__dict__['a'].__get__(b,type(b)) 。さて、ここで別の結論が得られます。「このような呼び出しプロセスでは、呼び出そうとしている属性がデータ記述子の場合、そのような優先順位が存在します。」 この属性がインスタンスの __dict__ ディクショナリに存在するかどうかに関係なく、呼び出そうとしている属性がデータでない場合は、記述子の __get__ メソッドが最初に呼び出されます。 記述子の場合、インスタンス内の __dict__ 内の既存の属性を優先して呼び出します。それらの属性が存在しない場合は、対応する原則に従ってクラスと親クラス内の __dict__ を検索します。 に含まれる属性の場合、属性が存在する場合は __get__ メソッドが呼び出され、属性が存在しない場合は __getattr__() が呼び出されます。 少し抽象的でわかりにくいですか? 大丈夫、すぐに説明しますが、ここではまずデータ記述子と非データ記述子について説明する必要があります。 、別の例を見てみましょう。データ記述子と非データ記述子とは何ですか?実際、__get__ も記述子に実装されています。 __set__ プロトコルの記述子は、__get__ プロトコルのみが実装されている場合、データ記述子ではありません。 。さて、例を見てみましょう:

defa(self):
pass
if__name__=="__main__":
 a=A()
 a.a()
ログイン後にコピー

好的,让我们仔细来看看这段代码,首先类描述符 @lazyproperty 的替换过程,前面已经说了,我们不在重复。接着,在我们第一次调用 c.area 的时候,我们首先查询实例 c 的 __dict__ 中是否存在着 area 描述符,然后发现在 c 中既不存在描述符,也不存在这样一个属性,接着我们向上查询 Circle 中的 __dict__ ,然后查找到名为 area 的属性,同时这是一个 non data descriptors ,由于我们的实例字典内并不存在 area 属性,那么我们便调用类字典中的 area 的 __get__ 方法,并在 __get__ 方法中通过调用 setattr 方法为实例字典注册属性 area 。紧接着,我们在后续调用 c.area 的时候,我们能在实例字典中找到 area 属性的存在,且类字典中的 area 是一个 non data descriptors ,于是我们不会触发代码里所实现的 __get__ 方法,而是直接从实例的字典中直接获取属性值。

描述符的使用

描述符的使用面很广,不过其主要的目的在于让我们的调用过程变得可控。因此我们在一些需要对我们调用过程实行精细控制的时候,使用描述符,比如我们之前提到的这个例子

classlazyproperty:
def__init__(self, func):
 self.func = func
  
def__get__(self, instance, owner):
ifinstanceisNone:
returnself
else:
 value = self.func(instance)
 setattr(instance, self.func.__name__, value)
returnvalue
  
def__set__(self, instance, value=0):
pass
  
  
importmath
  
  
classCircle:
def__init__(self, radius):
 self.radius = radius
pass
  
 @lazyproperty
defarea(self, value=0):
 print("Com")
ifvalue ==0andself.radius ==0:
raiseTypeError("Something went wring")
  
returnmath.pi * value *2ifvalue !=0elsemath.pi * self.radius *2
  
deftest(self):
pass
ログイン後にコピー

利用描述符的特性实现懒加载,再比如,我们可以控制属性赋值的值

classProperty(object):
"Emulate PyProperty_Type() in Objects/descrobject.c"
def__init__(self, fget=None, fset=None, fdel=None, doc=None):
 self.fget = fget
 self.fset = fset
 self.fdel = fdel
ifdocisNoneandfgetisnotNone:
 doc = fget.__doc__
 self.__doc__ = doc
  
def__get__(self, obj, objtype=None):
ifobjisNone:
returnself
ifself.fgetisNone:
raiseAttributeError("unreadable attribute")
returnself.fget(obj)
  
def__set__(self, obj, value=None):
ifvalueisNone:
raiseTypeError("You can`t to set value as None")
ifself.fsetisNone:
raiseAttributeError("can't set attribute")
 self.fset(obj, value)
  
def__delete__(self, obj):
ifself.fdelisNone:
raiseAttributeError("can't delete attribute")
 self.fdel(obj)
  
defgetter(self, fget):
returntype(self)(fget, self.fset, self.fdel, self.__doc__)
  
defsetter(self, fset):
returntype(self)(self.fget, fset, self.fdel, self.__doc__)
  
defdeleter(self, fdel):
returntype(self)(self.fget, self.fset, fdel, self.__doc__)
  
classtest():
def__init__(self, value):
 self.value = value
  
 @Property
defValue(self):
returnself.value
  
 @Value.setter
deftest(self, x):
 self.value = x
ログイン後にコピー

   

如上面的例子所描述的一样,我们可以判断所传入的值是否有效等等。

以上就是Python 描述符(Descriptor)入门,更多相关文章请关注PHP中文网(www.php.cn)!


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホット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

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

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Pythonを使用してテキストファイルのZIPF配布を見つける方法 Pythonを使用してテキストファイルのZIPF配布を見つける方法 Mar 05, 2025 am 09:58 AM

このチュートリアルでは、Pythonを使用してZIPFの法則の統計的概念を処理する方法を示し、法律の処理時にPythonの読み取りおよび並べ替えの効率性を示します。 ZIPF分布という用語が何を意味するのか疑問に思うかもしれません。この用語を理解するには、まずZIPFの法律を定義する必要があります。心配しないでください、私は指示を簡素化しようとします。 ZIPFの法則 ZIPFの法則は単に意味します。大きな自然言語のコーパスでは、最も頻繁に発生する単語は、2番目の頻繁な単語のほぼ2倍の頻度で表示されます。 例を見てみましょう。アメリカ英語の茶色のコーパスを見ると、最も頻繁な言葉は「thであることに気付くでしょう。

HTMLを解析するために美しいスープを使用するにはどうすればよいですか? HTMLを解析するために美しいスープを使用するにはどうすればよいですか? Mar 10, 2025 pm 06:54 PM

この記事では、Pythonライブラリである美しいスープを使用してHTMLを解析する方法について説明します。 find()、find_all()、select()、およびget_text()などの一般的な方法は、データ抽出、多様なHTML構造とエラーの処理、および代替案(SEL

Pythonでの画像フィルタリング Pythonでの画像フィルタリング Mar 03, 2025 am 09:44 AM

ノイズの多い画像を扱うことは、特に携帯電話や低解像度のカメラの写真でよくある問題です。 このチュートリアルでは、OpenCVを使用してPythonの画像フィルタリング手法を調査して、この問題に取り組みます。 画像フィルタリング:強力なツール 画像フィルター

Pythonでファイルをダウンロードする方法 Pythonでファイルをダウンロードする方法 Mar 01, 2025 am 10:03 AM

Pythonは、インターネットからファイルをダウンロードするさまざまな方法を提供します。これは、urllibパッケージまたはリクエストライブラリを使用してHTTPを介してダウンロードできます。このチュートリアルでは、これらのライブラリを使用してPythonからURLからファイルをダウンロードする方法を説明します。 ライブラリをリクエストします リクエストは、Pythonで最も人気のあるライブラリの1つです。クエリ文字列をURLに手動で追加したり、POSTデータのエンコードをフォームに追加せずに、HTTP/1.1リクエストを送信できます。 リクエストライブラリは、以下を含む多くの機能を実行できます フォームデータを追加します マルチパートファイルを追加します Python応答データにアクセスします リクエストを行います 頭

Pythonを使用してPDFドキュメントの操作方法 Pythonを使用してPDFドキュメントの操作方法 Mar 02, 2025 am 09:54 AM

PDFファイルは、クロスプラットフォームの互換性に人気があり、オペレーティングシステム、読み取りデバイス、ソフトウェア間でコンテンツとレイアウトが一貫しています。ただし、Python Plansing Plain Text Filesとは異なり、PDFファイルは、より複雑な構造を持つバイナリファイルであり、フォント、色、画像などの要素を含んでいます。 幸いなことに、Pythonの外部モジュールでPDFファイルを処理することは難しくありません。この記事では、PYPDF2モジュールを使用して、PDFファイルを開き、ページを印刷し、テキストを抽出する方法を示します。 PDFファイルの作成と編集については、私からの別のチュートリアルを参照してください。 準備 コアは、外部モジュールPYPDF2を使用することにあります。まず、PIPを使用してインストールします。 ピップはpです

DjangoアプリケーションでRedisを使用してキャッシュする方法 DjangoアプリケーションでRedisを使用してキャッシュする方法 Mar 02, 2025 am 10:10 AM

このチュートリアルでは、Redisキャッシングを活用して、特にDjangoフレームワーク内でPythonアプリケーションのパフォーマンスを向上させる方法を示しています。 Redisのインストール、Django構成、およびパフォーマンスの比較をカバーして、Beneを強調します

Natural Language Toolkit(NLTK)の紹介 Natural Language Toolkit(NLTK)の紹介 Mar 01, 2025 am 10:05 AM

自然言語処理(NLP)は、人間の言語の自動または半自動処理です。 NLPは言語学と密接に関連しており、認知科学、心理学、生理学、数学の研究とのリンクがあります。コンピューターサイエンスで

TensorflowまたはPytorchで深い学習を実行する方法は? TensorflowまたはPytorchで深い学習を実行する方法は? Mar 10, 2025 pm 06:52 PM

この記事では、深い学習のためにTensorflowとPytorchを比較しています。 関連する手順、データの準備、モデルの構築、トレーニング、評価、展開について詳しく説明しています。 特に計算グラップに関して、フレームワーク間の重要な違い

See all articles