Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.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_Python 3.x - Fatal编程技术网

Python 创建一个";“正常”;使用所有“静态”方法从类初始化

Python 创建一个";“正常”;使用所有“静态”方法从类初始化,python,python-3.x,Python,Python 3.x,从前,我写了一个单身班。该实现是一个仅由静态方法组成的类-我在\uuuuu init\uuuuu上添加了一个异常仅用于说明,我甚至没有\uuuuuu init\uuuu,但以后需要一个: class A: x = 3 def __init__(self): raise Exception('Oh no you did not!') @staticmethod def m1(): print(A.x) @staticmethod de

从前,我写了一个单身班。该实现是一个仅由静态方法组成的类-我在
\uuuuu init\uuuuu
上添加了一个异常仅用于说明,我甚至没有
\uuuuuu init\uuuu
,但以后需要一个:

class A:
    x = 3
    def __init__(self): raise Exception('Oh no you did not!')
    @staticmethod
    def m1():
        print(A.x)
    @staticmethod
    def m2(n):
        A.y=8
快进几年,现在我需要创建Singleton的实例-请不要判断:)。要求:

  • 我不能放弃单身版。我用了太多次,所以我不能重写它
  • 新类应该访问一个对象变量,而原来的类应该访问一个对象变量
  • 所有的
    staticmethod
    装饰程序都需要删除
  • 所有方法都需要一个额外的
    self
    参数
  • 需要定义
    \uuuu init\uuuu
    方法
  • 我不想复制粘贴并修复粘贴-该类很长,并且将受到未来更改的影响,这些更改应始终适用于两个版本,并遵守上述要求。因此,新版本的构建应该是动态的,并且依赖于原始版本(我已经把自己搞砸了,曾经没有提前思考)
  • 解决方案可能在原始类中实现,但我认为这可能是不可能的,因此,函数获取原始类并输出一个新类可能是可行的方法:

    class A:
        x = 3 #No need to touch class variable definitions. 
        def __init__(self): pass #Maybe the init method will be an argument
    
        def m1(self):
           print(self.x)
    
        def m2(self,n):
           self.y = n
    

    任何动态创建内容的解决方案(无论是否有黑客攻击)都可以。我目前正在考虑使用
    inspect
    来构建它,尽管我不确定它是否会成功。

    我不确定这是否足够,但我认为以下修改既可以用作原始单例,也可以用作普通类。有相当多的样板文件,但它是孤立于类的,而不是使用该类的代码

    class A:
    
        def __init__(self):
            pass
    
        def m1(*args):
            # A.m1() means args will be empty
            if args and isinstance(args[0], A):
                self = args[0]
            else:
                self = A
    
            print(self.x)
    
        def m2(*args):
            if isinstance(args[0], A):
                self, n = args
            else:
                self = A
                n = args[0]
    
            self.y = n
    
    基本上,您将对每个方法执行以下操作:

  • 去除
    staticmethod
    decorator
  • 将每个方法的参数列表替换为
    *args
  • 手动确定第一个参数(如果有)是否是A的实例。如果不是,则设置
    self=A
    ,否则设置
    self=args[0]
  • 根据步骤3中的内容,使用
    *args
    的适当元素手动为每个旧参数创建局部变量
  • 例如,
    A.m1()
    导致
    打印(A.x)
    ,而
    A=A();a、 mi()
    导致
    打印(a.x)
    。同样地,
    A.m2(8)
    A.y=8
    ,而
    A.m2(8)
    A.y=8


    我会犹豫是否尝试进一步自动化这一点;与手动更新每个方法相比,您可能会花费更多的时间来识别和尝试解决棘手的情况。

    我不确定这是否足够,但我认为以下修改既可以用作原始单例,也可以用作普通类。有相当多的样板文件,但它是孤立于类的,而不是使用该类的代码

    class A:
    
        def __init__(self):
            pass
    
        def m1(*args):
            # A.m1() means args will be empty
            if args and isinstance(args[0], A):
                self = args[0]
            else:
                self = A
    
            print(self.x)
    
        def m2(*args):
            if isinstance(args[0], A):
                self, n = args
            else:
                self = A
                n = args[0]
    
            self.y = n
    
    基本上,您将对每个方法执行以下操作:

  • 去除
    staticmethod
    decorator
  • 将每个方法的参数列表替换为
    *args
  • 手动确定第一个参数(如果有)是否是A的实例。如果不是,则设置
    self=A
    ,否则设置
    self=args[0]
  • 根据步骤3中的内容,使用
    *args
    的适当元素手动为每个旧参数创建局部变量
  • 例如,
    A.m1()
    导致
    打印(A.x)
    ,而
    A=A();a、 mi()
    导致
    打印(a.x)
    。同样地,
    A.m2(8)
    A.y=8
    ,而
    A.m2(8)
    A.y=8


    我会犹豫是否尝试进一步自动化这一点;与手动更新每个方法相比,您可能会花费更多的时间来识别和尝试解决棘手的问题。

    很难将所有副作用都只会影响类本身的静态单例类转换为只会影响实例对象的普通类。但也可以做相反的事情:只需使静态类拥有普通类的唯一实例并将其所有方法调用和属性访问委托给它,即可将普通类转换为单例静态类

    元类可以完成这项工作。这个函数创建一个特殊属性
    \u own
    来保存其模型类的实例,明确地为它创建具有适当签名的方法(它还保留docstring,如果有的话),只将调用委托给
    \u own
    ,并将所有属性访问委托给
    \u own

    import inspect
    
    class Singletoner(type):
        def __getattr__(self, attr):           # delegates attribute accesses
            return getattr(self._own, attr)
        def __new__(cls, name, bases, namespace, **kwds):
            obj = type.__new__(cls, name, bases, namespace)
            X = kwds['model']           # the model class is expected with the model keyword
            obj._own = X()
            for name, func in inspect.getmembers(X, inspect.isfunction):
                if name != '__init__':
                    _trans(name, func, obj)   # tranfers all methods other than __init__
            return obj
    
    def _trans(name, func, clazz):
        def f(*args,**kwargs):
                return func(clazz._own, *args, **kwargs)
        sig = inspect.signature(func)   # copy signature just removing the initial param
        parameters = sig.parameters
        params = [t[1] for t in list(sig.parameters.items())[1:]]
        f.__signature__ = sig.replace(parameters = params)
        f.__doc__ = func.__doc__
        setattr(clazz, name, f)
    
    在您的示例中,非单例类将是b:

    class A:
        x = 3
        def __init__(self): pass
        def m1(self):
            print(self.x)
        def m2(self, n):
            self.y=n
    
    其单一委托人可声明为:

    class B(metaclass=Singletoner, model=A):
        pass
    
    您可以简单地使用它:

    >>> B.m1()
    3
    >>> B.m2(6)
    >>> B.x
    3
    >>> B.y
    6
    >>> import inspect
    >>> print(inspect.signature(B.m2))
    (n)
    >>> print(inspect.signature(B.m1))
    ()
    

    很难将所有副作用只能影响类本身的静态单例类转换为只影响实例对象的普通类。但也可以做相反的事情:只需使静态类拥有普通类的唯一实例并将其所有方法调用和属性访问委托给它,即可将普通类转换为单例静态类

    元类可以完成这项工作。这个函数创建一个特殊属性
    \u own
    来保存其模型类的实例,明确地为它创建具有适当签名的方法(它还保留docstring,如果有的话),只将调用委托给
    \u own
    ,并将所有属性访问委托给
    \u own

    import inspect
    
    class Singletoner(type):
        def __getattr__(self, attr):           # delegates attribute accesses
            return getattr(self._own, attr)
        def __new__(cls, name, bases, namespace, **kwds):
            obj = type.__new__(cls, name, bases, namespace)
            X = kwds['model']           # the model class is expected with the model keyword
            obj._own = X()
            for name, func in inspect.getmembers(X, inspect.isfunction):
                if name != '__init__':
                    _trans(name, func, obj)   # tranfers all methods other than __init__
            return obj
    
    def _trans(name, func, clazz):
        def f(*args,**kwargs):
                return func(clazz._own, *args, **kwargs)
        sig = inspect.signature(func)   # copy signature just removing the initial param
        parameters = sig.parameters
        params = [t[1] for t in list(sig.parameters.items())[1:]]
        f.__signature__ = sig.replace(parameters = params)
        f.__doc__ = func.__doc__
        setattr(clazz, name, f)
    
    在您的示例中,非单例类将是b:

    class A:
        x = 3
        def __init__(self): pass
        def m1(self):
            print(self.x)
        def m2(self, n):
            self.y=n
    
    其单一委托人可声明为:

    class B(metaclass=Singletoner, model=A):
        pass
    
    您可以简单地使用它:

    >>> B.m1()
    3
    >>> B.m2(6)
    >>> B.x
    3
    >>> B.y
    6
    >>> import inspect
    >>> print(inspect.signature(B.m2))
    (n)
    >>> print(inspect.signature(B.m1))
    ()
    

    对我来说,最大的问题似乎是让方法调用
    self.x
    而不是
    A.x
    这将是一个愚蠢的想法,但是你说黑客修复是可以的,所以我们可以备份