実は以前にカプセル化の概念に触れたことがありますが、乱雑なデータをリストに投げ込むことは一種のカプセル化であり、データ レベルのカプセル化です。よく使用されるコード セグメントを関数に詰め込むこともカプセル化の一種であり、 はステートメント レベルのカプセル化です。 ; これから学習したいオブジェクトもカプセル化のアイデアです。オブジェクトのソースは次のとおりです。現実世界をシミュレートし、データとコードの両方を一緒にカプセル化します。
たとえば、カメは現実世界のオブジェクトであり、通常は 2 つの部分から説明されます。
(1) からの説明 静的特性: たとえば、緑色、4 本の脚、殻付きなど。これは静的な説明です。 (2)
動的行動の説明: たとえば、這ったり、追いかけると走ったり、時には噛みついたり、眠ったりするなど、すべて行動面から見たものです。説明する。
オブジェクトの特性を「プロパティ」といいます、オブジェクトの動作を「メソッド」といいます。 :
タートルをコードとして記述すると、次のようになります。class Turtle: # Python中的类名约定以大写字母开头
# 特征的描述称为属性,在代码层面看来其实就是变量
color = 'green'
legs = 4
shell = True
# 方法实际就是函数,通过调用这些函数来完成某些工作
def climb(self):
print('向前爬')
def run(self):
print('向前跑')
def bite(self):
print('咬人')
def sleep(self):
print('睡觉')
上記のコードは、タートルの特性 (プロパティ) と動作 (メソッド) を定義します。
ですが、まだ完全なオブジェクトではありません。定義されたオブジェクトは クラス (Class) と呼ばれます。実際のオブジェクトを作成するにはクラスを使用する必要があります。このオブジェクトは、このクラスの インスタンス (インスタンス) と呼ばれ、インスタンス オブジェクト (インスタンス オブジェクト) とも呼ばれます。 たとえば、これは一連のおもちゃを生産する必要がある工場のようなもので、まずおもちゃの金型を作成し、次にその金型に基づいておもちゃを量産する必要があります。
それでは、実際のインスタンス オブジェクトを作成するにはどうすればよいでしょうか?
、 は実際には非常に簡単です: # 首先要有上面那一段类的定义
tt = Turtle()
注:呼び出す場合は、ドット演算子 (.)クラス名は次のとおりです。小さな括弧が続く場合、これは関数を呼び出すことと同じです。したがって、Python では、クラス名 は大文字で始まり、関数は小文字 で始まるため、区別しやすくなります。また、代入操作は必要ありませんが、作成したインスタンスオブジェクトが変数に代入されていない場合、インスタンスへの参照がないためオブジェクトは使用できず、最終的にはガベージコレクションされてしまいます。 Python メカニズムは自動的にリサイクルされます。
オブジェクト内のメソッドを
を使用します。
次に、コードの一部を見て、
、Class について理解を深めましょう。オブジェクトAndインスタンス オブジェクト3 つの概念:
この例からわかるように、
count 属性に値を割り当てた後、インスタンス オブジェクト cの は、クラス オブジェクト C の count 属性 をカバーする と同等です。下図のように、代入網羅がない場合はクラスオブジェクトのcount属性が参照されます。
クラスで定義されている属性は静的変数であることに注意してください。クラスの属性はクラス オブジェクトにバインドされており、それの任意のインスタンス オブジェクトに依存します。
さらに、属性の名前がメソッド名と同じ場合、属性はメソッドをオーバーライドします :
# #名前の競合を避けるために、いくつかの従来のルールに従う必要があります:
(1) クラス内で考えられるすべての機能とメソッドを定義しようとせず、拡張には継承と組み合わせのメカニズムを使用する必要があります。 (2) 属性名には名詞、メソッド名には動詞など、さまざまな品詞を使用して名前を付け、キャメル ケースの名前を使用します。
self とは
これまでプログラミング言語に触れたことがない場合は、簡単に言うと、
クラスを図面と比較した場合、クラスによってインスタンス化された オブジェクトは、実際に使用できる実際の家です。に住んでいました ###。 1 つの図面に基づいて何千もの家を設計でき、それらはすべて同じように見えますが、それぞれの家には異なる所有者がいます。誰もが自分の家を見つけたいと思っていますが、 の場合、self はここの家の番号 に相当します。self を使用すると、自分の家を簡単に見つけることができます。 Python の self パラメータも同じ理由です。クラスから無数のオブジェクトを生成できます。オブジェクト メソッドが呼び出されるとき、オブジェクトは独自の参照を最初のパラメータとしてメソッドに渡します。その後、Python はどのパラメータであるかを認識します。オブジェクトメソッド を操作する必要があります。
簡単な例を挙げてください:
一般面向对象的编程语言都会区分公有和私有的数据类型,像C++和Java它们使用public和private关键字用于声明数据是公有的还是私有的,但在Python中并没有类似的关键字来修饰。
默认上对象的属性和方法都是公开的,可以直接通过点操作符(.)进行访问:
为了实现类似私有变量的特征,Python内部采用了一种叫name mangling(名字改编)的技术,在Python中定义私有变量只需要在变量名或函数名前加上“_ _”两个下划线,那么这个函数或变量就会成为私有的了:
这样,在外部将变量名“隐藏”起来了,理论上如果要访问,就要从内部进行:
但是认真想一下这个技术的名字name mangling(名字改编),那就不难发现其实Python只是把双下横线开头的变量进行了改名而已。实际上,在外部使用“_类名_ _变量名”即可访问双下横线开头的私有变量了:
说明:Python目前的私有机制其实是伪私有的,Python的类是没有权限控制的,所有的变量都是可以被外部调用的。
举个例子来说明继承。例如现在有个游戏,需要对鱼类进行细分,有金鱼(Goldfish)、鲤鱼(Carp)、三文鱼(Salmon)以及鲨鱼(Shark)。那么我们能不能不要每次都从头到尾去重新定义一个新的鱼类呢?因为我们知道大多数鱼的属性和方法是相似的,如果有一种机制可以让这些相似的东西得以自动传递,那么就方便多了。这就是继承。
继承的语法很简单:
c l a s s 类 名 ( 被 继 承 的 类 ) : . . . class 类名(被继承的类): \\ \quad ... class类名(被继承的类):...
被继承的类称为基类、父类或超类;继承者称为子类,一个子类可以继承它的父类的任何属性和方法。
举个例子:
需要注意的是,如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性:
接下来,尝试写一下开头提到的金鱼(Goldfish)、鲤鱼(Carp)、三文鱼(Salmon)以及鲨鱼(Shark)的例子。
import random as r class Fish: def __init__(self): self.x = r.randint(0, 10) self.y = r.randint(0, 10) def move(self): # 这里主要演示类的继承机制,就不考虑检查场景边界和移动方向问题 # 假设所有的鱼都是一路向西游 self.x -= 1 print("我的位置是:", self.x, self.y) # 金鱼 class Goldfish(Fish): pass # 鲤鱼 class Carp(Fish): pass #三文鱼 class Salmon(Fish): pass # 上面三种鱼都是食物,直接继承Fish类的全部属性和方法 # 下面定义鲨鱼类,除了继承Fish类的属性和方法,还要添加一个吃的方法 class Shark(Fish): def __init__(self): self.hungry = True def eat(self): if self.hungry: print("吃掉你!") self.hungry = False else: print("太饱了,吃不下了~")
首先运行这段代码,然后进行测试:
同样是继承于Fish类,为什么金鱼(goldfish)可以移动,而鲨鱼(shark)一移动就报错呢?
可以看到报错提示为:Shark对象没有x属性,这是因为在Shark类中,重写了_ _init_ _()方法,但新的_ _init_ _()方法里面没有初始化鲨鱼的x坐标和y坐标,因此调用move()方法就会出错。
那么解决这个问题,只要在鲨鱼类中重写_ _init_ _()方法的时候先调用基类Fish的_ _init_ _()方法。
下面介绍两种可以实现的技术:
(1)调用未绑定的父类方法
(2)使用super函数
什么是调用未绑定的父类方法?举个例子:
修改之后,再运行下发现鲨鱼也可以成功移动了:
这里需要注意的是,这个self并不是父类Fish的实例对象,而是子类Shark的实例对象。所以这里说的未绑定是指并不需要绑定父类的实例对象,使用子类的实例对象代替即可。
スーパー関数は、基本クラスのメソッドを自動的に見つけるのに役立ちますまた、self パラメータを渡すこともできます必要はありません。次のことを実行してください:
#実行後も同じ結果が得られます:
さらに、Python は 多重継承 もサポートしています。つまり、 複数の親クラスのプロパティとメソッドを同時に継承できます:
c l a s s クラス名 (親クラス 1、親クラス 2、親クラス 3、...): . . . クラス クラス名 (親クラス 1、親クラス 2、親クラス 3、...) ):\\ \quad ... クラス クラス名 (親クラス 1、親クラス 2、親クラス 3、...):...
例:
これは基本的な多重継承構文ですが、多重継承はコードの混乱を招きやすいため、本当に多重継承を使用する必要があるかどうかわからない場合は、次のことを行ってください。予期せぬバグが発生する可能性があるため、使用は避けてください。
以前に継承の概念を学習し、多重継承について説明しましたが、カメと魚がいる場合は、プールと呼ばれるクラスを定義する必要があります。プールには必ずカメと魚がいます。プール、カメ、魚は異なる種であるため、多重継承を使用するのは奇妙に思えます。では、これらをプール クラスに結合するにはどうすればよいでしょうか?
実際、Python では非常に簡単です。必要なクラスをそれに入れてインスタンス化するだけです。これは combination:
と呼ばれます。
最初に上記のコードを実行してからテストします。
Python オブジェクトには多くの機能があります。 magics メソッドの場合、オブジェクトがこれらのメソッドのいずれかを実装している場合、このメソッドは特別な状況下で Python によって呼び出され、このすべてが 自動的に行われます。
_ _init_ _() メソッドは、通常、構築メソッドと呼ばれます。オブジェクトがインスタンス化されている限り、このメソッドは、オブジェクトの作成時に自動的に呼び出されます。オブジェクトをインスタンス化するときにパラメータを渡すことができます。これらのパラメータは、_ _init_ _() メソッドに自動的に渡されます。このメソッドをオーバーライドすることで、オブジェクトの初期化操作をカスタマイズできます。
例:
一部の読者は、_ _init_ _() メソッドがクラス定義に記述されているのではないかと尋ねるかもしれません。時々そうでないのですが、なぜですか?次の例を見てください。 ここで、_ _init_ _() メソッドの戻り値は None でなければならず、他の ## にすることはできないことに注意してください。 #:
したがって、
通常、初期化が必要な場合は _ _init_ _() メソッドを書き換えます。したがって、この _ _init_ _() メソッドは、オブジェクトをインスタンス化するときに呼び出される最初のメソッドではありません。 _ _new_ _(cls[, …]) メソッド_ _new_ _() メソッドは、
オブジェクトがインスタンス化されるときに呼び出される最初のメソッドですであり、他のパラメータは _ _init_ _() メソッドに直接渡されます。 _ _new_ _() メソッドでは、インスタンス オブジェクト (通常は cls クラスによってインスタンス化されたオブジェクト) を返すために が必要です。もちろん、他のオブジェクトを返すこともできます。
_ _new_ _() メソッドが書き換えることはほとんどなく、通常、Python はデフォルトのスキームで実行できます。ただし、 このメソッド をオーバーライドする必要がある状況があります。つまり、
不変型を継承する場合、その特性が特に重要になります。
_ _del_ _(self) デストラクター メソッド_ _init_ _() メソッドと _ _new_ _() メソッドがオブジェクトのコンストラクターである場合、 Python には、_ _del_ _() メソッドと呼ばれるデストラクターも提供されています。
オブジェクトが破棄されようとしているとき、このメソッドが呼び出されますバインディングの概念については前述しましたが、バインディングとは何でしょうか。 Python では、メソッドを呼び出す前にインスタンスが必要であることが厳密に要求されていますが、この制限は実際には Python のいわゆるバインディングの概念です。
これを試してみると、次のように呼び出すこともできることがわかるかもしれません:
ただし、これには問題があります。 クラスによってインスタンス化されたオブジェクトによると、内部の関数はまったく呼び出すことができません:
実際には、Pythonのバインディング機構により、最初のパラメータとして bb オブジェクトが自動的に使用されるため、TypeError が発生します。
別の例を見てください:
_ _dict_ _属性は辞書で構成されており、インスタンスは 個だけです。ディクショナリ内 オブジェクトの属性 には、クラス属性と特別な属性は表示されません。 キーは属性名 を表し、 値は属性の対応するデータ値 を表します。
インスタンス オブジェクト dd には 2 つの新しい属性があり、これら 2 つの属性はインスタンス オブジェクトにのみ属します:
## #どうしてこれなの?実際、これは完全に self パラメータによるものです。インスタンス オブジェクト dd が setXY メソッドを呼び出すとき、渡される最初のパラメータは dd なので、self.x = 4、self.y = 5 と同等です。 dd.x = 4、dd.y = 5 となるため、 これら 2 つの属性はインスタンス オブジェクト dd にのみ属するため、x と y はインスタンス オブジェクトやクラス オブジェクトでさえ見ることができません。
クラス インスタンスが削除された場合でも、インスタンス オブジェクト dd は printXY メソッドを呼び出すことができますか?答えは「はい」です:#
以上がPython のクラスとオブジェクトの使用方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。