オブジェクト指向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__を独自のクラスに追加する必要がある場合は、それも実行できますか。それをやってみましょう。

my_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__()

組み込み型からの継承

クラスは組み込み型から継承することもできます。つまり、組み込みから継承し、そこにあるすべての機能を利用できます。

以下の例では、辞書から継承していますが、そのメソッドの1つ__setitem__を実装しています。これ(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には、強制はしていませんが、促進する命名規則とスタイル規則があります。「」によって書かれたスタイルガイドがありますGuido van Rossum” the originator of Python, that describe the best practices and use of name and is called PEP8. Here is the link for this, https://www.python.org/dev/peps/pep-0008/

PEPはPython拡張提案の略で、提案された変更について議論するためにPythonコミュニティに配布された一連のドキュメントです。たとえば、すべてをお勧めします、

  • モジュール名-all_lower_case
  • クラス名と例外名-CamelCase
  • グローバル名とローカル名-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!