2017-02-19 21 views
2

Iは、peeweeのソースコードを見て具体的Modelupdate機能れている:https://github.com/coleifer/peewee/blob/a33e8ccbd5b1e49f0a781d38d40eb5e8f344eee5/peewee.py#L4718クラスメソッドがインスタンスで呼び出されないようにするにはどうすればよいですか?

任意更新操作は、すべての行に影響を与える場合、私は、この方法は、行インスタンスから呼び出すことができるという事実が好きではありませんステートメントがwhere句と正しく結合されていない場合はモデル内にあります。したがって、このクラスメソッドをモデルインスタンスから呼び出すことを禁止する方法を探したいと思います。

グーグルでは、これが非常に難しいと私は信じています。 delattrから__init__が機能していないようです。 uppdate関数からisclass(self)を実行すると常にTrueが返されます。これは、classmethod内に実際にはクラスでインスタンスではないことがわかります。

提案がありますか?あなたが唯一のインスタンスに対してすべての属性アクセスとのために呼ばれ__getattribute__を上書きしてclassmethodicityのために戻されているものを調べることができ

+0

私はあなたが 'classmethod'でそれを行うことはできないと思います。インスタンスにバインドされているかどうかをチェックし、例外が発生するかどうかを調べる 'classmethod'に似た独自の記述子を書く必要があります。 – BrenBarn

答えて

1

__getattribute__はSchwobasegglの回答のようにカスタマイズできますが、カスタムメタクラスを使用することもできます。

Pythonで「メタクラス」と言えば、通常は__new__メソッドをオーバーライドし、クラス作成時に(インスタンス作成時とは対照的に)複雑な作業を行うと考えられます。ただし、すべての特別なダンダー(__these__ __methods__)を残しておくと、メタクラスはクラスのクラスに過ぎず、すべてのメソッドはクラス自体からは見えますが、クラスのインスタンスからは表示されません。つまり、1つのインスタンスがインスタンスであるときには表示されませんが、インスタンスでクラスを直接参照することはできません。 (もちろん、人は常にself.__class__.methodを行うことができます、が)

また、複雑さのmetaclasseの正当悪い-名声にもかかわらず、__getattribute__自体をオーバーライドすることは、いくつかのpitfallsを持つことができます。この特定の場合、あなたはalreaydメタクラス使用守りたいclasssで

- 「普通の」メタクラスが使用するとは異なりますが、この特定の使用を、普通のクラス階層のように自由に構成可能になります

class ClsMethods(BaseModel): 
    # inherit from `type` if there is no metaclass already 

    # now, just leave __new__, __init__, __prepare__ , alone 
    # and write your class methods as ordinary methods: 
    def update(cls, *args, **kw): 
      ... 

    def fetch_rows_from(self, ...): 
      ... 

class Model(with_metaclass(ClsMethods)): 
     # This really socks. Do you really still need Py2 support? :-) 

     ... 

(それは明白であるが、あなたはクラスメソッドとしてメタクラスで メソッドを宣言する必要はありません知覚する必要があります。それらのすべてが クラスでメタクラスのインスタンスのためのクラスメソッド、です)

とAT迅速なデモコンソール:

In [37]: class M(type): 
    ...:  def secret(cls): print("At class only") 
    ...:  

In [38]: class A(metaclass=M): 
    ...:  pass 
    ...: 

In [39]: A.secret() 
At class only 

In [40]: A().secret() 
--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 
<ipython-input-40-06355f714f97> in <module>() 
----> 1 A().secret() 

AttributeError: 'A' object has no attribute 'secret' 
+0

TypeError:メタクラスの競合が発生しました。派生クラスのメタクラスは、すべてのベースのメタクラスの(厳密ではない)サブクラスでなければなりません。 –

+0

この行から 'BaseModel .__ new__'の' super super(BaseModel、cls).__新しい__(cls、name、bases、attrs) 'を返します。 –

0

。また、あなただけの特定のitemを拒否することができます。

import inspect 

class A(object): # aka Model 
    @classmethod 
    def f(cls, *args, **kwargs): 
     print(args, kwargs) 

class B(A): # your Model subclass 
    def __getattribute__(self, item): 
     # if item == 'update': 
     #  raise TypeError 
     obj = super(B, self).__getattribute__(item) 
     # classmethod check 
     if inspect.ismethod(obj) and obj.__self__ is B: 
      raise TypeError 
     return obj 

> a = A() 
> b = B() 

> A.f(5, p=7) 
(5,) {'p': 7} 

> B.f(5, p=7) 
(5,) {'p': 7} 

> a.f(5, p=7) 
(5,) {'p': 7} 

> b.f(5, p=7) 
# TypeError 

クラスメソッドのチェックがMartijn Pietersにより、このanswerから取得されます。

関連する問題