オブジェクト向けプログラミングベース-Phythonクラス(一)
12325 ワード
pythonでのインスタンス属性の作成
Personクラスでxiaoming、xiaohongなどのインスタンスを作成できますが、これらのインスタンスはアドレスの違い以外に何の違いもありません.現実世界では、xiaoming、xiaohongを区別するには、それぞれの名前、性別、誕生日などの属性に頼る必要があります.
各インスタンスに異なるプロパティを持たせるにはどうすればいいですか?Pythonは動的言語であるため、各インスタンスに直接属性を割り当てることができます.たとえば、xiaomingというインスタンスにname、gender、birth属性を加えることができます.
xiaohongに加えたプロパティは、必ずしもxiaomingと同じではありません.
インスタンスのプロパティは、通常の変数のように操作できます.
列:
2つのPersonクラスを含むインスタンスのリストを作成し、2つのインスタンスのnameに値を割り当て、nameに従ってソートします.
pythonでインスタンス属性を初期化する
1つのインスタンスに様々な属性を自由にバインドすることができますが、現実世界では、1つのタイプのインスタンスが同じ名前の属性を持つべきです.たとえば、Personクラスは作成時に
Personクラスを定義する場合、Personクラスに特別な
したがって、インスタンスを作成するには、
特に、初心者定義
これは、最初のパラメータnameがPythonインタプリタによってインスタンスの参照に渡され、メソッド全体の呼び出しパラメータの位置が一致しないため、作成に失敗したり、正常に動作しなかったりします.
例:
キーワードパラメータを定義するには、
参照コード:
pythonでのアクセス制限
Pythonの属性権限の制御は属性名によって実現され、1つの属性が二重下線の先頭
二重下線で始まる
ただし、属性が
下線で始まる属性
例:
実行結果:
pythonでのクラス属性の作成
クラスはテンプレートであり、インスタンスはクラスに基づいて作成されたオブジェクトです.
1つのインスタンスにバインドされたプロパティは他のインスタンスには影響しませんが、クラス自体もオブジェクトです.クラスにプロパティをバインドすると、すべてのインスタンスがクラスのプロパティにアクセスでき、すべてのインスタンスがアクセスするクラスのプロパティは同じです.すなわち、インスタンス属性は各インスタンスがそれぞれ持つ、互いに独立しており、クラス属性は1部のみである.
クラス属性を定義するには、classで直接定義します.
クラス属性は直接クラスにバインドされているため、アクセスクラス属性はインスタンスを作成する必要がなく、直接アクセスできます.
1つのインスタンス呼び出しクラスのプロパティにもアクセスできます.すべてのインスタンスが属するクラスのプロパティにアクセスできます.
Pythonは動的言語であるため、クラス属性も動的に追加および変更できます.
クラス属性が1つしかないため、Personクラスのaddressが変更されると、すべてのインスタンスがアクセスするクラス属性が変更されます.
例:
参照コード:
pythonのクラス属性とインスタンス属性の名前が衝突したらどうしますか?
クラス属性を変更すると、すべてのインスタンスがアクセスするクラス属性がすべて影響を受けますが、インスタンス変数でクラス属性を変更するとどのような問題が発生しますか?
結果は次のとおりです.
原因はp 1である.address='China'はPersonのaddressを変更するのではなく、p 1というインスタンスにインスタンス属性addressをバインドします.p 1にはインスタンス属性address('China')があり、その属するクラスPersonにもクラス属性addressがあります.
アクセスp 1.addressの場合は、インスタンスプロパティを優先して「China」を返します.
p 2にアクセスする.addressの場合、p 2にはインスタンス属性addressはありませんが、クラス属性addressがあるため、「Earth」を返します.
インスタンス属性とクラス属性が重複すると、インスタンス属性の優先度が高くなり、クラス属性へのアクセスがブロックされます.
p 1のaddressインスタンス属性を削除すると、p 1にアクセスする.addressはまたクラス属性の値'Earth'を返します.
インスタンスにクラス属性を変更しないでください.実際にはクラス属性を変更するのではなく、インスタンスにインスタンス属性をバインドします.
列子:前節のPersonクラス属性countを__に変更してください.count、インスタンスとクラスからこのプロパティにアクセスできるかどうか試してみましょう.
pythonでのインスタンスメソッドの定義
インスタンスのプライベート属性は
プライベート属性は外部からアクセスできませんが、クラスの内部からアクセスできます.インスタンスのプロパティを定義できるほか、インスタンスのメソッドを定義することもできます.
インスタンスのメソッドは、クラスで定義された関数であり、最初のパラメータは常に
インスタンスメソッドを呼び出すには、インスタンスで呼び出す必要があります.
インスタンス・メソッドの内部では、すべてのインスタンス・プロパティにアクセスできます.これにより、外部がプライベート・プロパティにアクセスする必要がある場合は、メソッド・コールによって取得できます.このデータ・パッケージの形式は、内部データの一貫性を保護するだけでなく、外部コールの難易度を簡素化することができます.
列子:Personクラスにプライベート属性を追加してください.score、スコアを表し、インスタンスメソッドget_を追加grade()、により_scoreの値はそれぞれA-優秀,B-合格,C-不合格の3段階を返す.
pythonのメソッドもプロパティです
classで定義したインスタンスメソッドも属性であり、実際には関数オブジェクトです.
すなわち、
メソッドもプロパティであるため、インスタンスに動的に追加することもできますが、
pythonでのクラスメソッドの定義
プロパティと同様に、メソッドにはインスタンスメソッドとクラスメソッドもあります.
クラスメソッドをclassで定義するには、次のように書く必要があります.
メソッドは、クラスのインスタンスではなく
インスタンスではなくクラスで呼び出されるため、クラスメソッドはインスタンス変数を取得できず、クラスの参照のみを取得できます.
例:クラス属性
注意クラスメソッドには
Personクラスでxiaoming、xiaohongなどのインスタンスを作成できますが、これらのインスタンスはアドレスの違い以外に何の違いもありません.現実世界では、xiaoming、xiaohongを区別するには、それぞれの名前、性別、誕生日などの属性に頼る必要があります.
各インスタンスに異なるプロパティを持たせるにはどうすればいいですか?Pythonは動的言語であるため、各インスタンスに直接属性を割り当てることができます.たとえば、xiaomingというインスタンスにname、gender、birth属性を加えることができます.
xiaoming = Person()
xiaoming.name = 'Xiao Ming'
xiaoming.gender = 'Male'
xiaoming.birth = '1990-1-1'
xiaohongに加えたプロパティは、必ずしもxiaomingと同じではありません.
xiaohong = Person()
xiaohong.name = 'Xiao Hong'
xiaohong.school = 'No. 1 High School'
xiaohong.grade = 2
インスタンスのプロパティは、通常の変数のように操作できます.
xiaohong.grade = xiaohong.grade + 1
列:
2つのPersonクラスを含むインスタンスのリストを作成し、2つのインスタンスのnameに値を割り当て、nameに従ってソートします.
class Person(object):
pass
p1 = Person()
p1.name = 'Bart'
p2 = Person()
p2.name = 'Adam'
p3 = Person()
p3.name = 'Lisa'
L1 = [p1, p2, p3]
L2 = sorted(L1,lambda p1,p2:cmp(p1.name,p2.name))
print L2[0].name
print L2[1].name
print L2[2].name
pythonでインスタンス属性を初期化する
1つのインスタンスに様々な属性を自由にバインドすることができますが、現実世界では、1つのタイプのインスタンスが同じ名前の属性を持つべきです.たとえば、Personクラスは作成時に
name
、gender
とbirth
の属性を持つべきですが、どうすればいいですか?Personクラスを定義する場合、Personクラスに特別な
init()
メソッドを追加できます.インスタンスを作成すると、init()
メソッドが自動的に呼び出され、インスタンスごとに次のプロパティを統一できます. class Person(object):
def __init__(self, name, gender, birth):
self.name = name
self.gender = gender
self.birth = birth
init()
メソッドの最初のパラメータはself
でなければなりません(別の名前でもいいですが、習慣的な使い方を推奨します).後続のパラメータは自由に指定でき、定義関数と何の違いもありません.したがって、インスタンスを作成するには、
self
以外のパラメータを指定する必要があります. xiaoming = Person('Xiao Ming', 'Male', '1991-1-1')
xiaohong = Person('Xiao Hong', 'Female', '1992-2-2')
init()
メソッドにより、Personインスタンス毎にname
、gender
、birth
およびinit()
の3つの属性が作成する、また、異なる属性値が付与され、属性使用にアクセスする.オペレータ:print xiaoming.name
# 'Xiao Ming'
print xiaohong.birth
# '1992-2-2'
特に、初心者定義
self
メソッドは、**kw
パラメータを忘れがちであることに注意してください.>>> class Person(object):
... def __init__(name, gender, birth):
... pass
...
>>> xiaoming = Person('Xiao Ming', 'Male', '1990-1-1')
Traceback (most recent call last):
File "", line 1, in
TypeError: __init__() takes exactly 3 arguments (4 given)
これは、最初のパラメータnameがPythonインタプリタによってインスタンスの参照に渡され、メソッド全体の呼び出しパラメータの位置が一致しないため、作成に失敗したり、正常に動作しなかったりします.
例:
キーワードパラメータを定義するには、
self.name = 'xxx'
;setattr(self, 'name', 'xxx')
を直接使用して属性を設定できるほか、(__)
を使用して属性を設定することもできます.参照コード:
class Person(object):
def __init__(self, name, gender, birth, **kw):
self.name = name
self.gender = gender
self.birth = birth
for k, v in kw.iteritems():
setattr(self, k, v)
xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student')
print xiaoming.name
print xiaoming.job
pythonでのアクセス制限
Pythonの属性権限の制御は属性名によって実現され、1つの属性が二重下線の先頭
"__job"
である場合、その属性は外部からアクセスできない.例を見てみましょう.class Person(object):
def __init__(self, name):
self.name = name
self._title = 'Mr'
self.__job = 'Student'
p = Person('Bob')
print p.name
# => Bob
print p._title
# => Mr
print p.__job
# => Error
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'Person' object has no attribute '__job'
二重下線で始まる
"__xxx__"
のみが外部に直接アクセスできないことがわかります.ただし、属性が
"__xxx__"
の形式で定義されている場合は、外部からアクセスすることもできます."__xxx__"
で定義された属性はPythonのクラスでは特殊な属性と呼ばれ、多くの事前定義された特殊な属性が使用できます.通常、一般的な属性を"_xxx"
で定義しないでください.下線で始まる属性
Person
は、外部からアクセスすることもできますが、習慣的には外部からアクセスするべきではありません.例:
class Person(object):
def __init__(self, name, score):
self.name = name
self.__score = score
p = Person('Bob', 59)
print p.name
print p.__score
実行結果:
Traceback (most recent call last):
File "index.py", line 9, in
print p.__score
AttributeError: 'Person' object has no attribute '__score'
Bob
pythonでのクラス属性の作成
クラスはテンプレートであり、インスタンスはクラスに基づいて作成されたオブジェクトです.
1つのインスタンスにバインドされたプロパティは他のインスタンスには影響しませんが、クラス自体もオブジェクトです.クラスにプロパティをバインドすると、すべてのインスタンスがクラスのプロパティにアクセスでき、すべてのインスタンスがアクセスするクラスのプロパティは同じです.すなわち、インスタンス属性は各インスタンスがそれぞれ持つ、互いに独立しており、クラス属性は1部のみである.
クラス属性を定義するには、classで直接定義します.
class Person(object):
address = 'Earth'
def __init__(self, name):
self.name = name
クラス属性は直接クラスにバインドされているため、アクセスクラス属性はインスタンスを作成する必要がなく、直接アクセスできます.
print Person.address
# => Earth
1つのインスタンス呼び出しクラスのプロパティにもアクセスできます.すべてのインスタンスが属するクラスのプロパティにアクセスできます.
p1 = Person('Bob')
p2 = Person('Alice')
print p1.address
# => Earth
print p2.address
# => Earth
Pythonは動的言語であるため、クラス属性も動的に追加および変更できます.
Person.address = 'China'
print p1.address
# => 'China'
print p2.address
# => 'China'
クラス属性が1つしかないため、Personクラスのaddressが変更されると、すべてのインスタンスがアクセスするクラス属性が変更されます.
例:
count
クラスにクラス属性count
を追加してください.インスタンスを作成するたびにPerson
属性に1を追加します.これにより、合計何個__init__()
のインスタンスが作成されたかを統計できます.インスタンスの作成には必ずcount
メソッドが呼び出されるので、ここでクラス属性p1.address = 'China'
を変更するのが適切です.参照コード:
class Person(object):
count = 0
def __init__(self, name):
Person.count = Person.count + 1
self.name = name
p1 = Person('Bob')
print Person.count
# => 1
p2 = Person('Alice')
print Person.count
# => 2
p3 = Person('Tim')
print Person.count
# => 3
pythonのクラス属性とインスタンス属性の名前が衝突したらどうしますか?
クラス属性を変更すると、すべてのインスタンスがアクセスするクラス属性がすべて影響を受けますが、インスタンス変数でクラス属性を変更するとどのような問題が発生しますか?
class Person(object):
address = 'Earth'
def __init__(self, name):
self.name = name
p1 = Person('Bob')
p2 = Person('Alice')
print 'Person.address = ' + Person.address
p1.address = 'China'
print 'p1.address = ' + p1.address
print 'Person.address = ' + Person.address
print 'p2.address = ' + p2.address
結果は次のとおりです.
Person.address = Earth
p1.address = China
Person.address = Earth
p2.address = Earth
__
が設定された後、p 1アクセスaddressは確かに「China」になったが、Person.addressとp 2.addressはまだ「Earch」ですが、どうしたんですか.原因はp 1である.address='China'はPersonのaddressを変更するのではなく、p 1というインスタンスにインスタンス属性addressをバインドします.p 1にはインスタンス属性address('China')があり、その属するクラスPersonにもクラス属性addressがあります.
アクセスp 1.addressの場合は、インスタンスプロパティを優先して「China」を返します.
p 2にアクセスする.addressの場合、p 2にはインスタンス属性addressはありませんが、クラス属性addressがあるため、「Earth」を返します.
インスタンス属性とクラス属性が重複すると、インスタンス属性の優先度が高くなり、クラス属性へのアクセスがブロックされます.
p 1のaddressインスタンス属性を削除すると、p 1にアクセスする.addressはまたクラス属性の値'Earth'を返します.
del p1.address
print p1.address
# => Earth
インスタンスにクラス属性を変更しないでください.実際にはクラス属性を変更するのではなく、インスタンスにインスタンス属性をバインドします.
列子:前節のPersonクラス属性countを__に変更してください.count、インスタンスとクラスからこのプロパティにアクセスできるかどうか試してみましょう.
class Person(object):
__count = 0
def __init__(self, name):
Person.__count = Person.__count + 1
self.name = name
print Person.__count
p1 = Person('Bob')
p2 = Person('Alice')
print Person.__count
pythonでのインスタンスメソッドの定義
インスタンスのプライベート属性は
self
で始まる属性で、外部からアクセスできません.これらの属性定義は何の役に立ちますか?プライベート属性は外部からアクセスできませんが、クラスの内部からアクセスできます.インスタンスのプロパティを定義できるほか、インスタンスのメソッドを定義することもできます.
インスタンスのメソッドは、クラスで定義された関数であり、最初のパラメータは常に
get_name(self)
であり、メソッドを呼び出すインスタンス自体を指し、他のパラメータは通常の関数と完全に同じです.class Person(object):
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
self
は、__init__(self, name)
の最初のパラメータである例の方法である.p1.get_grade
実は特殊な実例方法と見なすこともできる.インスタンスメソッドを呼び出すには、インスタンスで呼び出す必要があります.
p1 = Person('Bob')
print p1.get_name() # self
# => Bob
インスタンス・メソッドの内部では、すべてのインスタンス・プロパティにアクセスできます.これにより、外部がプライベート・プロパティにアクセスする必要がある場合は、メソッド・コールによって取得できます.このデータ・パッケージの形式は、内部データの一貫性を保護するだけでなく、外部コールの難易度を簡素化することができます.
列子:Personクラスにプライベート属性を追加してください.score、スコアを表し、インスタンスメソッドget_を追加grade()、により_scoreの値はそれぞれA-優秀,B-合格,C-不合格の3段階を返す.
class Person(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def get_grade(self):
if self.__score >= 80:
return 'A'
if self.__score >= 60:
return 'B'
return 'C'
p1 = Person('Bob', 90)
p2 = Person('Alice', 65)
p3 = Person('Tim', 48)
print p1.get_grade()
print p2.get_grade()
print p3.get_grade()
pythonのメソッドもプロパティです
classで定義したインスタンスメソッドも属性であり、実際には関数オブジェクトです.
class Person(object):
def __init__(self, name, score):
self.name = name
self.score = score
def get_grade(self):
return 'A'
p1 = Person('Bob', 90)
print p1.get_grade
# => >
print p1.get_grade()
# => A
すなわち、
p1.get_grade()
は関数オブジェクトを返すが、この関数はインスタンスにバインドされた関数であり、types.MethodType()
がメソッド呼び出しである.メソッドもプロパティであるため、インスタンスに動的に追加することもできますが、
class
で関数をメソッドに変更する必要があります.import types
def fn_get_grade(self):
if self.score >= 80:
return 'A'
if self.score >= 60:
return 'B'
return 'C'
class Person(object):
def __init__(self, name, score):
self.name = name
self.score = score
p1 = Person('Bob', 90)
p1.get_grade = types.MethodType(fn_get_grade, p1, Person)
print p1.get_grade()
# => A
p2 = Person('Alice', 65)
print p2.get_grade()
# ERROR: AttributeError: 'Person' object has no attribute 'get_grade'
# p2 get_grade
pythonでのクラスメソッドの定義
プロパティと同様に、メソッドにはインスタンスメソッドとクラスメソッドもあります.
self
で定義されているのはすべてインスタンスメソッドであり、インスタンスメソッドの最初のパラメータ@classmethod
はインスタンス自体である.クラスメソッドをclassで定義するには、次のように書く必要があります.
class Person(object):
count = 0
@classmethod
def how_many(cls):
return cls.count
def __init__(self, name):
self.name = name
Person.count = Person.count + 1
print Person.how_many()
p1 = Person('Bob')
print Person.how_many()
メソッドは、クラスのインスタンスではなく
Person
クラスにバインドされます.クラスメソッドの最初のパラメータはクラス自体に渡され、通常、パラメータ名はcls
と命名され、上のcls.count
は実際にはPerson.count
に相当する.インスタンスではなくクラスで呼び出されるため、クラスメソッドはインスタンス変数を取得できず、クラスの参照のみを取得できます.
例:クラス属性
count
をプライベート属性__count
に変更すると、外部から__score
を読み取ることはできませんが、クラスメソッドで取得できます.クラスメソッドを記述して__count
値を取得してください.注意クラスメソッドには
@classmethod
を追加する必要があります. :
class Person(object):
__count = 0
@classmethod
def how_many(cls):
return cls.__count
def __init__(self, name):
self.name = name
Person.__count = Person.__count + 1
print Person.how_many()
p1 = Person('Bob')
print Person.how_many()