Python我可以限制从

时间:2018-01-29 15:17:09

标签: python introspection

我有一个类和一个普通的构造函数但我希望预处理参数并对结果进行后处理,因此我提供了一个强制的Factory构造函数。是的,我知道这对于Factory来说是一个不寻常的意义,我也知道我可以使用memoization进行处理但是我在扩展memoized类时遇到了问题。

我希望防止自己意外使用普通的构造函数,这是一种方法。

import inspect

   class Foo():
       def __init__(self):
           actual_class_method = Foo.Factory
           # [surely there's a way to do this without introspection?]
           allowed_called_from = {name:method for name,method in inspect.getmembers(Foo, inspect.ismethod)}['Factory']

           actual_called_from = inspect.currentframe().f_back.f_code # .co_name)

           print("actual class method = ",actual_class_method," id = ",id(actual_class_method),",name = ",actual_class_method.__name__)
           print("allowed called from = ",allowed_called_from,", id = ",id(allowed_called_from),", name =",allowed_called_from.__name__)
           print()
           print("actual called from = ",actual_called_from,", id = ",id(actual_called_from),", name =",actual_called_from.co_name)
       @classmethod
       def Factory(cls):
           Foo()

   Foo.Factory()

产生输出

actual class method =  <bound method Foo.Factory of <class '__main__.Foo'>>  id =  3071817836 ,name =  Factory
allowed called from =  <bound method Foo.Factory of <class '__main__.Foo'>> , id =  3072138412 , name = Factory

actual called from =  <code object Factory at 0xb7118f70, file "/home/david/Projects/Shapes/rebuild-v0/foo.py", line 15> , id =  3071381360 , name = Factory

假设我希望检查Foo()的构造函数是否已从其Factory调用。我可以找到关于调用Foo()的方法的各种事情,例如它的名称和编译它的文件名,这就足以阻止我不小心直接调用它,但我看不出一种说法(调用 Foo()的方法(类 Foo 中的方法 Factory()) 。有没有办法做到这一点?

2 个答案:

答案 0 :(得分:0)

没有inspect,您可以为构造函数提供一个默认参数,并检查传递的值是否是您期望的值(默认值为0)

只有工厂有机会传递正确的初始化值(或某人真的想要调用构造函数,但不是偶然的)

class Foo():
    __MAGIC_INIT = 12345678
    def __init__(self,magic=0):
        if magic != self.__MAGIC_INIT:
            raise Exception("Cannot call constructor, use the factory")

    @classmethod
    def Factory(cls):
       return Foo(magic=Foo.__MAGIC_INIT)

f = Foo.Factory()   # works

f = Foo()           # exception

另一种变化是切换私人&#34;锁定&#34;布尔值。如果设置为True,则在输入构造函数时会崩溃,否则让它完成其工作,然后重置为True

当然,该因子可以访问此布尔值,并可以在调用构造函数之前将其设置为False

class Foo():
    __FORBID_CONSTRUCTION = True
    def __init__(self):
        if self.__FORBID_CONSTRUCTION:
            raise Exception("Cannot call constructor, use the factory")
        Foo.__FORBID_CONSTRUCTION = True        # reset to True

    @classmethod
    def Factory(cls):
        Foo.__FORBID_CONSTRUCTION = False
        return Foo()

f = Foo.Factory()
print("OK")
f = Foo()
由于python GIL,即使多线程也不是问题。

答案 1 :(得分:0)

Alex Martelli发布了answer

这可能会让你得到你想要的东西:

class Foo:
    def __init__(self):
        print('Foo.__init__')  # might consider throwing an exception

    @classmethod 
    def makeit(cls):
        self = cls.__new__(cls)
        self.foo = 'foo'
        return self

f = Foo()    # accidentally create Foo in the usual way

g = Foo.makeit()  # use the 'One True Way' of making a Foo
print(g.foo)
print(f.foo)

输出:

Foo.__init__
foo
Traceback (most recent call last):
  File "D:\python\soMetaClassWorkAroundInit.py", line 19, in <module>
    print(f.foo)
AttributeError: 'Foo' object has no attribute 'foo'