Har*_*ren 6 python cpython class-method peewee
我一直在寻找 的源代码peewee,特别Model是该update函数:https://github.com/coleifer/peewee/blob/a33e8ccbd5b1e49f0a781d38d40eb5e8f344eee5/peewee.py#L4718
我不喜欢这样的事实:如果语句未与子句正确耦合,则任何更新操作都会影响模型中的每一行,可以从行实例调用此方法where。因此,我想找到某种方法来禁止从模型实例调用此类方法。
一些谷歌搜索让我相信这可能相当困难。delattr从__init__似乎没有工作。从 update 函数运行isclass(self)总是返回 True,因为当我们在类方法内部时,我们实际上是类而不是实例。
有什么建议么?
__getattribute__您可以像 Schwobaseggl 的答案一样自定义该类- 但您也可以使用自定义元类。
当我们在Python中提到“元类”时,人们通常会想到重写它的__new__方法并在类创建时(与实例创建时相反)做复杂的事情。但是,如果将所有特殊的 dunder ( __these__ __methods__) 放在一边,元克拉只是类的类 - 并且它的所有方法对于类本身都是可见的,但对于类的实例是不可见的。这意味着,当一个“dir”是实例时,它们不会显示,但当一个“dir”是类时,它们会显示 - 并且不能通过实例直接检索。(当然,尽管人们总是可以做到self.__class__.method)
此外,尽管元类因复杂性而名声不佳,但重写__getattribute__自身可能会存在一些陷阱。
在这种特定情况下,您想要保护的类已经使用元类 - 但这种特殊用途与“普通”元类用途不同,可以像普通类层次结构一样自由组合:
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? :-)
...
Run Code Online (Sandbox Code Playgroud)
(这应该是显而易见的,但是您不需要将元类中的方法声明为类方法:所有这些都是元类实例(即类)的类方法)
控制台上有一个快速演示:
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'
Run Code Online (Sandbox Code Playgroud)
Python 的classmethod装饰器,甚至普通的实例方法,实际上都使用了描述符协议:这些方法本身就是对象,有一个专门的__get__方法,在从实例或类中检索它们并相应地修改可调用对象时使用该方法。
因此,我们所要做的就是创建一个等效的对象classmethod,它将禁止从实例调用:
from functools import partial
class strict_classmethod:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
if instance is not None:
raise TypeError("This method cannot be called from instances")
return partial(self.func, owner)
class A:
@strict_classmethod
def secret(cls, ...):
...
Run Code Online (Sandbox Code Playgroud)
这是一个简单的实现,可以工作,但是修饰的方法仍然会出现在类的自省中dir- 但是,它足以避免错误调用。