Python—为什么我可以用实例调用类方法?
我是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
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
返回的对象实际上存储在dictionarything.\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)