Python 中的“特殊”函数

“ 私有函数,魔法函数,回调函数”

在任何编程语言中,都会规定某些对象 (属性、方法、函数、类等) 只能够在某个范围内访问,出了这个范围就不能访问了。这是“公”、“私”之分。此外,还会专门为某些特殊的东西指定一些特殊表示,比如类的名字就不能用 class,def 等,这就是保留字。除了保留字,python 中还为类的名字做了某些特殊准备,就是“专有”的范畴。

01

私有函数

有时在项目中会看到这样一些函数。

图片

图片

在某些时候,会看到有一种方法命名比较特别,是以“__”双划线开头的,将这类命名的函数 / 方法称之为“私有函数”。

所谓私有函数,不可以从它们的模块外面被调用;私有类方法不能够从它们的类外面被调用;私有属性不能够从它们的类外面被访问。跟私有对应的,就是所谓的公有啦。有的编程语言用特殊的关键词来说明某函数或方法或类是私有还是公有。但是 python 仅仅用名字来说明,因为 python 深刻理解了两千年前孔子所说的“名不正言不顺”的含义。

如果一个 python 函数, 类方法, 或属性的名字以两个下划线开始 (但不是结束), 它是私有的; 其它所有的都是公有的。类方法或者是私有 (只能在它们自已的类中使用) 或者是公有 (任何地方都可使用)。

例如:

class Person:

def __init__(self, name):
    self.name = name
    print(self.name)

def __work(self, salary):
    print("%s salary is: %d" % (self.name, salary))

if name == “main”:
officer = Person(“Tom”)
officer.__work(1000)

运行结果:

Tom
Traceback (most recent call last):
File “C:/Users/Administrator/PycharmProjects/Myworld/work.py”, line 13, in
officer.__work(1000)
AttributeError: ‘Person’ object has no attribute ‘__work’

从运行结果中可以看出,当运行到 officer.__work(1000) 的时候,报错了。并且从报错信息中说,没有该方法。这说明,这个私有方法,无法在类外面调用(其实类外面可以调用私有方法,就是太麻烦,况且也不提倡)。

将上述代码进行如下修改:
class Person:
def init(self, name):
self.name = name
print(self.name)

def __work(self, salary):
    print("%s salary is: %d" % (self.name, salary))

def worker(self):
    self.__work(500)  # 在类内部调用私有方法

if name == “main”:
officer = Person(“Tom”) # Tom
# officer.__work(1000)
officer.worker() # Tom salary is: 500

得到正确结果

02

魔法函数

有时在项目中会看到这样一些函数。

图片

如果是以双划线开头,但不是以它结尾,所命名的方法是私有方法;

如果以双划线开头,并且以双划线结尾,所命名的方法就是专有方法。也叫魔法函数。

比如内置函数 __init__(), 就是一个典型的专有方法。关于专有方法,除了 __init__() 之外,还有诸如:str,__setitem__ 等等,要想看,可以利用 dir() 函数在交互模式下看看某个函数里面的专有方法。

例如:

python code to demonstrate example of

dir() number

class std_info:
name = “Amit shukla”
age = 21
course = “B.Tech (CS)”

printing return type of dir() function

print("return type of dir():", type(dir(std_info)))

printing details using dir() function

print(dir(std_info))

查看结果:

return type of dir(): <class ‘list’>
[‘class’, ‘delattr’, ‘dict’, ‘dir’, ‘doc’,
eq’, ‘format’, ‘ge’, ‘getattribute’, ‘gt’,
hash’, ‘init’, ‘le’, ‘lt’, ‘module’, ‘ne’,
new’, ‘reduce’, ‘reduce_ex’, ‘repr’, ‘se
tattr
’, ‘sizeof’, ‘str’, ‘subclasshook’, ‘weakref’,
‘age’, ‘course’, ‘name’]

魔法函数:init()

所有类的超类 object,有一个默认包含 pass 的 __ init __() 实现,这个函数会在对象初始化的时候调用,我们可以选择实现,也可以选择不实现,一般建议是实现的,不实现对象属性就不会被初始化,虽然我们仍然可以对其进行赋值,但是它已经成了隐式的了,编程时显示远比隐式的更好。

看下面的小栗子:

class test_1:
def method(self):
self.a = “1”
self.b = “2”
return self.a,self.b

class test_2:
def init(self):
self.a = “1”
self.b = “2”

def method(self):
return self.a,self.b

print(vars(test_1()))
print(“-”*10)
print(vars(test_2()))
"""
{}

{‘a’: ‘1’, ‘b’: ‘2’}
"""

我们可以通过 vars 函数获知显示声明的属性,但是隐式的就无法获知了,这并不值得提倡,但是在知道参数的情况下我们还是可以对其进行赋值的,如下:

class test_1:
def method(self):
return self.a, self.b

class test_2:
def init(self):
self.a = “1”
self.b = “2”

def method(self):
return self.a, self.b

t1 = test_1()
t1.a = 1
t1.b = 2
print(t1.method()) # (1, 2)
print(‘-’ * 10)
t2 = test_2()
t2.a = 3
t2.b = 4
print(t2.method()) # (3, 4)

03

回调函数

回调函数就是一个通过函数名调用的函数。如果你把函数的名字(地址)作为参数传递给另一个函数,当这个参数被用来调用其所指向的函数时,我们就说这是回调函数.

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应.

上面是对回调函数的描述和解释, 概念往往都显得生涩拗口, 不易理解.

简单来说, 我们可以这样理解回调,A 实现了 A1 函数和 A3 函数,B 实现了 B2 函数,B2 函数接收一个函数名字作为参数, 然后在 B2 内执行这个函数.

在实际应用时,A1 函数调用了 B2,B2 函数接收函数 A3 作为参数, 在 B2 内部执行 A3 函数,A3 就是回调函数.

下面举例说明

File:callback_B.py

def trade_meeting(callback_func):
“““贸易会谈并签署协议”””
print()
print(“—++ 与特朗普开始会谈 ++—”)
callback_func()
print(“—++ 会谈结束签署协议 ++—”)
print()

File:callback_A.py

from callback_B import trade_meeting

def trade_cn_us():
“““大大赴美, 中美贸易磋商”””
print()
print(“—++ 准备行程, 大大赴美 ++—”)
trade_meeting(ready_info)
print(“—++ 会谈结束, 带喜讯回国 ++—”)

def ready_info():
“““准备商谈内容”””
print()
print(“—++ 会议中提出要求 ++—”)
print()

if name == ‘main’:
trade_cn_us()

这个例子以中美贸易磋商作为示例:

在 callback_A.py 中实现了赴美进行贸易磋商并回国的函数 trade_cn_us(), 准备商谈资料(收集民众要求)的函数 ready_info().

在 callback_B.py 中实现了在美国召开会议并签署协议的函数 trade_meeting(callback_func).

可以理解为 callback_A.py 中实现的方法是在中国做的事情, callback_B.py 中实现的方法是在美国做的事情 (与现实的逻辑符合).

要实现赴美完成贸易磋商并回国的业务逻辑, trade_cn_us()调用了 trade_meeting(callback_func), 在美国进行贸易会议时, 需要调用国内准备会议资料的函数 ready_info(), 用 ready_info 函数的名字作为参数传递给 trade_meeting(), 然后在 trade_meeting() 中执行.

此时,ready_info() 就是回调函数。

运行结果:

—++ 准备行程, 大大赴美 ++—

—++ 与特朗普开始会谈 ++—

—++ 会议中提出要求 ++—

—++ 会谈结束签署协议 ++—

—++ 会谈结束, 带喜讯回国 ++—

两个类之间的回调

上面的回调是在两个不同的 python 文件中实现的, 在面向对象编程中, 两个不同的类之间也可以实现回调, 参考代码如下:

class China(object):
“““国内事项”””

def trade_cn_us(self):
    """大大赴美,中美贸易磋商"""
    print()
    print("---++  准备行程,大大赴美  ++---")
    us = American()
    us.trade_meeting(self.ready_info)
    print("---++  会谈结束,带喜讯回国  ++---")

def ready_info(self):
    """准备商谈内容"""
    print()
    print("---++  会议中提出要求  ++---")
    print()

class American(object):
“““美国事项”””

def trade_meeting(self, callback_func):
    """贸易会谈并签署协议"""
    print()
    print("---++  与特朗普开始会谈  ++---")
    callback_func()
    print("---++  会谈结束签署协议  ++---")
    print()

if name == ‘main’:
cn = China()
cn.trade_cn_us()

以上就是使用 Python 实现回调函数的过程。