Python学習ノート(五)OOP
モジュール
モジュール
標準モジュールファイルテンプレート:モジュール内の非公開関数プレフィックス で直接参照できる特殊な変数は、一般に Pythonはprivate関数または変数へのアクセスを完全に制限する方法がないことに注意してください.だからこれは自覚に頼らなければならない サードパーティモジュールはpipを使用して
オブジェクト向けプログラミング
クラス構文
アヒルのタイプ:アヒルのように見え、走るとアヒルのように見える限り、アヒルと見なすことができます
Pythonのダイナミック性も継承に現れている.クラスを呼び出す関数があると仮定すると、受信したオブジェクトにもこのメソッドがある限り、そのオブジェクトがクラスまたはクラスのサブクラスであるかどうかのインスタンスに関係なく実行できます.
オブジェクト情報の取得は、オブジェクトの情報を取得するためにtype()を使用することができ、 dir()は、1つのオブジェクトのすべての属性およびメソッドを に戻すことができる.オブジェクトの詳細が分からない場合、 オブジェクト向けの高度なプログラミング
Pythonは動的言語であるため、クラス、インスタンスに属性またはメソッドを任意にバインドできます.バインディングメソッドは、
インスタンスのプロパティを制限する場合は、クラスを定義するときに、インスタンスにバインドされたプロパティ名がname 1またはname 2に限定される特殊な変数
分析:
(1)インスタンスに属性をバインドするには:
(2)クラスへのバインド属性:
(3)インスタンスへのバインド方法:
(4)クラスへのバインド方法
残りの2つの状況は、
@propertyの使用
属性を変更する必要がある場合、パラメータをチェックできるように、一般的にメソッドを呼び出して属性値を設定します.しかし、これでは少し面倒になります.このとき@propertyアクセサリーが機能します.
注意属性
多重継承
継承された複数の親が同じメソッドを持っている場合、最初の親に準じて、後の親のメソッドは機能しません.
カスタムクラス
列挙クラス
valueはメンバーのint値を列挙し、デフォルトは1から
もう1つのEnumから派生したカスタム列挙クラスは、構文がC++の列挙タイプに似ています.
列挙クラスのメンバーには、次の参照方法があります.
メタ*
動的言語の関数とクラスの定義は、実行時に動的に作成されます.
これにより、
クラスはメタクラスのインスタンスに相当します.metaclassはPythonがオブジェクトに向かって最も理解しにくく、最も使いにくいマジックコードで、一般的には使えません
*この部分は省略しておき、使用するときは実例に基づいて整理する
モジュール
import
を使用します.あるモジュールの1つのクラスまたは関数のみをインポートし、from import
を使用して実装するものもあります.モジュール名の競合を回避するために、Pythonはパッケージ(Package)と呼ばれるディレクトリ別にモジュールを整理する方法を導入した.aディレクトリの下のb.pyモジュール名はa.b
です.aディレクトリの下には、ファイルの内容が空であっても、ファイル__ini__.py
が必要です.さもないとaは普通のディレクトリになります.標準モジュールファイルテンプレート:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'a test module' #
__author__ = 'Your Name'
...
def f():
...
if __name__ == '__main__': # ,if 。
f()
_
、例えばdef _private_1():
__argname__
という前後の2つの下線の形式で表され、自分が定義した公開関数または変数は一般的に一般的な形式def f
で表され、このような下線の形式は使用されない.pip install numpy
をインストールすることができ、pythonの公式サイトから自動的にダウンロードおよびインストールされます.自分でダウンロードしてインストールすることもできます.オブジェクト向けプログラミング
クラス構文
class Student(object):
pass
object
はデフォルトの親の名前です.インスタンスの作成にはtom = Student()
が使用されます.動的言語として、Pythonはtomバインドクラス外の新しい属性tom.name = 'Tom'
を自由にサポートする.インスタンスの作成時にバインドする必要があるプロパティがある場合は、クラスの__ini__
関数に一般的に書き込まれます.def __ini__(self, arg1, arg2):
self.__arg1 = ...
self.arg2 = ...
__ini__
の最初のパラメータは常にselfであり、自動的に入力されます.このような__ini__
があれば、インスタンスを作成する際にarg1
およびarg2
パラメータを入力する必要がある.__arg1
の2つの前下線は、外部からアクセスできないプライベート属性であることを示しています.アヒルのタイプ:アヒルのように見え、走るとアヒルのように見える限り、アヒルと見なすことができます
Pythonのダイナミック性も継承に現れている.クラスを呼び出す関数があると仮定すると、受信したオブジェクトにもこのメソッドがある限り、そのオブジェクトがクラスまたはクラスのサブクラスであるかどうかのインスタンスに関係なく実行できます.
オブジェクト情報の取得
import types
であれば、type( ) == types.type
を使用して、オブジェクトが特定の関数タイプであるか否かを判断することもできる.isinstance( , )
の判定方法は、そのオブジェクトがパラメータ内のクラスの親である場合にもTrueを返す.typeで判断できる基本タイプはisinstanceを使用し、2番目のパラメータはlistであってもよく、要素の1つであればTrueを返します.hasattr(obj, 'arg')
を使用してobjにarg属性または方法があるかどうかを得ることができる.getattr(obj, 'arg')
は、属性またはメソッドを返す.setattr(obj, 'arg', value)
属性またはメソッドの設定(ない場合は直接増加)__slots__
の使用Pythonは動的言語であるため、クラス、インスタンスに属性またはメソッドを任意にバインドできます.バインディングメソッドは、
from types import MethodType
s.f = MethodType(f, s)
を使用して、メソッドfをクラスまたはインスタンスsにバインディングします.同時に、fの最初のパラメータがselfであればバインドできないことに注意してください.インスタンスのプロパティを制限する場合は、クラスを定義するときに、インスタンスにバインドされたプロパティ名がname 1またはname 2に限定される特殊な変数
__slots__ = ('name1','name2')
を定義する必要があります.分析:
from types import MethodType
class Student(object):
__slots__ = ('name', 'sex', 'set_name', 'set_grade')
# 。 #
#
def set_name(self, name):
self.name = name
# #
def set_grade(self, grade):
self.grade = grade
# #
def set_score(self, score):
self.score = score
# #
def set_sex(self, sex):
self.sex = sex
tom = Student()
jane = Student()
(1)インスタンスに属性をバインドするには:
tom.name = 'Tom' # ,name
jane.grade = 98 # ,grade ,
print(jane.name) # , jane name
#
(2)クラスへのバインド属性:
Student.name = 'name' #
Student.grade = 0 # , __slots__
tom.name = 'Tom' # ,
print(jane.name) # name
(3)インスタンスへのバインド方法:
tom.set_name = MethodType(set_name, tom) # ,
tom.set_grade = MethodType(set_name, tom) # , ,
tom.set_score = MethodType(set_score, tom) # ,
tom.set_sex = MethodType(set_name, tom) # ,
(4)クラスへのバインド方法
#
Student.set_name = MethodType(set_name, Student)
tom.name = 'Tom'
print(jane.name) # , ,“ . =”
tom.set_name('Tom')
jane.set_name('Jane') # ,
tom.name = 'Tom' # , (3) , 。
print(jane.name)
print(tom.name) # Jane, ,
# ,
Student.set_grade = MethodType(set_grade, Student)
tom.set_grade(4) #
tom.grade = 4 # ,
print(tom.grade) # , , ,
残りの2つの状況は、
__slots__
がクラスを制限しないため、任意の方法および属性をバインドすることができるため、言うまでもない.ただし、呼び出しメソッドによってバインドされた属性は読み取り専用であり、呼び出しメソッドによってのみ変更でき、インスタンスで.
賦値を直接使用して変更することはできません.__slots__
は、インスタンスのメソッドまたは属性バインドのみを制限し、クラスは制限しません.クラスバインドのメソッドとプロパティは、インスタンスで呼び出すことができますが、クラスプロパティはインスタンスでは読み取り専用であり、その値は最後の呼び出しメソッドまたは . =
で付与された結果であり、インスタンスでは . =
で変更できません.@propertyの使用
属性を変更する必要がある場合、パラメータをチェックできるように、一般的にメソッドを呼び出して属性値を設定します.しかし、これでは少し面倒になります.このとき@propertyアクセサリーが機能します.
@property
def name(self):
return self._name
@name.setter # , name
def name(self,value):
...
self._name = value
注意属性
_name
は必ず下線を引いて属性と方法を区別しなければならない.そうしないと、名前が同じ方法になり、上のコードが再帰になり、再帰回数オーバーフローエラーが報告される.多重継承
継承された複数の親が同じメソッドを持っている場合、最初の親に準じて、後の親のメソッドは機能しません.
カスタムクラス
__slots__
のような両端に下線が2つある変数や関数は特殊な用途があるため、このようなオブジェクトを定義することでクラスをカスタマイズすることができます.__str__(self)
:print( )
を実行すると、プログラムは属性とメモリアドレスを印刷し、特定のコンテンツを印刷したい場合は、__str__
メソッドを定義して、特定のコンテンツを出力することができる.printではなくクラス名出力情報を直接呼び出す場合は、__repr__()
メソッドを定義する必要があります.簡単な定義メソッドは__repr__ = __str__
高速定義です.__iter__(self)
:クラスを反復するには、__iter__
メソッドを定義してself
を返し、__next__(self)
メソッドを定義して反復で行うことを定義する必要があります.__getitem__(self, n)
:クラスをlistのように下付き要素で操作できます.__getitem__
で要素値を返します.スライスなどの機能を実現するには、伝達されたパラメータがsliceであるかどうかを判断するなど、この関数をさらに細分化する必要があります.同様に、クラスをdictのようにして__setitem__
を使用する.__delitem__
を使用して要素を削除します.以上の方法では,クラスをlistやdictの「アヒル」に変え,クラスをlistやdictのように操作できるようにした.__getattr__(self, attr)
:ダイナミックプロパティまたはメソッドを返します.この関数の下でattrを判断し,所定の属性や方法をバインドする.バインドプロパティはプロパティ値を返し、バインドメソッドはlambda関数を返します.制限がなければ、任意のプロパティまたはメソッドがバインドできることは明らかです.この場合、自身を返すと、チェーン呼び出しが実現されます.これを利用して,異なるAPIに対するSDKを構築する.以下のコードは、GitHubのAPIのURL出力を実現します.class Chain(object):
def __init__(self, path =''):
self._path = path
def __getattr__(self, path):
return Chain('%s/%s' %(self._path, path))
def __call__(self,name):
return Chain('%s/:%s' %(self._path, name))
def __str__(self):
return 'GET ' + self._path
print(Chain().users('hermanncain').repos)
# GET /users/:hermanncain/repos
__call__(self)
:インスタンス自体が呼び出されます.すなわち、s()
が呼び出されると__call__(self)
が実行される.パラメータを渡すために__call__(self, *args, **kw)
を使用してもよく、s(*args, *kw)
が呼び出されるとその内容が実行される.これにより、クラスとインスタンスの境界が曖昧になります.列挙クラス
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
'Oct', 'Nov', 'Dec'))
for name, member in Month.__member__.items():
print(name, '=>', member, ',', member.value)
valueはメンバーのint値を列挙し、デフォルトは1から
もう1つのEnumから派生したカスタム列挙クラスは、構文がC++の列挙タイプに似ています.
from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0
Mon = 1
...
@unique
デコレーションは、繰り返し値をチェックするために使用される.列挙クラスのメンバーには、次の参照方法があります.
print(Weekday.Sun)
print(Weekday['Sun'])
print(Weekday(1))
# Weekday.Sun
print(Weekday.Sun.value)
# 0
メタ*
type()
を使用したクラスの作成動的言語の関数とクラスの定義は、実行時に動的に作成されます.
a.py
のモジュールを書いて、モジュールの中でclass A
を定義して、それからメインプログラムの中でfrom a import A
で、モジュールをロードする時モジュールのすべての文を実行して、結果は動的に1つのAのclassを作成します.type(A)
戻り値がtype
type(A )
戻り値がclass '__main__'.A
です.ただし、type()
は、クラスを動的に作成するためにも使用できます.実際にPythonインタプリタがclass
定義に遭遇した場合も、type()
を使用してクラスを動的に作成します.def f(self, ...):
...
A = type('A', (object,), dict(af = f)
これにより、
A
クラスが動的に作成され、親はobject
であり(多重継承親はtuple
に配置されることに注意し、親が1つしかない場合、tupleには1つの要素しかなく、カンマは少なくない)、af
という方法がある.metaclass
元*クラスはメタクラスのインスタンスに相当します.metaclassはPythonがオブジェクトに向かって最も理解しにくく、最も使いにくいマジックコードで、一般的には使えません
*この部分は省略しておき、使用するときは実例に基づいて整理する