Python初体验(3)-java与python的差异(函数)

(60) 2024-07-02 11:01:01

一.python中的内存分配

1.

在python中变量就是对象的引用,变量位于栈,对象位于堆。

与java不同,python所有中1、2、3这种整数类型也是看作对象存放在堆中

a=1 # 等号左面的叫变量,等号右边的叫对象,在python中变量是没有类型的,对象才有类型。 

如果在java中这可以理解为,给变量a赋值1。但是在python中不可以这样描述,正确的是:引用a指向了对象1。

2.可变类型与不可变类型

在Python中有两种类型的对象,可变对象和不可变对象

可变类型:对象在内存地址中存储的数据可变,可变对象有:list,dict

不可变类型:对象在内存地址中存储的数据不能变化,不可变对象有:int,string,float,tuple

def fun(b): b+=1; a=1 print(a) #1 fun(a) print(a) #1 

上面的测试看起来像是进行了java中的值传递,因为没有改变实参a的值。但原因是这样的,当执行b+=1的时候,并不是把b指向的对象加一,而是将这个变量b重新指向对象2。

def fun(b): print(id(b)) #52 b+=1; print(id(b)) #84,局部变量b指向的地址发生了变化 

python缓存了整数,一个整数在内存中像是一个对象,只存有一份

a=1 b=1 print(a is b) #TRUE 

思考:python是如何做内存垃圾回收的

二.python中的传参

由上可知,与java不同,python唯一支持的参数传递方式是引用传递,

但是引用传递又分为两种情况

1.传递不可变对象和可变对象

就像上面的例子中表现的那样,不可变对象在函数中不会改变对象的值,也无法改变实参的指向。效果类似 c++ 的值传递。

传递可变对象的时候,类似 c++ 的引用传递。

2.参数形式

python中函数传递,根据参数的形式可分为以下四种

位置传递:最普通的形式,实参与形参一一对应。

默认参数:当实参中未传对应的参数时,变量使用默认值。写形参时也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时,需要把参数名写上,threading.Thread就是这种形式。

def fun(a=0,b=0,c=0,d=0): #默认值 print(a) #0 print(b) #2 print(c) #0 print(d) #1 fun(b=2,d=1) 

不定长参数:也叫可变参数,在java中也有这样的传参形式,在形参中不定长参数是一个tuple

def fun(*a): for i in range(len(a)): print (a[i]) fun(1,2,3,4,5) 

关键字参数:形参中带两个星号标识,在形参中是一个dict,算是不定长参数的一种扩展。

def fun(a,**dic): print(a) #1 print(dic['c']) #3 fun(1,b=2,c=3) 

命名关键字参数:还没搞清楚,这种形式有啥用

def fun(a,*,b,c): print(a) print(b) print(c) fun(1,b=2,c=3) 

思考,这几种方式混用,会出现什么问题,应该遵循怎样的原则

三.高级函数

在python中,函数本身也是对象,可以作为参数,可以作为返回值。

1.函数作为参数

def add(a,b): return a+b def exec(func,*args): a=0 for i in args: a = func(a ,i ) return a a = exec(add,1,2,3,4,5,6) #add是一个函数,作为形参 print(a) #21 

2.函数作为返回值

def exec(*args): def fun(): #函数内又定义了一个函数 a=0 for i in args: a+=i return a return fun a = exec(1,2,3,4,5,6) #这个返回值并不是一个整数,a是一个函数 print(a) # a是一个函数,这里并不能打印出21,而且a内的代码并没有执行过 print(a()) #21,在这里a内部的代码才第一次执行 

3.匿名函数

lambda表达式,代替的是java中匿名内部类的功能,java8中也有这个功能。

匿名函数本身也是一个函数对象,多用在做形参的时候

与java的匿名内部类相比,匿名函数有个限制,只能有一个表达式。

def exec(listener,a,b): if a>b: listener(a) else: listener(b) exec(lambda x:print(x),345,654) 

四.魔法函数

魔法函数是Python的一种高级语法,允许你在类中重写某些固定函数,这些函数会在特定的情况下被解释器调用。比如在类A中自定义__init__()函数,则在创建对象的时候,会自动调用__init__()函数,函数名格式一般为__xx__(双下划线)

str()就像是java中的toString;hash()就是java中的hashCode;等等

抄一些常用的魔法函数在这里:

name()

call(),对象或者实例可以像函数一样调用,就像执行普通函数一样

new()

slots()

len()

del_() ,析构函数

class obj: def __call__(self,a,b): print("__call__()",a,b) o = obj() o("把对象","当函数用") 

python中的魔法函数并不都是定义在object中的,思考:当编译器为什么敢调用一个,类不一定有的函数
五.动态语言鸭子类型

在python中是没有父类引用指向子类对象这种操作的。

在使用java的时候常常让几个不同的类实现同一接口,然后用这个接口类型的引用指向不同对象,直接调用函数。那么在python中如何表现这种多态呢,鸭子类型。

如果在网络上搜鸭子类型,一定会看到这样的描述:当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。

翻译一下:一个对象有我需要的方法就行,我不管这个方法是不是继承来的。

class cat: def run(self): print("小猫跑") class dog: def run(self): print("小狗跑") def animalRun(animal): animal.run() #如果传入一个没有run()方法的对象,这里就会报错 c = cat() d = dog() animalRun(c) animalRun(d) 

写惯了java,觉得这样做有点草率,这大概就是动态语言的区别吧。

在python中函数与方法这两个词是有区别的,
python中的 inspect 模块,提供函数ismethod() 与 isfunction() ,判断方法和判断函数,看到这里我一脸蒙蔽,方法和函数不是同一个东西吗?思考:python中区分方法和函数的意义是什么?

THE END

发表回复