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

一.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))    #3158044469552

    b+=1;

    print(id(b))    #3158044469584,局部变量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中区分方法和函数的意义是什么?

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值