Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.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_Decorator_Class Method - Fatal编程技术网

Python 创建一个同时是类方法和实例方法的方法

Python 创建一个同时是类方法和实例方法的方法,python,decorator,class-method,Python,Decorator,Class Method,Python中是否有一种方法可以定义一个同时是类方法和实例方法的方法,这样cls和self都是接收者。特别是,我希望创建一个方法:(1)知道在类上调用它时调用了哪个类(Foo.method(value)),以及(2)知道在实例上调用它时调用了哪个实例(Foo.method()) 例如,我会设想这样的工作: class Foo: def __str__(self): return 'Foo()' @classinstancemethod def method(cls, s

Python中是否有一种方法可以定义一个同时是类方法和实例方法的方法,这样
cls
self
都是接收者。特别是,我希望创建一个方法:(1)知道在类上调用它时调用了哪个类(
Foo.method(value)
),以及(2)知道在实例上调用它时调用了哪个实例(
Foo.method()

例如,我会设想这样的工作:

class Foo:
    def __str__(self): return 'Foo()'

    @classinstancemethod
    def method(cls, self):
        print(cls, self)

class Bar(Foo):
    def __str__(self): return 'Bar()'

Foo().method()     # <class '__main__.Foo'> Foo()
Bar().method()     # <class '__main__.Bar'> Bar()
Foo.method(Foo())  # <class '__main__.Foo'> Foo()
Foo.method(Bar())  # <class '__main__.Foo'> Bar()
Bar.method(Foo())  # <class '__main__.Bar'> Foo()
Foo类:
定义str(self):返回'Foo()'
@分类安装方法
def方法(cls,自我):
打印(cls,自我)
分类栏(Foo):
定义str(self):返回'Bar()'
Foo().method()#Foo()
Bar().method()#Bar()
方法(Foo())#Foo()
Foo.method(Bar())#Bar()
方法(Foo())#Foo()

注意,我知道可以像
Foo.Foo(value)
那样调用未修饰的方法,但这不是我想要的,因为它没有得到
cls
变量。如果没有
cls
变量,方法就不知道刚刚调用了哪个类。它可能被称为
Bar.method(value)
,现在可以知道如果
value
Foo
的一个实例。未修饰的方法更像是静态方法和实例方法,而不是类方法和实例方法。

这不需要装饰器。这就是方法已经起作用的方式;实例作为第一个参数传递—从实例调用方法时隐式传递,从类显式传递—实例可用时,您可以通过调用实例上的
type
来检索类:

class Foo(object):
    def __repr__(self): return 'Foo()'

    def method(self):
        print((type(self), self)) 

class Bar(Foo):
    def __repr__(self): return 'Bar()'
另一方面,在
\uuu str\uu
(或
\uu repr\uu
)特殊方法中,您应该返回字符串,而不是打印

我使用了
\uuuu repr\uuuu
,因为在容器对象(这里的元组)中打印实例时不调用
\uuu str\uuuu

更新

考虑到上述方法中的类/实例打印问题,您可以使用描述符来正确管理方法中的正确类和实例选择:

class classinstancemethod():

  def __get__(self, obj, cls):
     def method(inst=None):
        print(cls, inst if inst else obj)
     return method

class Foo(object):
    method = classinstancemethod()

    def __str__(self): return 'Foo()'


class Bar(Foo):
    def __str__(self): return 'Bar()'

你不需要一个装饰师。这就是方法已经起作用的方式;实例作为第一个参数传递—从实例调用方法时隐式传递,从类显式传递—实例可用时,您可以通过调用实例上的
type
来检索类:

class Foo(object):
    def __repr__(self): return 'Foo()'

    def method(self):
        print((type(self), self)) 

class Bar(Foo):
    def __repr__(self): return 'Bar()'
另一方面,在
\uuu str\uu
(或
\uu repr\uu
)特殊方法中,您应该返回字符串,而不是打印

我使用了
\uuuu repr\uuuu
,因为在容器对象(这里的元组)中打印实例时不调用
\uuu str\uuuu

更新

考虑到上述方法中的类/实例打印问题,您可以使用描述符来正确管理方法中的正确类和实例选择:

class classinstancemethod():

  def __get__(self, obj, cls):
     def method(inst=None):
        print(cls, inst if inst else obj)
     return method

class Foo(object):
    method = classinstancemethod()

    def __str__(self): return 'Foo()'


class Bar(Foo):
    def __str__(self): return 'Bar()'

这可以通过将
classinstancemethod
作为自定义实现来解决

简而言之,描述符必须定义一个在作为属性访问时将被调用的方法(如
Foo.method
Foo().method
)。此方法将作为参数传递实例和类,并返回绑定方法(即,它返回一个包含
cls
self
参数的方法)。调用此绑定方法时,它将烘焙的
cls
self
参数转发给实际方法

class classinstancemethod:
    def __init__(self, method, instance=None, owner=None):
        self.method = method
        self.instance = instance
        self.owner = owner

    def __get__(self, instance, owner=None):
        return type(self)(self.method, instance, owner)

    def __call__(self, *args, **kwargs):
        instance = self.instance
        if instance is None:
            if not args:
                raise TypeError('missing required parameter "self"')
            instance, args = args[0], args[1:]

        cls = self.owner
        return self.method(cls, instance, *args, **kwargs)

结果:

class Foo:
    def __repr__(self): return 'Foo()'

    @classinstancemethod
    def method(cls, self):
        print((cls, self))


class Bar(Foo):
    def __repr__(self): return 'Bar()'


Foo().method()     # (<class '__main__.Foo'>, 'Foo()')
Bar().method()     # (<class '__main__.Bar'>, 'Bar()')
Foo.method(Foo())  # (<class '__main__.Foo'>, 'Foo()')
Foo.method(Bar())  # (<class '__main__.Foo'>, 'Bar()')
Bar.method(Foo())  # (<class '__main__.Bar'>, 'Foo()')
Foo类:
def _repr _(self):返回'Foo()'
@分类安装方法
def方法(cls,自我):
打印((cls,自我))
分类栏(Foo):
def _repr _(self):返回'Bar()'
Foo().method()#(,'Foo()'))
Bar().method()#(,'Bar()'))
方法(Foo())#(,'Foo()'))
Foo.method(Bar())#(,'Bar()'))
Bar.method(Foo())#(,'Foo()'))

这可以通过将
classinstancemethod
作为自定义实现来解决

简而言之,描述符必须定义一个在作为属性访问时将被调用的方法(如
Foo.method
Foo().method
)。此方法将作为参数传递实例和类,并返回绑定方法(即,它返回一个包含
cls
self
参数的方法)。调用此绑定方法时,它将烘焙的
cls
self
参数转发给实际方法

class classinstancemethod:
    def __init__(self, method, instance=None, owner=None):
        self.method = method
        self.instance = instance
        self.owner = owner

    def __get__(self, instance, owner=None):
        return type(self)(self.method, instance, owner)

    def __call__(self, *args, **kwargs):
        instance = self.instance
        if instance is None:
            if not args:
                raise TypeError('missing required parameter "self"')
            instance, args = args[0], args[1:]

        cls = self.owner
        return self.method(cls, instance, *args, **kwargs)

结果:

class Foo:
    def __repr__(self): return 'Foo()'

    @classinstancemethod
    def method(cls, self):
        print((cls, self))


class Bar(Foo):
    def __repr__(self): return 'Bar()'


Foo().method()     # (<class '__main__.Foo'>, 'Foo()')
Bar().method()     # (<class '__main__.Bar'>, 'Bar()')
Foo.method(Foo())  # (<class '__main__.Foo'>, 'Foo()')
Foo.method(Bar())  # (<class '__main__.Foo'>, 'Bar()')
Bar.method(Foo())  # (<class '__main__.Bar'>, 'Foo()')
Foo类:
def _repr _(self):返回'Foo()'
@分类安装方法
def方法(cls,自我):
打印((cls,自我))
分类栏(Foo):
def _repr _(self):返回'Bar()'
Foo().method()#(,'Foo()'))
Bar().method()#(,'Bar()'))
方法(Foo())#(,'Foo()'))
Foo.method(Bar())#(,'Bar()'))
Bar.method(Foo())#(,'Foo()'))

不,那是错的
Foo.method(Bar())
应该输出
(,'Bar()')
,但是您的输出
(,'Bar()'))
@aranfey谢谢您的注意。他们可以在Python3中使用隐藏的
\uuuuu class\uuuuu
变量,而不是
类型(self)
。这也不符合预期。如果您使用
\uuuu class\uuuu
,那么它将始终返回
Foo
作为类。我在最后一段中预期了此解决方案。这不是我要寻找的,因为当它像
Bar.method(Foo())
那样被调用时,
method
不知道它的接收者是
Bar
类。这些信息已经丢失了。@Aran Fey已经在做描述性的回答,试图回答你的评论,谢谢你的眼睛。不,那是错误的
Foo.method(Bar())
应该输出
(,'Bar()')
,但是您的输出
(,'Bar()'))
@aranfey谢谢您的注意。他们可以使用