方法
Python
函数

python中的函数和方法有什么区别? ?

有明白的大神跟通俗的指导一下吗?
关注者
35
被浏览
112,572

22 个回答

1. 哪些是函数?哪些是方法?

很多人认为函数和方法是一回事,只不过叫法不同而已,但其实在Python 3中对函数和方法进行了区分。以如下代码为例,主要分了三种情况:

  • 直接独立定义的叫函数;
  • 在类里面定义的,又分两种情况:
    • 通过类名直接调用,还是函数;
    • 通过实例化以后调用的,就成了方法(这里有一个特例,稍后讲)。
from types import MethodType, FunctionType

def foo():
    return 

class MyClass:
    def foo():
        return 

# foo是函数
print(isinstance(foo, MethodType))          # output: False
print(isinstance(foo, FunctionType))        # output: True

# MyClass.foo也是函数
print(isinstance(MyClass.foo, MethodType))  # output: False
print(isinstance(MyClass.foo, FunctionType)) # output: True

# 但是mycls.foo是方法
mycls = MyClass()
print(isinstance(mycls.foo, MethodType))    # output: True
print(isinstance(mycls.foo, FunctionType))  # output: False

2. 函数和方法有什么区别?

讲了这么多,到底有什么区别呢?函数是可以独立存在的个体,所有的参数都是显式传递的;而方法和实例化的对象严格绑定,同时在使用时会隐式传递一个实例化的对象。听起来很拗口,我们来看一个例子:

# foo.py

def foo(arg):
    print(“”arg)

class MyClass:
    def foo(arg):
        print(arg)

mycls = MyClass()

foo("foo")                  # 猜猜会怎样?
MyClass.foo("MyClass.foo")  # 猜猜会怎样?
mycls.foo("obj.foo")        # 猜猜会怎样?

猜猜这段代码的输出结果是什么?结果如下图所示:

执行结果

可以发现foo和MyClass.foo都正常,但是mycls.foo出错,console提示多给了一个参数?这个参数是什么呢?其实就是隐式传递的mycls它自己。如果把代码改成如下情况,就一切正常了。

class MyClass:
    def foo(self, arg):    # 注意这里加了self
        print(arg)

mycls = MyClass()
mycls.foo("obj.foo")

3. 一个特殊情况:静态方法

在上面提到了,类里面定义的有一种特殊情况,这种特殊情况就是静态方法。如下所示,静态方法无论通过什么方法调用,都是函数,函数的调用过程中也没有隐式传递。

from types import MethodType, FunctionType

class MyClass:
    @staticmethod
    def foo(arg):
        print(arg)

# MyClass.foo也是函数
print(isinstance(MyClass.foo, MethodType))  # output: False
print(isinstance(MyClass.foo, FunctionType)) # output: True

# 但是mycls.foo是方法
mycls = MyClass()
print(isinstance(mycls.foo, MethodType))    # output: False
print(isinstance(mycls.foo, FunctionType))  # output: True

# 均可以直接调用,没有隐式传递
MyClass.foo("MyClass.foo")
mycls.foo("obj.foo")

发布于 2022-03-26 12:04

实例化出来的去调用,叫做方法。

直接使用类名去调用,叫做函数。

from types import MethodType,FunctionType
class Foo(object):
 def __init__(self):
         self.name="haiyan"
 def func(self):
         print(self.name)
obj = Foo()
print(isinstance(obj.func,FunctionType))  #False
print(isinstance(obj.func,MethodType))   #True   #说明这是一个方法

print(isinstance(Foo.func,FunctionType))  #True   #说明这是一个函数
print(isinstance(Foo.func,MethodType))  #False
注意,这只是在 python3 中才有的区分,python2 中全部称为方法。

发布于 2021-01-14 18:08

不请自来

方法就是属于对象的函数

你可以试试分别打印type(some_class.method)和type(some_object.method)

你会发现前一个是函数,后一个就成了方法

实际上当类实例化时,会把对象本身当做参数(self)传进函数,并返回一个新的函数,这个新函数就叫方法

方法其实可以当成某个内置装饰器的产物,你看静态方法和类方法也是用装饰器定义的,都是一个道理

编辑于 2019-03-25 18:41

函数和方法本质都是对一段功能的抽象。

欢迎关注我的知乎账号 @黄哥

类是抽象数据类型具体实现,类是属性 + 方法组成。

类中的实例方法 和 函数区别,方法第一个参数是默认的self。

编辑于 2021-08-27 18:17

简单介绍一下:

函数(FunctionType)

函数是封装了一些独立的功能,可以直接调用,能将一些数据(参数)传递进去进行处理,然后返回一些数据(返回值),也可以没有返回值。可以直接在模块中进行定义使用。

所有传递给函数的数据都是显式传递的。

方法(MethodType)

方法和函数类似,同样封装了独立的功能,但是方法是只能依靠类或者对象来调用的,表示针对性的操作。
方法中的数据self和cls是隐式传递的,即方法的调用者;
方法可以操作类内部的数据

简单的说,函数在python中独立存在,可直接使用的,而方法是必须被别人调用才能实现的。
静态方法除外(与类和对象均无关,通过类名和对象名均可被调用,属函数)

Python的内置函数自成一派,属BuiltinFunctionType

class BuiltinFunctionType:
    __self__ = ...  # type: Union[object, ModuleType]
    __name__ = ...  # type: str
    __qualname__ = ...  # type: str
    def __call__(self, *args: Any, **kwargs: Any) -> Any: ...
BuiltinMethodType = BuiltinFunctionType

验证类型的最好办法就是isinstance(), 也可以使用type(),当然实际开发中最好使用前者,效率更高,毕竟一个是方法一个是类;一个针对性更强,一个需要对类型逐一检索匹配

如果想具体的学一下课程,推荐以下教程,从零基础开始学习,小白从入门到精通:

发布于 2021-01-18 15:57

基本没啥区别,特别是在python3里面


# 这是python2
>>> class C:
...   def foo():
...     pass
... 
>>> C.foo
<unbound method C.foo>
>>> C.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with C instance as first argument (got nothing instead)

可以看到 python2 里面,方法必须要指定一个参数的;


# Python 3代码
>>> class C:
...    def foo():
...      pass
...    def bar(*args):
...      print(args)
...
>>> C.bar()
()
>>> C.bar(1)        # 以 类去调用的时候,和普通函数没有区别
(1,)
>>> C().bar         # 以 实例去调用的时候,实例作为第一个参数
<bound method C.bar of <__main__.C object at 0x000001D30B76F940>>
>>> C.bar           # 注意和Python 2 的区别
<function C.bar at 0x000001D30B767D90>
>>> a = C()
# 注意下面两种调用方法的效果是一样的,a 都是作为第一个参数传入
>>> a.bar()
(<__main__.C object at 0x000001D30B76F978>,)
>>> C.bar(a)
(<__main__.C object at 0x000001D30B76F978>,)

# 写个函数,替换类的方法也是可以的
>>> def foo(*args):
...    print("foo", args)
...
>>> C.foo = foo
>>> C.foo()
foo ()
>>> C.foo(1)
foo (1,)
>>> C().foo(1)
foo (<__main__.C object at 0x000001D30B76F898>, 1)
>>> a
<__main__.C object at 0x000001D30B76F978>
>>> a.foo
<bound method foo of <__main__.C object at 0x000001D30B76F978>>
>>> a.foo()
foo (<__main__.C object at 0x000001D30B76F978>,)
>>>

发布于 2019-03-25 14:02

区别:定义位置、定义方式、调用方式

1、定义位置

函数:Python的函数是直接写在Python模块中的,即在.py文件中直接定义。

方法:只能定义在class类中

2、定义方式

函数:函数定义的方式 def关键字 然后接函数名 再是括号 括号里面写形参也可以省略不写形参

方法:方法定义的方式, 首先方法是定义在类中的,其他大体和函数定义差不多,这里需要注意的一点就是方法必须带一个默认参数self(静态方法除外)

3、调用方式

函数:直接使用函数名(参数1,参数2,…)调用

方法:方法是通过对象点方法调用的(这里是指对象方法)

注意:静态方法除外,可以不传递第一个self参数

最后附赠一套Python编程8天快速入门的教程,希望对你学习Python有帮助!

发布于 2020-12-21 16:25

class中的函数 (单身女子) ,在把某instance作为self传参进去后,只愿作该instance的方法(女友) (不再是FunctionType, 但文档说,A method is a function that “belongs to” an object)

A method is a function that “belongs to” an object.

(In Python, the term method is not unique to class instances: other object types can have methods as well.

For example, list objects have methods called append, and so on)


例子:

str类

str类的lower函数

str.lower()

s = [ 'I' , 'am', 'a', 'Boy']       

s=sorted(s,key=str.lower() )  多出了(), 提示TypeError: lower() missing 1 required positional argument: 'self'
# 方法第一个参数是默认的self。

#应为
 s=sorted(s,key=str.lower )

sorted(iterable, key=某函数, reverse=reverse)

ss=‘I am here'
ss.lower() 等价于
str.lower(ss)
实例名.方法名() 等价于 类名.函数名(实例名) ps:函数名和方法名写起来一样


When a non-data attribute of an instance is referenced, the instance’s class is searched.

If the name denotes a valid class attribute that is a function object,a method object is created as an abstract object

packing (pointers to) the instance object and the function object just found together

类在实例化时,调用_init_

这里后面没看

Data attributes may be referenced by methods as well as by ordinary users (“clients”) of an object.

9. Classes - Python 3.9.4 documentation


梁大炮:如何理解python中一切皆对象呢?看type,object,class的关系

编辑于 2021-05-01 08:39

Python中方法 和 函数 的区别:

先来看两个定义吧:

function(函数) —— A series of statements which returns some value toa caller. It can also be passed zero or more arguments which may beused in the execution of the body.
method(方法) —— A function which is defined inside a class body. Ifcalled as an attribute of an instance of that class, the methodwill get the instance object as its first argument (which isusually called self).


从上面可以看出, 别的编程语言一样, Function也是包含一个函数头和一个函数体, 也同样支持0到n个形参,而Method则是在function的基础上, 多了一层类的关系, 正因为这一层类, 所以区分了 functionmethod.而这个过程是通过 PyMethod_New实现的


PyObject *
PyMethod_New(PyObject *func, PyObject *self, PyObject *klass)
{
register PyMethodObject *im; // 定义方法结构体
im = free_list;
if (im != NULL) {
free_list = (PyMethodObject *)(im->im_self);
PyObject_INIT(im, &PyMethod_Type); // 初始化
numfree--;
}
else {
im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
if (im == NULL)
return NULL;
}
im->im_weakreflist = NULL;
Py_INCREF(func);

/* 往下开始通过 func 配置 method*/
im->im_func = func;
Py_XINCREF(self);
im->im_self = self;
Py_XINCREF(klass);
im->im_class = klass;
_PyObject_GC_TRACK(im);
return (PyObject *)im;


所以本质上, 函数和方法的区别是: 函数是属于 FunctionObject, 而 方法是属 PyMethodObject


简单来看下代码:


def aa(d, na=None, *kasd, **kassd):
pass
class A(object):
def f(self):
return 1
a = A()
print '#### 各自方法描述 ####'
print '## 函数 %s' % aa
print '## 类方法 %s' % A.f
print '## 实例方法 %s' % a.f


输出结果:


#### 各自方法描述 ####
## 函数 <function aa at 0x000000000262AB38>
## 类方法 <unbound method A.f>
## 实例方法 <bound method A.f of <__main__.A object at 0x0000000002633198>>


Bound Method 和 Unbound Method


method 还能再分为 Bound Method 和 Unbound Method, 他们的差别是什么呢? 差别就是 Bound method 多了一个实例绑定的过程!


A.f 是 unbound method, 而 a.f 是 bound method, 从而验证了上面的描述是正确的!


看到这, 我们应该会有个问题:


方法的绑定, 是什么时候发生的? 又是怎样的发生的?


带着这个问题, 我们继续探讨.很明显, 方法的绑定, 肯定是伴随着class的实例化而发生,我们都知道, 在class里定义方法, 需要显示传入self参数, 因为这个self是代表即将被实例化的对象。


我们需要dis模块来协助我们去观察这个绑定的过程:


[root@iZ23pynfq19Z ~]# cat 33.py
class A(object):
def f(self):
return 123
a = A()
print A.f()
print a.f()

## 命令执行 ##
[root@iZ23pynfq19Z ~]# python -m dis 33.py
1 0 LOAD_CONST 0 ('A')
3 LOAD_NAME 0 (object)
6 BUILD_TUPLE 1
9 LOAD_CONST 1 (<code object A at 0x7fc32f0b5030, file "33.py", line 1>)
12 MAKE_FUNCTION 0
15 CALL_FUNCTION 0
18 BUILD_CLASS
19 STORE_NAME 1 (A)

4 22 LOAD_NAME 1 (A)
25 CALL_FUNCTION 0
28 STORE_NAME 2 (a)

5 31 LOAD_NAME 1 (A)
34 LOAD_ATTR 3 (f)
37 CALL_FUNCTION 0
40 PRINT_ITEM
41 PRINT_NEWLINE

6 42 LOAD_NAME 2 (a)
45 LOAD_ATTR 3 (f)
48 CALL_FUNCTION 0
51 PRINT_ITEM
52 PRINT_NEWLINE
53 LOAD_CONST 2 (None)
56 RETURN_VALUE


dis输出说明: 第一列是代码的函数, 第二列是指令的偏移量, 第三列是可视化指令, 第四列是参数, 第五列是指令根据参数计算或者查找的结果
咱们可以看到 第4列 和第五列, 分别就是对应: print A.f() 和 print a.f()


他们都是同样的字节码, 都是从所在的codeobject中的co_name取出参数对应的名字, 正因为参数的不同, 所以它们分别取到 A 和 a,下面我们需要来看看 LOAD_ATTR 的作用是什么:


//取自: python2.7/objects/ceval.c
TARGET(LOAD_ATTR)
{
w = GETITEM(names, oparg); // 从co_name 取出 f
v = TOP(); // 将刚才压入栈的 A/a 取出来
x = PyObject_GetAttr(v, w); // 取得真正的执行函数
Py_DECREF(v);
SET_TOP(x);
if (x != NULL) DISPATCH();
break;
}


通过 SET_TOP, 已经将我们需要真正执行的函数压入运行时栈, 接下来就是通过 CALL_FUNCTION 来调用这个函数对象, 继续来看看具体过程:


//取自: python2.7/objects/ceval.c
TARGET(CALL_FUNCTION)
{
PyObject **sp;
PCALL(PCALL_ALL);
sp = stack_pointer;
#ifdef WITH_TSC
x = call_function(&sp, oparg, &intr0, &intr1);
#else
x = call_function(&sp, oparg); // 细节请往下看
#endif
stack_pointer = sp;
PUSH(x);
if (x != NULL) DISPATCH();
break;
}

static PyObject *
call_function(PyObject ***pp_stack, int oparg)
{
int na = oparg & 0xff; // 位置参数个数
int nk = (oparg>>8) & 0xff; // 关键位置参数的个数
int n = na + 2 * nk; // 总的个数和
PyObject **pfunc = (*pp_stack) - n - 1; // 当前栈位置-参数个数,得到函数对象
PyObject *func = *pfunc;
PyObject *x, *w;
... // 省略前面细节, 只看关键调用
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
/* optimize access to bound methods */
PyObject *self = PyMethod_GET_SELF(func);
PCALL(PCALL_METHOD);
PCALL(PCALL_BOUND_METHOD);
Py_INCREF(self);
func = PyMethod_GET_FUNCTION(func);
Py_INCREF(func);
Py_SETREF(*pfunc, self);
na++;
n++;
} else
Py_INCREF(func);
READ_TIMESTAMP(*pintr0);
if (PyFunction_Check(func))
x = fast_function(func, pp_stack, n, na, nk);
else
x = do_call(func, pp_stack, na, nk);
READ_TIMESTAMP(*pintr1);
Py_DECREF(func);
}


咱们来捋下调用顺序:


CALL_FUNCTION -> call_function -> 根据函数的类型 -> 执行对应的操作


当程序运行到call_function时, 主要有的函数类型判断有: PyCFunction, PyMethod, PyFunction


在这里, 虚拟机已经判断出func是不属于PyCFunction, 所以将会落入上面源码的判断分支中, 而它将要做的,就是分别通过 PyMethod_GET_SELF, PyMethod_GET_FUNCTION 获得self对象和func函数, 然后通过调用 Py_SETREF(*pfunc, self):


// Py_SETREF 定义如下
#define Py_SETREF(op, op2)
do {
PyObject *_py_tmp = (PyObject *)(op);
(op) = (op2);
Py_DECREF(_py_tmp);
} while (0)


可以看出, Py_SETREF是用这个self对象替换了pfunc指向的对象了, 而pfunc在上面已经提及到了, 就是当时压入运行时栈的函数对象. 除了这几步, 还有更重要的就是, na 和 n 都分别自增1


看回上面的 a.f(), 咱们可以知道, 它是不需要参数的, 所以理论上 na,nk和n都是0, 但是因为f是method(方法), 经过上面一系列操作, 它将会传入一个self,而na也会变成1, 又因为*pfunc已经被替换成self, 相应代码:


if (PyFunction_Check(func))
x = fast_function(func, pp_stack, n, na, nk);
else
x = do_call(func, pp_stack, na, nk);


所以它不再进入function的寻常路了, 而是走do_call, 然后就开始真正的调用;


其实这个涉及到Python调用函数的整个过程, 因为比较复杂, 后期找个时间专门谈谈这个


聊到这里, 我们已经大致清楚, 一个method(方法) 在调用时所发生的过程.明白了函数和方法的本质区别, 那么回到主题上 来说下 Unbound 和 Bound, 其实这两者差别也不大. 从上面我们得知, 一个方法的创建, 是需要self, 而调用时, 也会使用self,而只有实例化对象, 才有这个self, class是没有的, 所以像下面的执行, 是失败的额


class A(object):
def f(self):
return 1
a = A()

print '#### 各自方法等效调用 ####'
print '## 类方法 %s' % A.f()
print '## 实例方法 %s' % a.f()

## 输出结果 ##
#### 各自方法等效调用 ####
Traceback (most recent call last):
File "C:/Users/Administrator/ZGZN_Admin/ZGZN_Admin/1.py", line 20, in <module>
print '## 类方法 %s' % A.f()
TypeError: unbound method f() must be called with A instance as first argument (got nothing instead)


错误已经很明显了: 函数未绑定, 必须要将A的实例作为第一个参数


既然它要求第一个参数是 A的实例对象, 那我们就试下修改代码:


class A(object):
def f(self):
return 1
a = A()

print '#### 各自方法等效调用 ####'
print '## 类方法 %s' % A.f(a) #传入A的实例a
print '## 实例方法 %s' % a.f()

## 结果 ##
#### 各自方法等效调用 ####
## 类方法 1
## 实例方法 1


可以看出来, Bound 和 Unbound判断的依据就是, 当方法真正执行时, 有没有传入实例, A.f(a) 和 a.f() 用法的区别只是在于, 第一种需要人为传入实例才能调用, 而第二种, 是虚拟机帮我们做好了传入实例的动作, 不用我们那么麻烦而已, 两种方法本质上是等价的



发布于 2022-11-28 14:52

其实没啥区别,只不过在类里就叫方法,特指这个是针对类或者实例的,是类或者实例提供的。函数就是不针对特定的类,不是类提供的。总之,就是个概念,本质上没啥区别。

发布于 2019-03-25 16:29
教程9 python入门 模块和函数
143 播放
尝试输出一些教学视频,帮助想学编程的小伙伴入门。



我们的目标:【可以在最短的时间内,用python写脚本,提高效率】

数据结构,算法要不要学?要的,但前提是你愿意专研,感兴趣,
不喜欢的话,那么也不用像专业程序员那样啦,我们只要能利用好工具,达到目的就好了。

1.先把基本的python学了。
2.学习turtle库,pygame整点小游戏,写写脚本。
3.学学git,github宝藏,gpt怎么玩。
4.django,flask,fastapi,爬虫一些web相关。
总的来说就是,带你入门,感觉有兴趣,觉得好玩~,可以自己写一些小脚本~,提高工作效率
如果想有个学习氛围的话,可以加群:791785491
我的b站频道: space.bilibili.com/3291
发布于 2024-01-16 13:03· 12 次播放

在 Python 中,函数和方法都是用来执行特定操作的可调用对象,但是它们有一些区别。

函数是独立的代码块,它可以接受零个或多个参数,并且可能会返回一个值,但是它不依赖于任何对象。函数可以在任何地方定义和调用,不一定需要在类中定义。

方法是一个函数,它定义在类或实例对象中,方法必须通过对象或类的实例进行调用。方法第一个参数通常是self,它指向该方法所属的对象实例,允许方法访问该对象的属性和方法。

在 Python 中,可以通过以下方式来区分函数和方法:

如果一个函数定义在类或实例对象中,并且使用了self作为第一个参数,则它是一个方法。

如果一个函数定义在全局命名空间或在一个模块中,并且没有使用self作为第一个参数,则它是一个函数。

下面是一个例子,展示了一个类中的方法和一个全局函数:

class MyClass:
    def my_method(self, x):
        return x * 2

def my_function(x):
    return x * 2

obj = MyClass()
print(obj.my_method(3))  # 调用对象的方法
print(my_function(3))    # 调用全局函数


在这个例子中,my_method是一个方法,它在MyClass类中定义,而my_function是一个函数,它定义在全局命名空间中。当调用my_method时,需要使用类实例的方法调用语法(obj.my_method(3)),而调用my_function时,则直接使用函数名调用(my_function(3))。

发布于 2023-03-20 15:27

方法是类内置的函数,与类相关联,无法单独调用,调用时通常都引用了类的一些属性,方法和函数都是人对其定义的概念,用于人对其功能的区分,并不会真的对使用有什么影响,类内置的方法必定要与类相关联,不然调用时会报错

方法和函数的称谓只是方便我们使用,实际与运行为准。常规情况下,类内定义的函数需要增加self的参数,只能对象来调用它,而对于对象来说,他就是方法。

非常规情况下,类内不使用self参数的函数可以用类直接调用,而对象无法调用它,会报错,他是仅能由类所调用的一个函数,实际应用可能会运算和现实与该类相关的运行环境等

发布于 2022-07-08 15:21

方法是属于对象的函数

函数是执行特定任务的代码块,将包含其自己的作用域,并通过名称进行调用。所有函数都可以包含零(无)参数或多个参数。退出时,一个函数可以或不能返回一个或多个值。python中的方法与函数类似,但它与对象/类相关联。

发布于 2022-08-24 10:08
067.Python全系列_函数的基本概念_内存分析_函数的分类_定义和调用
306 播放
编辑于 2021-12-22 17:25· 174 次播放