Python 3の組み込み関数を速攻理解しよう: オブジェクト/スコープ/モジュール/動的評価/入出力編特集:タイニーレファレンス(2/3 ページ)

» 2017年04月28日 05時00分 公開
[かわさきしんじInsider.NET編集部]

オブジェクトの属性を操作する: delattr/getattr/hasattr/setattr

 組み込み関数delattr/getattr/hasattr/setattrはそれぞれ、オブジェクトからの属性の削除/オブジェクトの属性値の取得/オブジェクトに属性があるかのチェック/オブジェクトに対する属性の設定を行う。以下に構文を示す。

delattr(object, name)  # objectから属性nameを削除
getattr(object, name[, default])  # objectの属性nameの値を取得
hasattr(object, name)  # objectに属性nameがあるかをチェック
setattr(object, name, value)  # objectの属性nameの値をvalueに設定


組み込み関数delattr/getattr/hasattr/setattrの構文

 組み込み関数delattrは第1引数に指定したオブジェクトから、第2引数に指定した名前の属性を削除する。オブジェクトoに属性aがあったとすると、「delattr(o, a)」は「del o.a」と同等の処理を行う。存在しない属性名を指定すると例外が発生する。

 組み込み関数getattrは第1引数に指定したオブジェクトから、第2引数で指定した名前の属性の値を取得する。オブジェクトoに属性aがあったとすると、「getattr(o, a)」は「o.a」と同等となる。第2引数で指定した名前の属性がないときには、第3引数を指定していればその値が返送され、指定していなければ例外が発生する。

 組み込み関数hasattrは第1引数に指定したオブジェクトに、第2引数で指定した名前の属性があればTrueを、なければFalseを返送する。

 組み込み関数setattrは第1引数に指定したオブジェクトに対して、第2引数で指定した名前の属性の値を第3引数に指定したものにする。「setattr(o, a, v)」は「o.a = v」と同等となる。

 以下にこれらの組み込み関数の使用例を示す。

class AttrTest:
  def __init__(self, name="", num=0):
    self.name = name  #setattr(self, "name", name)
    setattr(self, "num", num)
  def __repr__(self):
    result = ""
    for idx, value in vars(self).items():
      result += f"{idx}: {value}, "
    return result[0:-2]

at = AttrTest()

setattr(at, "name", "insider.net")
at.name = "build insider"
setattr(at, "newprop", 200)      # 新規の属性も作成可能(場合による)
print(getattr(at, "newprop"))    # 出力結果: 200
print(hasattr(at, "foo"))        # 出力結果: False
print(getattr(at, "foo"))        # 例外: AttributeError
print(getattr(at, "foo", None))  # 出力結果: None
delattr(at, "newprop")
repr(at)  # 出力結果: 'name: build insider, num: 0'


組み込み関数delattr/getattr/hasattr/setattrの使用例

 AttrTestクラスは__init__メソッドと__repr__メソッドを定義しており、前者では属性(インスタンス変数)の初期化を行い、後者では文字列表現を独自の方法で作成している(ここでは全ての属性を「vars(self)」で取り出して、属性名と値をカンマで区切った文字列を作成している(組み込み関数varsについては後述)。__init__メソッドでは、「self.name = ……」と「setattr(self, ……)」という2つの形式で属性を設定しているが、既に述べた通り、これらは同等な処理となる。

 クラス定義の後は、そのインスタンスを作成し、さまざまな形式でインスタンスの属性の設定(setattr)、取得(getattr)、チェック(hasattr)、削除(delattr)を行っている。

オブジェクトが呼び出し可能かを調べる: callable

 あるオブジェクトが呼び出し可能かどうかは組み込み関数callableで調べられる。構文は次の通り。

callable(object)


組み込み関数callableの構文

 使用例を以下に示す。

def func1(x):
  return x + 1

func2 = lambda x: x * 2

print(callable(func1))  # 出力結果: True
print(callable(func2))  # 出力結果: True
print(func1(10))  # 出力結果: 11
print(func2(9))   # 出力結果: 18

num = 100
print(callable(num))    # 出力結果: False

class Func:
  def __init__(self, x=100):
    self.x = x
  def __call__(self):
    return str(self.x)

func3 = Func()
print(callable(func3))  # 出力結果: True
print(func3())          # 出力結果: 100


組み込み関数callableの使用例

 関数func1/func2は通常の関数とラムダ式、func3オブジェクトは__call__メソッドを定義しているクラスFuncのインスタンスとなっていて、これら全てについて組み込み関数callableはTrueを返す。関数func1とfunc2については予想通りだが、func3オブジェクトについては少し説明が必要だ。あるクラスで__call__メソッドを定義すると、そのインスタンスは呼び出し可能なオブジェクトとなり、「()」を付けて呼び出せるようになる。呼び出しを行うと、__call__メソッドのコードが実行される。

クラスに関連するもの: classmethod/staticmethod/isinstance/issubclass/property/super

 組み込み関数classmethod/staticmethodはクラス定義の際にクラスメソッド(クラスオブジェクトを第1引数に取るクラスに関連付けられたメソッド)とスタティックメソッド(クラスに含まれるが、クラスともインスタンスとも関連付けられないメソッド)を定義するのに使用する。通常は次のようにデコレータの形で使用する。

class ClsTest:
  clscounter = 0
  _staticcounter = 0  
  @classmethod
  def clsmethod(cls):
    cls.clscounter += 1
    print(f"called {cls.clscounter} time(s)")
  @staticmethod
  def staticmethod():
    ClsTest._staticcounter += 1
    print(f"called {ClsTest._staticcounter} time(s)")

ClsTest.clsmethod()     # 出力結果: 1
ClsTest.staticmethod()  # 出力結果: 1


classmethod/staticmethodによるクラスメソッド/スタティックメソッドの定義

 組み込み関数isinstanceは第1引数に渡したオブジェクトが、第2引数に渡した型オブジェクトで表される型(もしくはその派生クラス)かどうかをチェックする。組み込み関数issubclassは第1引数に渡した型オブジェクトで示される型が、第2引数に渡した型オブジェクトで示される型(もしくはその派生クラス)かどうかをチェックする。構文は次のようになっている。

isinstance(object, classInfo)
issubclass(class, clssInfo)


組み込み関数isinstance/issubclassの構文

 以下に例を示す。

class B:
  pass

class C:
  pass

class D(B):
  pass

c = C()
d = D()
print(isinstance(c, B))  # 出力結果: False
print(isinstance(d, B))  # 出力結果: True
print(isinstance(c, (B, C)))  # 出力結果: True
print(issubclass(B, B))  # 出力結果: True
print(issubclass(C, B))  # 出力結果: False
print(issubclass(D, B))  # 出力結果: True


組み込み関数isinstance/issubclassの使用例

 組み込み関数issubclassでは第1引数と第2引数に同じ型オブジェクトを渡した場合(上の例では「issubclass(B, B)」)、その結果がTrueになる(クラスはそのクラスの派生クラスと見なされる)ことには注意しよう。また、いずれの関数も第2引数には型オブジェクトをタプルの形で渡してもよい(上の例では「isinstance(c, (B, C))」)。この場合、タプルに含まれるいずれかのクラスに該当すると、Trueが返される。

 組み込み関数propertyはクラス定義時にセッター/ゲッターなどを持つプロパティを定義する際に使用する。構文は次の通り。

property(fget=None, fset=None, fdel=None, doc=None)


組み込み関数propertyの構文

 パラメーターのfget/fset/fdel/docには、それぞれゲッターとなる関数/セッターとなる関数/属性(プロパティ)を削除する関数/プロパティのドキュメントストリングとなる文字列を指定する。以下に使用例を示す。

class PropTest1:
  def __init__(self, num=0):
    self._num = num
  def get(self):
    return self._num
  def set(self, value):
    self._num = value
  def remove(self):
    del self._num
  num = property(fget=get, fset=set, fdel=remove, doc="property num")
  #num = property(get, set, remove, "property num")も同等

pt = PropTest1()
print(pt.num)  # 出力結果: 0
pt.num = 100
print(pt.num)  # 出力結果: 100
del pt.num
pt.num  # 例外: AttributeError: 'PropTest1' object has no attribute '_num'


組み込み関数propertyの使用例(その1)

 組み込み関数propertyの戻り値が実際のプロパティとして使われる。上で行っているように、名前付きの引数なので、読み取り専用プロパティにするのであれば「num = property(fget=get, doc="……")」のようにする。

 なお、上のコードは次のように書いてもよい。

class PropTest2:
  def __init__(self, num=0):
    self._num = num
  @property
  def num(self):
    return self._num
  @num.setter
  def num(self, value):
    self._num = value
  @num.deleter
  def num(self):
    del self._num


組み込み関数propertyの使用例(その2)

 ここでは、propertyをデコレータとして使用している。最初にゲッターを定義して、そのメソッドと同じ名前のメソッドに「@<ゲッターのメソッド名>.setter」あるいは「@<ゲッターのメソッド名>.deleter」というデコレータを付記することで、セッターあるいは削除に使用するメソッドを定義できる(ここでは省略したが、ドキュメントストリングはゲッターの定義の先頭に含める)。

 組み込み関数superは、派生クラスで定義されているメソッドが、処理を基底クラスのメソッドに委譲する際に基底クラスにアクセスするために使用する。以下に例を示す。

class Base:
  def method(self):
    print("base method")

class Derived(Base):
  def method(self):
    super().method()
    print("derived method")

derived = Derived()
derived.method()


組み込み関数superの使用例

 引数を持つバージョンもあるが、これについては説明を割愛する。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。