9

同じ名前のプロパティとメソッドを持つ方法はありますか?通常の方法で使用でき、同時に呼び出すことができるプロパティを意味しますか?このような:

>>> b = Book()
>>> b.pages
123
>>> b.pages()
123
>>> b.pages(including_toc=False)
123
>>> b.pages(including_toc=True)
127
4

4 に答える 4

10

いいえ、できません。

()常に左側の式からオブジェクトを呼び出します。

これが意味することは、b.pages()次のように読むことができるということです。

_tmp = b.pages
_tmp()

ご覧のとおり、メソッド属性です。

あなたができること(しかしすべきではないこと)は、いくつかのカスタムクラスで整数をラップし、__call__メソッドを提供することです…しかし、私はそのような黒魔術に反対することをお勧めします。

于 2012-10-23T11:27:09.477 に答える
5

クラスのインスタンスは、Bookと呼ばれる属性を1つだけ持つことができますpages。その属性は何でもかまいません(整数、呼び出し可能な関数、実際には何でも)が、それは1つだけです。

物事を表示する別の方法は、バイトコードレベルです-2行のコードが与えられます:

>>> def a():
...     book.pages
...     book.pages()
... 

これがそれdisassemblesです:

>>> dis.dis(a)
  2           0 LOAD_GLOBAL              0 (book)
              3 LOAD_ATTR                1 (pages)
              6 POP_TOP

  3           7 LOAD_GLOBAL              2 (book)
             10 LOAD_ATTR                1 (pages)
             13 CALL_FUNCTION            0
  [...a few more irrelevant lines...]

最初の行(book.pages)はbookオブジェクトをロードし、そこからpages属性(LOAD_ATTR)をロードします

2行目(book.pages())はまったく同じことを行い、bookオブジェクトをロードし、属性をロードしてから、pages属性呼び出しCALL_FUNCTIONます。

LOAD_ATTR最終的にどのように使用されるかに基づいて、返品を別のものにすることができる正しい方法はありません。あなたが得ることができる最も近いものは、両方のように振る舞う奇妙なオブジェクトを返すことです

>>> class WeirdInteger(int):
...   def __call__(self, including_toc):
...     print "WeirdInteger(%s) called" % (self)
...
>>> a = WeirdInteger(10)
>>> a
10
>>> a*2
20
>>> a()
WeirdInteger(10) called

..しかし、そうしないでください。あなたのコードを使用している人は誰もpages属性がこのように機能することを期待しません、そして渡されるコードのビットはpages実際の整数を必要とするかもしれません。

代わりに、Booksクラスを別の方法で設計します(pages通常の関数を作成するか、別のプロパティを追加しますpages_without_toc

于 2012-10-23T11:51:45.130 に答える
3

簡単な回答:いいえ。プロパティとメソッドはクラスの属性であり、同じ名前空間の一部であるためです。したがって、後で宣言されるものは前のものをオーバーライドします。

于 2012-10-23T11:28:35.720 に答える
1

特定のフラグが設定されている場合、あなたの主な目標はpages異なる値を返すことだと思います。目標に応じて機能する可能性のあるアプローチの1つはpages、属性ではなくプロパティ(正確にはPythonの意味で)を作成することです。toc次に、フラグが設定されているかどうかに応じて、値の有無に応じて値を返すようにします。したがって、たとえば:

class Book(object):
    def __init__(self, toc, pages):
        self._toc = toc
        self._pages = pages
        self.include_toc = False

    @property
    def pages(self):
        if self.include_toc:
            return self._pages + self._toc
        else:
            return self._pages

仕組みは次のとおりです。

>>> b = Book(5, 55)
>>> b.pages
55
>>> b.include_toc = True
>>> b.pages
60

これはあなたが求めていたものを正確に実行するわけではありませんが、特定のユースケースのサブセット(つまりpages、フラグを設定して複数の呼び出しを行い、フラグを時々変更するだけの場合)には同じかそれ以上です- -エンドユーザーが設定する場合や、特定の書籍のページ数にinclude_tocほとんどの場合またはほとんど含まない場合など。)_toc

ただし、phant0mが指摘しているように、フラグは永続的であるため、設定した後でリセットに失敗すると、予期しない結果が生じる場合があります。そしてeryksunが指摘しているように、コンテキストマネージャーはその問題に対する古典的な解決策です。

これは確かに過剰設計かもしれませんが、それでもそれを実証するほど単純です。Bookこれを:の定義に追加するだけです。

    @contextlib.contextmanager
    def set_toc_reset(self, state):
        try:
            old_flag = self.include_toc
            self.include_toc = state
            yield self
        finally:
            self.include_toc = old_flag

これにより、フラグがリセットされます。

>>> from foo import Book
>>> b = Book(5, 55)
>>> with b.set_toc_reset(True):
...     print b.pages
... 
60
>>> b.include_toc
False
于 2012-10-23T12:45:41.823 に答える