初学Python(四)

函数   
    1.函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段
    2.语法:
        def 函数名(参数列表):
        函数体
         return “返回值”
    可以返回多个值,返回的多个值组成一个元组,返回值加上一对中括号,则返回一个列表
函数分为定义和调用
      3.可更改(mutable)与不可更改(immutable)对象
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
python 函数的参数传递:
不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响
4.以下是调用函数时可使用的正式参数类型:
必需参数
关键字参数:关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict
例:# 关键字参数:**kw
def person(name,age,**kw):
    print('name:',name,'age:',age,'other:',kw)
person('Frank','37')
person('Frank','37',city='Shanghai')
person('Frank','37',gender='M',job='Engineer')
也可以写成下面的简约形式:
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra)
注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。
默认参数:(缺省参数)缺省参数必须写在后面,可以不指定参数名,但是顺序要保证,否则要指定参数名
#可写函数说明
def printinfo( name, age = 35 ):
 "打印任何传入的字符串"
 print ("名字: ", name);
 print ("年龄: ", age);
 return;
 
#调用printinfo函数
printinfo( age=50, name="runoob" );
print ("------------------------")
printinfo( name="runoob" );
不定长参数(可变参数):
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple
class Person:
        def __init__(self,sex):
            self.sex=sex
        def eat(self):
            print("在吃饭")
        def sleep(self):
            print("睡觉")
        def say(self):
            print("我叫%s,年龄%d"%(self.name,self.age))
p=Person("女")
#添加属性
p.sleep()
p.name='张三'
p.age=20
p.say()
print(p.sex)
但是调用的时候,需要先组装出一个list或tuple:


如果利用可变参数,调用函数的方式可以简化成这样:


定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:


0
如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:


14
这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:

*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。
参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用,除了可变参数无法和命名关键字参数混合。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数/命名关键字参数和关键字参数。


比如定义一个函数,包含上述若干种参数:


def f1(a, b, c=0, *args, **kw):
 print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)


def f2(a, b, c=0, *, d, **kw):
 print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
最神奇的是通过一个tuple和dict,你也可以调用上述函数:



小结
Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。
默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!
要注意定义可变参数和关键字参数的语法:
*args是可变参数,args接收的是一个tuple;
**kw是关键字参数,kw接收的是一个dict。
变量作用域:
全局变量与局部变量的作用域不同
生命周期不同
全局变量:
g_a=10
def test2():
    global g_a#告诉程序这里是一个全局变量
 g_a=20
    print(g_a)
def test3():
    print(g_a)
test2()
test3()
当全局变量和局部变量同名时,局部变量优先
局部变量
当列表和字典作为全局变量时,不用加global
匿名函数:
python 使用 lambda 来创建匿名函数
语法:lambda [arg1 [,arg2,.....argn]]:expression
# 可写函数说明
sum = lambda arg1, arg2: arg1 + arg2;
sum(1,2)
def XXX(arg1,arg2):
 return arg1+arg2 
sum=XXX(10,20)
# 调用sum函数
print "相加后的值为 : ", sum( 10, 20 )
print "相加后的值为 : ", sum( 20, 20 )


# ###################### 普通函数 ######################
# 定义函数(普通方式)
def func(arg):
 return arg + 1
  
# 执行函数
result = func(123)
  
# ###################### lambda ######################
# 定义函数(lambda表达式)
my_lambda = lambda arg : arg + 1
# 执行函数


方法:
import math
def is_sqr(x):
 return math.sqrt(x) % 1 == 0
print filter(is_sqr, range(1, 101))
结果:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
python reduce():对于序列内所有元素进行累计操作
li = [11, 22, 33]
result = reduce(lambda arg1, arg2: arg1 + arg2, li)
python中的reduce
 python中的reduce内建函数是一个二元操作函数,他用来将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给reduce中的函数 func()(必须是一个二元操作函数)先对集合中的第1,2个数据进行操作,得到的结果再与第三个数据用func()函数运算,最后得到一个结果。
如:
 def myadd(x,y):  
 return x+y  
 sum=reduce(myadd,(1,2,3,4,5,6,7))  
 print sum  
#结果就是输出1+2+3+4+5+6+7的结果即28
当然,也可以用lambda的方法,更为简单:
 sum=reduce(lambda x,y:x+y,(1,2,3,4,5,6,7))  
 print sum 
reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。 


例如,编写一个f函数,接收x和y,返回x和y的和:


def f(x, y):
 return x + y
调用 reduce(f, [1, 3, 5, 7, 9])时,reduce函数将做如下计算:


先计算头两个元素:f(1, 3),结果为4;
再把结果和第3个元素计算:f(4, 5),结果为9;
再把结果和第4个元素计算:f(9, 7),结果为16;
再把结果和第5个元素计算:f(16, 9),结果为25;
由于没有更多的元素了,计算结束,返回结果25。
上述计算实际上是对 list 的所有元素求和。虽然Python内置了求和函数sum(),但是,利用reduce()求和也很简单。


reduce()还可以接收第3个可选参数,作为计算的初始值。如果把初始值设为100,计算:
reduce(f, [1, 3, 5, 7, 9], 100)
结果将变为125,因为第一轮计算是:


计算初始值和第一个元素:f(100, 1),结果为101。


sorted()也可以对字符串进行排序,字符串默认按照ASCII大小来比较:

类:具有相同的属性和方法的对象的集合。
对象:万物皆对象 var date=new Date();date.get
类和对象的关系:
类的包含属性和方法:
语法:
class 类名:
 属性
 方法
 定义一个类:
class Person:
 def eat(self): 
 print("正在吃饭...")
 def sleep(self):
 print("正在睡觉...")
创建对象:属性写在类外的情况,就是通过对象.属性,对象.方法()的方式调用
调用对象的方法:
创建多个对象:
self:
__init__(self):系统自动调用初始化方法,先生成对象,再调用此方法,再将对象赋值给引用名
 初始化操作
如果做全局属性:
例:
class Person:
 def __init__(self,v_name,v_age):
 self.name=v_name
 self.age=v_age
 def say(self):
 print("hello")
生成对象:
zhangsan=Person()
zhangsan.name="张三"
zhangsan.age=20
zhangsan.say()
__str__():
 return XXX
属性相对于类来说属于全局,每个方法都可以调用。
封装
get/set方法:不写__init__()方法
set_name(self,new_name):
self.name=new_name
get_name(self):
return self.name
案例:
class Student:
    def set_name(self,name):
        self.name=name
    def get_name(self):
        return self.name
stu=Student()
stu.set_name("abc")
print(stu.get_name())


公有方法:
私有方法:def __test():只能在当前类中使用,以__开头
自动销毁方法:
__del__():
 XXX
当对象没有引用的时候,或程序结束的时候,程序自动调用__del__()
del 引用
可演示删除时自动调用__del__()
程序结束时自动调用__del__()
可以测试一个对象有多少个引用:
import sys
t=T()
sys.getrefcount(t)返回2
面向对象的三大特征:封装、继承、多态
继承:子类继承父类,子类可以使用父类的属性和方法,简化代码.
当生成子类对象时,先初始化父类对象,所以如果父类有__init__()方法,并且有属性时,要通过子类的构造赋值
一个类可以有多个子类
在子类中,调用父类的属性时,在__init__()方法中使用
父类.属性,或self.属性或父类.__init__(self,参数)或super(父类,self).__init__(参数)四种方法给父类传参
调用父类方法时:super().父类方法()
练习:
交通工具类:属性:名称 方法:行驶
子类:卡车,属性:载重,重写行驶的方法
子类:火车,属性:车箱个数,重写行驶的方法
总结:当子类继承父类时,子类的构造方法应该包含父类和子类共同的属性,在子类的初始化方法中,将父类的属性传递给父类,子类的属性赋值给子类
方法重写:子类继承父类时,子类的方法签名和父类一样,此时子类重写了父类的方法,当生成子类对象时,调用的是子类重写的方法


父类()
子类(父类)
三代继承:子类初始化方法需要祖父、父类及自己的属性,可以调用父类的初始化方法传参,可以重写父类的方法
构造的顺序依然先构造祖父类,再构造父类,最后构造自己
类继承object
方法重写:
如果子类重写的方法想调用父类的方法时,在子类方法中:父类.方法(self)或super().父类方法()
私有属性、私有方法:均不能在类外面被调用
多继承:类同时继承多个父类,class C(A,B),当有AB均有相同方法,而子类又重写时,调用谁的方法,如果子类没有方法,则调用哪个父类的方法?
类名.mro(),可以看到所有父类,即搜索顺序
作业:

多态:
类属性:属于类的成员,属于对象共有的
类方法:在方法上添加@classmethod
@classmethod
def class_method(cls):
可以通过类方法调用类属性,也可以通过对象调用类属性
静态方法:方法前加@staticmethod,静态方法没有参数,静态方法既和类没关系,也和对象没关系,也可以通过类和对象调用
工厂类:有一些子类,在一个类中生成很多对象,简单工厂模式
 pass
__new__(cls):#用来创建对象,而且必须有返回值
 return object.__new__(cls)
可以用id(cls)看地址
当有属性时,需要在__new__()中也添加属性
单例:
class singleton:
 __instance=None
 def __new__(cls):
        if cls.__instance==None:
            cls.__instance=object.__new__(cls)
            return cls.__instance
        else:
            return cls.__instance
s=singleton()
ss=singleton()
print(id(s))
print(id(ss))
对象列表进行排序:按照什么进行排序,重写__ls__方法:


class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return "姓名:%s,年龄:%d"%(self.name,self.age)
    def __lt__(self, other):
        if self.name==other.name:
            return self.age<other.age
        else:
            return self.name.encode('gbk')>other.name.encode('gbk')
支持中文排序


peple=[Person("abc",20),Person("aabc",22),Person("abc",21),Person("aabc",23)]
peple.sort()
for m in peple:
    print(m)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值