python函数结构_PYTHON 之结构体,全局变量,函数参数,lambda编程 等

本文深入探讨了Python中的高级特性,包括结构体模拟、全局变量使用、函数参数传递、lambda表达式、generator应用以及如何构建switch结构。通过实例展示了Python的强大与灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PYTHON 之结构体,全局变量,函数参数,lambda编程 ,generator(yield)使用以及如何自己构建switch结构

***********************

pass

pass可以模拟struct结构

class Data

pass

d = Data()

d.a = 2

d.b = 4

print d.a

print d.b

***********************

子函数传参数的有趣的地方

def cheeseshop(kind, *arguments, **keywords):

print "-- Do you have any", kind, "?"

print "-- I'm sorry, we're all out of", kind

for arg in arguments: print arg #一个星号的arguments表示传入n元组tuple,可以想像成list或者数组

print "-" * 40

keys = keywords.keys()#两个星号的表示传入的是一个字典结构

keys.sort()

for kw in keys: print kw, ":", keywords[kw]

cheeseshop("Limburger", "It's very runny, sir.", "It's really very, VERY runny, sir.", shopkeeper='Michael Palin', client="John Cleese", sketch="Cheese Shop Sketch")

除了第一个参数被当做kind的值,剩下的将被构成一个tuple(和list相似,理解成数组吧),这些被当成整体传入函数cheeseshop,剩下的形如k=v的则全部被构建成一个词典dictionary 对象,然后传进入。

感觉这样的主要好处是定义函数cheeseshop的时候需要写的参数少了,同样类型的使用argument就好了,但是如果给别人调用的话,这样写恐怕非常不好。

当然,如果你写成

def testArg(*argument,*argument):

for a in argument: print a

那是不对的, 最多只能有一个参数是*的形式

***********************

使用全局变量

比如在外面定义了a,则函数内部如果想使用全局变量a,加上

global a

***********************

yield的用法

yield 是generator的关键词,看看generator

http://www.python.org/dev/peps/pep-0255/ 说明了采用generator的原因,并给出了一些restriction,最后使用binary tree作为例子

http://www.ibm.com/developerworks/library/l-pycon.html?S_TACT=105AGX52&S_CMP=cn-a-x

A generator is a function that remembers the point in the function body where it last returned. Calling a generator function a second (or nth) time jumps into the middle of the function, with all local variables intact from the last invocation.

yield 产生一个generator,这个generator有两个好处:

1)记录了产生generator的函数的内部状态,也就是数据的值

2)记录了该函数正在执行的语句,下一次调用将从上次执行yield语句的下一条开始执行。

***********************

switch

python没switch,但是有多种方法来实现switch,看看下面的例子把

#!/usr/local/bin/python

# coding: UTF-8

#first case

a = 2

def print1():

print 1

def print2():

print 2

def print3():

print 3

def print1():

print 'default'

#使用单条语句,然后使用exec函数执行

valuesStatement = {

1: 'print 1',

2: 'print 2',

3: 'print 3'

}

#使用函数,即获得了函数句柄,然后就可以直接调用

valuesFunc = {

1: print1,

2: print2,

3: print3

}

exec(valuesStatement.get(1,'print 2'))

valuesFunc.get(1,'default')()#注意,这里括号的位置,其实就是相当于首先取得函数指针,然后调用,如果你直接

print valuesFunc.get(1,'default') #的话,你就会看到函数的地址

#second case

#使用lambda, definition

#http://en.wikipedia.org/wiki/Lambda_calculus

#http://www.mathstat.dal.ca/~selinger/papers/lambdanotes.pdf,看看这篇文章可以更好的理解lambda,我看了Church理论证明之前的部分,理解了lambda怎么回事,但是lambda和函数编程之间的关系确解释不清楚,感觉函数编程并不依赖与lambda

#lumbda 如何使用

def make_incrementor(n):

return lambda x: x + n

f = make_incrementor(4) #这里相当于我们获得了一个函数

print f(3) #call

#那么使用lumbda实现switch吧,类似前面所属使用statement的方式,只是不需要使用exec了

result = {

'a': lambda x: x * 5,

'b': lambda x: x + 7,

'c': lambda x: x - 2

}

f = result['a']

print f(3)

#third case

#使用类

#This class provides the functionality we want. You only need to look at

# this if you want to know how this works. It only needs to be defined

# once, no need to muck around with its internals.

class switch(object):

def __init__(self, value):

self.value = value

self.fall = False

def __iter__(self ):

"""Return the match method once, then stop"""

yield self.match

raise StopIteration

def match(self, *args):

"""Indicate whether or not to enter a case suite"""

if self.fall or not args:#为Ture或者默认,默认是没有参数的

return True

elif self.value in args: # changed for v1.5, see below

self.fall = True

return True

else:

return False

# The following example is pretty much the exact use-case of a dictionary,

# but is included for its simplicity. Note that you can include statements

# in each suite.

v='ten'

for case in switch(v):#因为重写了 def __iter__(self):,而该函数返回match函数,从而可以传入参数并判断是否相等

if case('one'):#这里和普通case不同,前面多了个if,作者只是在形式上模拟了switch-case,实际用的是if

print 1

break

if case('two'):

print 2

break

if case('ten'):

print 10

break

if case('eleven'):

print 11

break

if case(): # default, could also just omit condition or 'if True'

print "something else!"

# No need to break here, it'll stop anyway

#无需多解释了,作者巧妙的利用了python的for功能来让iter返回函数指针,进而接受参数确定是否执行之。

#要注意,case前面必须有if,否则,就不奏效拉,因为作者就是用了mathc的返回值

<think>嗯,用户现在想了解回调函数的定义位置,也就是在编程中回调函数应该在哪里声明和实现。根据之前提供的引用内容,我需要综合这些信息来组织回答。首先,回调函数的定义位置可能因编程语言和应用场景而异,但通常有一些共通的原则。 首先,用户提到的引用[2]是关于C语言的例子,其中回调函数作为参数传递。在那里,回调函数`my_callback`是在主函数之前定义的,这样在传递给`do_something`函数时就可以被正确识别。这说明在C语言中,回调函数需要在使用之前声明,通常是在调用它的函数之前定义,或者在头文件中声明。 然后引用[3]提到函数指针在模块化编程中的用途,回调函数通过函数指针来指向用户定义的函数,这涉及到模块的设计。因此,回调函数可能在模块外部定义,由用户实现,模块通过函数指针来调用。这种情况下,回调函数的声明可能在模块的头文件中,而实现则由用户完成,这样可以降低耦合性。 引用[5]展示了Python使用回调函数的例子,回调函数`handle_data`在调用`get_data`之前定义,这样在异步操作完成后才能被正确调用。这说明在动态语言如Python中,回调函数的定义位置同样需要在使用前声明,但可能更灵活,比如可以作为匿名函数lambda表达式内联传递。 用户的问题可能想知道是否回调函数必须定义在某个特定的位置,比如全局作用域,或者是否可以局部定义。需要结合不同语言的情况来说明。例如在C语言中,回调函数必须是全局或静态函数,因为非静态局部函数无法获取其地址。而在支持闭包的语言如JavaScript或Python,回调函数可以内联定义,如匿名函数lambda,这样它们可以访问外部变量,提供了更大的灵活性。 此外,引用[4]提到MATLAB中的回调函数可以使用函数句柄、匿名函数等形式,这也说明不同环境下回调函数的定义位置和方式可能不同。例如,在GUI编程中,回调函数通常作为组件的事件处理函数,可能在类或结构体中定义。 用户可能还关心如何组织代码结构,使得回调函数易于维护。例如,将回调函数集中定义在某个模块,或者根据功能分散到不同的文件中。需要建议最佳实践,比如保持回调函数的单一职责,避免过于复杂的实现,以及合理的命名规范,如引用[6]提到的命名规范。 另外,用户之前的问题是关于C语言中printf输出小数位数的问题,现在转向回调函数,可能是在学习不同的编程概念。需要确保回答清晰,结构合理,分点说明不同语言中的情况,帮助用户建立全面的理解。 总结来说,回调函数的定义位置取决于编程语言和具体应用场景。在静态语言如C中,通常需要提前声明或定义,而在动态语言中可能更灵活。需要分点说明不同情况,并结合示例,让用户明白如何在不同环境中正确声明和实现回调函数。</think>在编程中,回调函数的定义位置与其作用域、语言特性及具体使用场景密切相关。以下从**声明方式**和**实现位置**两个维度进行详细说明,并结合多语言示例说明其差异: --- ### 一、回调函数的声明位置 #### 1. **全局作用域声明**(C/C++/静态语言) - **声明方式**:在全局或模块头文件中定义函数原型(如C语言需提前声明函数指针类型) ```c // 声明回调函数类型(通常在头文件中) typedef void (*Callback)(int); // 使用回调的函数声明 void process_data(int value, Callback callback); ``` - **优势**:便于跨模块调用,符合模块化编程规范[^3] - **限制**:需避免命名冲突,通常用于底层库设计 #### 2. **局部作用域声明**(Python/JavaScript/动态语言) - **声明方式**:在函数内部或调用点直接定义匿名函数(如lambda表达式) ```python def async_task(callback): result = compute() callback(result) # 回调在调用时动态定义 async_task(lambda data: print(f"Result: {data}")) # 匿名回调 ``` - **优势**:灵活控制上下文变量(闭包特性),减少代码冗余[^5] #### 3. **类/对象内声明**(面向对象语言) - **声明方式**:作为类的成员函数或接口方法(如Java接口、C++虚函数) ```java interface OnCompleteListener { void onComplete(String result); // 回调接口声明 } class MyTask { public void execute(OnCompleteListener listener) { listener.onComplete("Done"); // 调用类内定义的回调 } } ``` - **优势**:实现回调与对象状态的绑定,增强封装性 --- ### 二、回调函数的实现位置 #### 1. **独立函数实现**(通用模式) - **场景**:需要复用的通用逻辑(如日志记录、错误处理) ```c // 独立回调函数实现(全局作用域) void log_callback(int error_code) { printf("Error: %d\n", error_code); } // 调用时传入 read_file("data.txt", log_callback); ``` #### 2. **嵌套/闭包实现**(动态语言特性) - **场景**:需要访问外部变量的回调(如事件处理器) ```javascript function fetchData(url) { let retries = 0; sendRequest(url, function(response) { // 嵌套回调捕获retries变量 if (!response.ok && retries < 3) { retries++; fetchData(url); // 闭包访问外部变量 } }); } ``` #### 3. **模块化实现**(解耦设计) - **场景**:跨模块协作时,回调由用户自定义(如插件系统) ```c // 模块头文件声明回调类型 typedef void (*PluginCallback)(const char*); // 用户自定义实现(独立文件) void user_plugin(const char* data) { // 处理数据 } ``` 通过函数指针注册到核心模块,实现解耦[^3] --- ### 三、关键差异对比 | 特性 | 静态语言(C/C++) | 动态语言(Python/JS) | 面向对象语言(Java/C#) | |---------------------|--------------------------------|--------------------------------|-----------------------------| | **声明位置** | 全局/头文件声明函数指针类型 | 调用点动态定义(匿名函数) | 接口/委托类型声明 | | **实现作用域** | 全局或静态函数 | 任意作用域(支持闭包) | 类成员方法或匿名内部类 | | **典型应用** | 底层系统回调、硬件中断处理 | 事件驱动编程、异步操作 | GUI事件处理、异步任务监听 | --- ### 四、代码示例验证 #### 1. C语言(全局回调) ```c #include <stdio.h> typedef void (*Logger)(const char*); void process_data(int value, Logger logger) { logger("Processing started"); // 数据处理逻辑 } // 独立实现的回调函数 void file_logger(const char* msg) { fprintf(stderr, "[LOG] %s\n", msg); } int main() { process_data(100, file_logger); // 传入全局回调 return 0; } ``` #### 2. Python(闭包回调) ```python def async_operation(callback): def on_complete(): result = "Data loaded" callback(result) # 调用闭包捕获的callback # 模拟异步完成 on_complete() def main(): context = "Status: " async_operation(lambda data: print(context + data)) # 匿名回调捕获context main() # 输出:Status: Data loaded ``` --- ### 五、设计建议 1. **降低耦合**:通过接口/函数指针分离回调定义与调用方[^3] 2. **命名规范**:回调函数名应体现触发时机(如`onClick`、`handleError`)[^1] 3. **上下文管理**:动态语言中优先使用闭包,静态语言可通过参数传递上下文[^5] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值