Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python我可以限制从何处调用函数吗_Python_Introspection - Fatal编程技术网

Python我可以限制从何处调用函数吗

Python我可以限制从何处调用函数吗,python,introspection,Python,Introspection,我有一个类和一个普通构造函数,但我希望预处理参数和后处理结果,所以我提供了一个强制工厂构造函数。是的,我知道这对工厂来说是一个不寻常的意义,我也知道我可以使用memorization来进行处理,但我在扩展memorized类时遇到了问题 我希望防止自己意外使用普通构造函数,这是一种方法 import inspect class Foo(): def __init__(self): actual_class_method = Foo.Factory

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

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

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
actual class method=id=3071817836,name=Factory
允许从调用,id=3072138412,名称=工厂
实际调用自=,id=3071381360,name=Factory

假设我希望检查Foo()的构造函数是否已从其工厂调用。我可以找到有关调用Foo()的方法的各种信息,例如它的名称和编译它的文件名,这足以阻止我意外地直接调用它,但我看不到一种说法(调用Foo()的方法)(类Foo中的方法工厂()。有什么方法可以做到这一点吗?

如果不使用
inspect
,您可以向构造函数提供一个默认参数,并检查传递的值是否是您期望的值(默认值为0)

只有工厂才有机会通过正确的初始化值(或者有人真的想调用构造函数,但不是偶然的)

另一种变体是切换私有“锁定”布尔值。如果设置为
True
,则在进入构造函数时崩溃,否则让它执行其工作,然后重置为
True

当然,factor可以访问此布尔值,并且可以在调用构造函数之前将其设置为
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,即使多线程也不是问题。

Alex Martelli发布了一篇文章

这可能会满足您的需求:

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'
Foo.\uuu init__
福
回溯(最近一次呼叫最后一次):
文件“D:\python\sometClassWorkaroundinit.py”,第19行,在
印刷品(f.foo)
AttributeError:“Foo”对象没有属性“Foo”

我很困惑。根据您的输出,
actual\u从.co\u name==“Factory”
,所以看起来您已经准备好了所有的部分,就我而言,我不会费心阻止类的直接实例化。你能对你的实际用例进行一点扩展吗?这个问题:和答案有不同的方式来区分直接实例化类和通过“工厂”间接实例化类。@PaulH我知道它是从一个名为“工厂”的方法调用的,但这可能是一个完全不同的同名方法。我想检查一下名为'Factory'@brunodesshuilliers的/my/方法。我不想解释为什么我要这样做,因为原来的问题会丢失。基本上,Foo有一个参数,参数的每个值都有一个唯一的Foo。Factory方法检查给定参数是否已经存在foo,如果没有,则创建它,并返回预构造的对象。我知道这是类的备忘录(见brandizzi),但当我想通过类栏(Foo)扩展Foo时遇到了问题,最终放弃了。这个神奇的数字非常聪明,我可能会使用它。它不太符合要求,因为在过去的半小时里,我一直在试验一个工厂类,它自动添加工厂方法,并将Foo和Bar实现为Foo(工厂)和Bar(工厂)。后者和后者都有相同的幻数,所以我无法区分对Foo()的调用和对Foo.Factory()的调用(合法)和对Bar.Factory()中的Foo()的调用(非法),所以不要硬编码幻数。使用类名的散列。哦,是的,或者甚至可以只使用类名。事实上,我刚刚意识到我并不完全明白发生了什么。为什么工厂中的调用是“return Foo(Foo.\u MAGIC\u INIT)”而不是“return Foo(MAGIC=\u MAGIC\u INIT)”?这是一样的。按参数名称定位vs。
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'