Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.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 2.7_Inheritance_Class Method - Fatal编程技术网

Python—为什么我可以用实例调用类方法?

Python—为什么我可以用实例调用类方法?,python,python-2.7,inheritance,class-method,Python,Python 2.7,Inheritance,Class Method,我是Python新手,读了一些书之后,在我的自定义类方法中创建了一些方法,而不是实例方法 因此,我测试了我的代码,但我没有更改一些方法调用来调用类中的方法,而不是实例中的方法,但它们仍然有效: class myClass: @classmethod: def foo(cls): print 'Class method foo called with %s.'%(cls) def bar(self): print 'Instance method bar

我是Python新手,读了一些书之后,在我的自定义类方法中创建了一些方法,而不是实例方法

因此,我测试了我的代码,但我没有更改一些方法调用来调用类中的方法,而不是实例中的方法,但它们仍然有效:

class myClass:
   @classmethod:
   def foo(cls):
      print 'Class method foo called with %s.'%(cls)

   def bar(self):
      print 'Instance method bar called with %s.'%(self)

myClass.foo()
thing = myClass()
thing.foo()
thing.bar()
这将产生:

class method foo called with __main__.myClass.
class method foo called with __main__.myClass.
instance method bar called with <__main__.myClass instance at 0x389ba4>.
然后我得到:

TypeError: unbound method bar() must be called with myClass instance...

这很有道理。

您可以在实例上调用它,因为
@classmethod
是一个函数(它将函数作为参数并返回一个新函数)

下面是Python中的一些相关信息

可以在类(例如C.f())或实例上调用它 (例如C().f())。实例被忽略,但其类除外。如果 为派生类(派生类对象)调用类方法 作为隐含的第一个参数传递


关于
@classmethod
,也有相当多的SO讨论

让我们从描述符协议的快速概述开始。如果一个类定义了一个
\uuuuu get\uuuu
方法,那么该类的一个实例就是一个描述符。将描述符作为另一个对象的属性进行访问会生成
\uuuu get\uuuu
方法的返回值,而不是描述符本身

函数是一个描述符;这就是实例方法的实现方式。给定

class myClass:
    @classmethod:
    def foo(cls):
        print('Class method foo called with %s.' % (cls,))

    def bar(self):
        print 'Instance method bar called with %s.'%(self)

c = myClass()
表达式
c.bar
相当于

myClass.__dict__['bar'].__get__(c, myClass)
而表达式
myClass.bar
与表达式

myClass.__dict__['bar'].__get__(None, myClass)
请注意,唯一的区别在于作为第一个参数传递给
\uuuu get\uuuu
的对象。前者返回一个新的
方法
对象,调用该对象时将
c
及其自身参数传递给函数
bar
。这就是为什么
c.bar()
c.bar(c)
是等效的。后者只返回函数
bar
本身

classmethod
是一种类型,它提供了
\uuuu get\uuuu
的不同实现。这意味着
c.foo()
myClass.foo()
调用
\uuuu get\uuuu
与前面一样:

# c.foo
myClass.__dict__['foo'].__get__(c, myClass)

# myClass.foo
myClass.__dict__['foo'].__get__(None, myClass)
但是,现在两个调用都返回相同的
方法
对象,当调用此
方法
对象时,将
myClass
作为第一个参数传递给原始的
函数
对象。也就是说,
c.foo()
相当于
myClass.foo()
,它
相当于
x(myClass)
(其中
x
是装饰之前定义的原始函数,将名称
foo
绑定到
classmethod
)的一个实例。

谢谢-我对继承、classmethods等进行了各种搜索,但正如您可以想象的那样,结果令人难以接受。我很乐意接受它的工作原理,但作为一名汇编程序员,我想知道它是如何工作的。“你可以在一个实例上调用它,因为@classmethod是一个decorator”--我不遵循这个逻辑。@Alexey你知道什么是decorator吗?是的。但是我相信我可以制作一个decorator,这样被修饰的函数将生成一个class属性,如果作为实例方法调用,它将引发错误(事实上,它根本不可调用)。例如:
defdecor(f):返回42
。从技术上讲,
classmethod
是一种类型;调用它会返回
类方法的实例,而不是函数。在Python中,方法不会被调用
thing.foo
不是一个方法调用,它是一个属性访问,它基本上与
getattr(thing,“foo”)
@Alexey'foo`是一个方法,
thing.foo()
正在调用对象
thing
方法?属性不是Python术语中其他语言所指的变量或属性吗?我认为“
(thing.foo)(
调用对象的
foo
方法
thing
”(括号表示清楚)是“
(thing.foo)(
调用可调用对象
thing.foo
”的隐喻,就是这样。首先,这个对象是在调用
getattr(thing,“foo”)
时动态创建的,当然它有一个对
thing
对象的引用。请注意由其类定义的对象“属性”和对象本身“存储”的属性之间的区别。因为如果你有一个函数(或任何对象/值)
bar
,你可以写
thing.foo=bar
,然后调用它
thing.foo()
,如果
bar
是可调用的。在本例中,
thing.foo
返回的对象实际上存储在dictionary
thing.\uuuu dict\uuuu
中,并且不是动态生成的,正如我认为“实例方法”被定义为类定义的一部分一样。“属性不是其他语言称为变量或属性的Python术语吗?”--根据我对Python的实验,Python通过允许使用attribute getter和setter来发挥其作用。“魔法”发生在您写入或读取属性时。属性不仅仅是记录字段:使用它们可以触发任意代码。看到
\uuuuu\uuuuu\uuuuu
实现有助于完整描述。虽然我不确定为什么
cls
被传递给
self.method
而不是
instance
,为什么
instance
没有被使用,这是出于设计。类方法总是接收一个类作为其第一个参数。如果从类中调用它,则得到该类。如果从类的实例调用它,则会得到该实例的类型。
# c.foo
myClass.__dict__['foo'].__get__(c, myClass)

# myClass.foo
myClass.__dict__['foo'].__get__(None, myClass)