Object-oriented-python-advanced-features
オブジェクト指向Python-高度な機能
ここでは、Pythonが提供する高度な機能のいくつかを見ていきます。
クラス設計のコア構文
この記事では、Pythonがクラス内の演算子をどのように活用できるかについて説明します。 Pythonは主にオブジェクトであり、メソッドはオブジェクトを呼び出します。これは、便利な構文で隠されている場合でも続きます。
>>> var1 = 'Hello'
>>> var2 = ' World!'
>>> var1 + var2
'Hello World!'
>>>
>>> var1.__add__(var2)
'Hello World!'
>>> num1 = 45
>>> num2 = 60
>>> num1.__add__(num2)
105
>>> var3 = ['a', 'b']
>>> var4 = ['hello', ' John']
>>> var3.__add__(var4)
['a', 'b', 'hello', ' John']
したがって、マジックメソッドaddを独自のクラスに追加する必要がある場合は、それを行うこともできます。 それを試してみましょう。
mylistという引数としてlistを取るコンストラクタinitを持つSumlistというクラスがあります。
class SumList(object):
def __init__(self, my_list):
self.mylist = my_list
def __add__(self, other):
new_list = [ x + y for x, y in zip(self.mylist, other.mylist)]
return SumList(new_list)
def __repr__(self):
return str(self.mylist)
aa = SumList([3,6, 9, 12, 15])
bb = SumList([100, 200, 300, 400, 500])
cc = aa + bb # aa.__add__(bb)
print(cc) # should gives us a list ([103, 206, 309, 412, 515])
出力
[103, 206, 309, 412, 515]
しかし、他の魔法のメソッドによって内部的に管理される多くのメソッドがあります。 以下はその一部です、
'abc' in var # var.__contains__('abc')
var == 'abc' # var.__eq__('abc')
var[1] # var.__getitem__(1)
var[1:3] # var.__getslice__(1, 3)
len(var) # var.__len__()
print(var) # var.__repr__()
組み込み型からの継承
クラスは組み込み型から継承することもできます。つまり、組み込み型から継承し、そこにあるすべての機能を利用できます。
以下の例では、辞書から継承していますが、メソッドsetitemの1つを実装しています。 この(setitem)は、辞書にキーと値を設定するときに呼び出されます。 これは魔法のメソッドなので、暗黙的に呼び出されます。
class MyDict(dict):
def __setitem__(self, key, val):
print('setting a key and value!')
dict.__setitem__(self, key, val)
dd = MyDict()
dd['a'] = 10
dd['b'] = 20
for key in dd.keys():
print('{0} = {1}'.format(key, dd[key]))
出力
setting a key and value!
setting a key and value!
a = 10
b = 20
前の例を拡張してみましょう。以下では、リストインデックスを処理するときに呼び出されるgetitemおよびsetitemという2つのマジックメソッドを呼び出します。
# Mylist inherits from 'list' object but indexes from 1 instead for 0!
class Mylist(list): # inherits from list
def __getitem__(self, index):
if index == 0:
raise IndexError
if index > 0:
index = index - 1
return list.__getitem__(self, index) # this method is called when
# we access a value with subscript like x[1]
def __setitem__(self, index, value):
if index == 0:
raise IndexError
if index > 0:
index = index - 1
list.__setitem__(self, index, value)
x = Mylist(['a', 'b', 'c']) # __init__() inherited from builtin list
print(x) # __repr__() inherited from builtin list
x.append('HELLO'); # append() inherited from builtin list
print(x[1]) # 'a' (Mylist.__getitem__ cutomizes list superclass
# method. index is 1, but reflects 0!
print (x[4]) # 'HELLO' (index is 4 but reflects 3!
出力
['a', 'b', 'c']
a
HELLO
上記の例では、Mylistに3つのアイテムリストを設定し、暗黙的にinitメソッドが呼び出され、要素xを印刷すると、3つのアイテムリスト(['a'、 'b'、 'c'])を取得します。 次に、このリストに別の要素を追加します。 後でインデックス1とインデックス4を要求します。 しかし、出力が表示された場合、要求された(index-1)から要素を取得しています。 リストのインデックス作成は0から始まりますが、ここではインデックス作成は1から始まります(そのため、リストの最初のアイテムが取得されます)。
命名規則
この記事では、変数に使用する名前、特に世界中のPythonプログラマーが使用するプライベート変数と規約を調べます。 変数はプライベートとして指定されていますが、Pythonにはプライバシーがありません。これは設計上です。 よく文書化されている他の言語と同様、Pythonには命名規則とスタイル規則がありますが、それらは強制されていません。 Pythonの創始者である「* Guido van Rossum」によって書かれたスタイルガイドがあります。これは、ベストプラクティスと名前の使用を説明し、PEP8と呼ばれています。 このリンクはこちらです*。https://www.python.org/dev/peps/pep-0008/
PEPはPython拡張提案の略であり、提案された変更について議論するためにPythonコミュニティに配布された一連のドキュメントです。 たとえば、すべてをお勧めします、
- モジュール名-all_lower_case
- クラス名と例外名-キャメルケース
- グローバル名とローカル名-all_lower_case
- 関数とメソッド名-all_lower_case
- 定数-ALL_UPPER_CASE
これらは単なる推奨事項であり、必要に応じて変更できます。 しかし、ほとんどの開発者はこれらの推奨事項に従っているので、コードが読みにくくなるかもしれません。
なぜ慣例に従うのですか?
PEPの推奨事項に従うことができます。
- 大多数の開発者にとってより身近なもの
- コードのほとんどの読者にとって明確です。
- 同じコードベースで作業する他の貢献者のスタイルと一致します。
- プロのソフトウェア開発者のマーク
- 誰もがあなたを受け入れます。
変数の命名-「パブリック」と「プライベート」
Pythonでは、モジュールとクラスを扱うときに、一部の変数または属性をプライベートとして指定します。 Pythonには、オブジェクトの内部を除いてアクセスできない「プライベート」インスタンス変数は存在しません。 プライベートとは、単にコードのユーザーが使用することを意図したものではなく、内部で使用することを意図したものです。 一般に、ほとんどのPython開発者は慣習に従っています。 たとえば、アンダースコアが前に付いた名前。 _attrval(以下の例)は、関数、メソッド、データメンバーのいずれであっても、APIまたはPythonコードの非公開部分として扱う必要があります。 以下は、私たちが従う命名規則です。
- パブリック属性または変数(このモジュールのインポーターまたはこのクラスのユーザーが使用することを意図)-* regular_lower_case *
- プライベート属性または変数(モジュールまたはクラスによる内部使用)-* _ single_leading_underscore *
- サブクラス化すべきでないプライベート属性-* __ double_leading_underscore *
- マジックアトリビュート-* double_underscores *(使用して、作成しないでください)
class GetSet(object):
instance_count = 0 # public
__mangled_name = 'no privacy!' # special variable
def __init__(self, value):
self._attrval = value # _attrval is for internal use only
GetSet.instance_count += 1
@property
def var(self):
print('Getting the "var" attribute')
return self._attrval
@var.setter
def var(self, value):
print('setting the "var" attribute')
self._attrval = value
@var.deleter
def var(self):
print('deleting the "var" attribute')
self._attrval = None
cc = GetSet(5)
cc.var = 10 # public name
print(cc._attrval)
print(cc._GetSet__mangled_name)
出力
setting the "var" attribute
10
no privacy!