#遍历 info = {'key1':'value1','key2':'value2','key3':'value3'} #方式一 for i in info: print(i,info[i]) #方式二 for key,value in info.items(): print(key,value)
li = [1,2,3,5,4,7,9,7]
for index,v in enumerate(li):
print(index,v)
函数:
*定义函数,函数体不执行,只有调用函数时,函数体才执行。
#写一个监控程序,监控服务器的系统状况,当cpu\disk\memory等指标的使用量超过阀值时即发邮件报警 #不使用函数版 while True: if cpu利用率 > 90%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 if 硬盘使用空间 > 90%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 if 内存占用 > 80%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 #以上代码存在问题: #1.代码重复过多,一个劲的copy and paste不符合高端程序员的气质 #2.如果日后需要修改发邮件的这段代码,比如加入群发功能,那你就需要在所有用到这段代码的地方都修改一遍 #函数版 def 发送邮件(内容) #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 while True: if cpu利用率 > 90%: 发送邮件('CPU报警') if 硬盘使用空间 > 90%: 发送邮件('硬盘报警') if 内存占用 > 80%: 发送邮件('内存报警')
函数是什么?
函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在Java里面叫做method。
定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
特性:
- 减少重复代码
- 使程序变的可扩展
- 使程序变得易维护
语法:
def say(): #定义函数,def为关键词,say为函数名 print("Hello,my name is ChenTaicheng,I'm fine,Thank you.") #函数内容,为一系列语句 say() #调用函数
带参数
#下面这段代码 a,b = 5,8 c = a**b print(c) #改成用函数写 def calc(x,y): #该函数可以接受传入两个参数,即x,y,多一个不行,少一个也不行 res = x**y return res #返回函数执行结果 c = calc(a,b) #结果赋值给c变量 print(c)
形参与实参
形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
默认参数
def stu_register(name, age, course, country='CN'):#定义函数时设置默认参数 print("----注册学生信息------") print("姓名:", name) print("age:", age) print("国籍:", country) print("课程:", course) stu_register("张三", 22, "python_devops","美国")#有传值则使用传入的值 stu_register("李四", 21, "linux")#没有传值则使用默认参数
stu_register(age=22,name='CCIE',course="python",) #使用指定参数名赋值,里面的参数就得都使用指定参数名赋值的方式
非固定参数:*args *keyargs
非固定参数 若你的函数在定义时不确定用户想传入多少个参数,就可以使用非固定参数 def stu_register(name,age,*args): # *args 会把多传入的参数变成一个元组形式 print(name,age,args) stu_register('ctc',22) #输出 ctc 22 (),后面这个()就是args,只是因为没传值,所以为空 stu_register('ctc',22,'python','qypt') #输出 ctc 22 ('python', 'qypt') 还可以有一个**kwargs def stu_register(name,age,*args,**kwargs): # *kwargs 会把多传入的参数变成一个dict形式 print(name,age,args,kwargs) stu_register('ctc',22) #输出ctc 22 () {},{}#后面这个{}就是kwargs,只是因为没传值,所以为空 stu_register('ctc',22,'python','qypt') #输出 ctc 22 ('python', 'qypt') {} stu_register('ctc',22,'python',school = 'qypt',sex = 'man') #ctc 22 ('python',) {'school': 'qypt', 'sex': 'man'}
全局变量与局部变量
''' 全局与局部变量 在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。 全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。 当全局变量与局部变量同名时: 在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。 ''' name = "ChenTaicheng" #全局变量 def change_name(name): print("before change:", name) name = "一个改变世界的人" #局部变量 print("after change", name) change_name(name) print("在外面看看name改了么?", name) -----------------------------------------------------------------------------》 -----------------------------------------------------------------------------》 输出结果: before change: ChenTaicheng after change 一个改变世界的人 在外面看看name改了么? ChenTaicheng
递归与返回值
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
要想获取函数的执行结果,就可以用return语句把结果返回
注意:
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
def calc(n): print(n) if int(n / 2) == 0: return n return calc(int(n / 2)) f = calc(10) print(f) #输出函数的返回值 输出: 10 5 2 1 1 #函数的返回值
匿名函数 :匿名函数就是不需要显式的指定函数
#这段代码 def calc(n): return n**n print(calc(10)) #换成匿名函数 calc = lambda n:n**n print(calc(10)) 你也许会说,用上这个东西没感觉有毛方便呀, 。。。。呵呵,如果是这么用,确实没毛线改进,不过匿名函数主要是和其它函数搭配使用的呢,如下 res = map(lambda x:x**2,[1,5,7,4,8]) for i in res: print(i)
高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
def add(x,y,f): return f(x) + f(y) res = add(3,-6,abs) #即把一个函数名当中参数值,abs为求绝对值的函数的函数名 print(res)
装饰器:
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
# 一个简单的例子 # def foo(): # print("I'm foo") # # foo() # 现在有新需求,需要添加一个新功能 # def foo(): # print("NEW function") # print("I'm foo") # # foo() #如果Bar1(),Bar2()也需要添加这个新功能,此时就需要在每个函数里添加这个新功能的代码,就造成了大量的重复代码, #所以就可以重新定义个函数用于表示这个新功能 #如下 # def foo(): # print("I'm foo") # # # def NEW_F(func): # print("NEW function") # func() # # NEW_F(foo) #我们每次都要将一个函数作为参数传递给NEW_F函数。而且这种方式已经破坏了原有的代码逻辑结构, # 之前执行业务逻辑时,执行运行bar(),但是现在不得不改成NEW_F(foo)。 #此时就需要装饰器了
#简单装饰器 # def foo(): # print("I'm foo") # # # def NEW_F(func): # # def wrapper(*args,**keyargs): # print("NEW function") # return func(*args,*keyargs) # return wrapper # # foo = NEW_F(foo) # foo() #函数NEW_F就是装饰器,它把执行真正业务方法的func包裹在函数里面,看起来像foo被 #NEW_F装饰了。在这个例子中,函数进入和退出时 ,被称为一个横切面(Aspect),这种编程方式 # 被称为面向切面的编程(Aspect-Oriented Programming)。 #@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作 # def NEW_F(func): # # def wrapper(*args,**keyargs): # print("NEW function") # return func(*args,*keyargs) # return wrapper # # # @NEW_F #需注意装饰器函数必须先定义再应用 # def foo(): # print("I'm foo") # # # foo() #如上所示,这样我们就可以省去foo = NEW_F(foo)这一句了,直接使用foo()了 #如果我们有其他的类似函数,我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。 # 带参数的装饰器 # 装饰器还有更大的灵活性,例如带参数的装饰器:在上面的装饰器调用中,比如@NEW_F, # 该装饰器唯一的参数就是执行业务的函数。装饰器的语法允许我们在调用时, # 提供其它参数,比如@decorator(a)。这样,就为装饰器的编写和使用提供了更大的灵活性。 def logging_f(level): def decorator(func): def wrapper(*args,**keyargs): if level == "warn": print('出现紧急情况!') return func(*args) return wrapper return decorator @logging_f(level="warn") def foo(): print("I'm foo") foo() #上面的use_logging是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。 # 我们可以将它理解为一个含有参数的闭包。当我 们使用@use_logging(level="warn")调用的时候,Python能够发现这一层的封装, # 并把参数传递到装饰器的环境中。
类
面向对象
类
对象
# #
class Foo: # class 类名
def F1(self, name): # 定义函数,在类中叫做方法
print('Hello,world!')
print(name)
return '返回值'
# 调用类
# 创建对象
obj = Foo() # 对象 = 类名()
# 通过对象执行方法
r = obj.F1('chentaicheng') # 对象.方法()
print(r)
# #
构造方法,self
析构方法
# # class Foo: def __init__(self,name,age,addr): self.name = name self.age = age self.addr = addr def F1(self,name): print('Hello,world!') print(name) return '返回值' def __del__(self):#析构方法 print("没有[%s]这个人了"%self.name) #创建对象,即运行类名()就会自动先执行类中的__init__方法 obj = Foo('chentaicheng',21,'shantou') print(obj.addr) #obj.addr即使self.addr del obj #del会触发析构方法 ##
面向对象三大特性:封装、继承、多态
# 多态: 可对不同类的对象使用同样的操作。
# 封装:对外部世界隐藏对象的工作细节。
# 继承:以普通的类为基础建立专门的类对象。
封装:例子:__init__方法,把类(参数,参数……)括号里的参数封装到对象中去。
继承:
# 自己有先执行自己的,没有再从父类中找
# 没有共同父类时,一条道走到黑
# 有共同的一个父类时,从左先执行,走到顶端(未到父类)就不走缩回去
#先上一个比较简单的单继承语法。在python3中,基类的构造函数不会被自动调用,需要手动调用,同样的方法也是这样,需要手动调用。
可以使用类名称 + init方法,也可以使用super语法进行调用。在下面这个例子中,子类继承了基类的方法和字段。字段会在基类中初始化。 # class BaseClass: def __init__(self): self.name = 'BaseClass' print('BaseCalss: Constructor called') def getname(self): print('BaseCalss: self name equals ' + self.name) class DerivedClass(BaseClass): def __init__(self): super().__init__() print('DerivedClass: Constructor called') if __name__ == '__main__': class1 = BaseClass() class1.getname() class2 = DerivedClass() class2.getname() # 运行结果: BaseCalss: Constructor called BaseCalss: self name equals BaseClass BaseCalss: Constructor called DerivedClass: Constructor called BaseCalss: self name equals BaseClass
子类也可以overwrite父类的方法,那么父类的方法就不会被调用,除非手动调用:
class BaseClass: def __init__(self): self.name = 'BaseClass' print('BaseCalss: Constructor called') def getname(self): print('BaseCalss: self name equals ' + self.name) class DerivedClass(BaseClass): def __init__(self): super().__init__() print('DerivedClass: Constructor called') def getname(self): print('self.name init value is ' + self.name) self.name = 'DerivedClass' print('DerivedClass: self name equals ' + self.name) if __name__ == '__main__': class1 = BaseClass() class1.getname() class2 = DerivedClass() class2.getname() # # 运行结果: BaseCalss: Constructor called BaseCalss: self name equals BaseClass BaseCalss: Constructor called DerivedClass: Constructor called self.name init value is BaseClass DerivedClass: self name equals DerivedClass
python不仅仅支持单继承,还支持多继承,字段和方法都可以被继承。在多继承super()只能代表继承的第一个父类,所以您在子类的构造函数中,不能单独使用super().__init__(),
那只是表示调用其中一个基类的构造函数。所以用super就不是那么好用了。还是要用会原来的类名 + init方法来调用。
class BaseClass1: def __init__(self): self.name1 = 'BaseClass1_Name1' self.name = 'BaseClass1_Name' print('BaseCalss1: Constructor called') def getname1(self): print('BaseCalss1: self name1 equals ' + self.name1) def getname(self): print('BaseCalss1: getname called, name equal ' + self.name) class BaseClass2: def __init__(self): self.name2 = 'BaseClass2_Name2' self.name = 'BaseClass2_Name' print('BaseClass2: Constructor called') def getname2(self): print('BaseClass2: self name2 equals ' + self.name2) def getname(self): print('BaseCalss2: getname called, name equal ' + self.name) class DerivedClass2(BaseClass1, BaseClass2): def __init__(self): BaseClass1.__init__(self) BaseClass2.__init__(self) print('DerivedClass: Constructor called') if __name__ == '__main__': class1 = BaseClass1() class1.getname1() class2 = BaseClass2() class2.getname2() class3 = DerivedClass2() class3.getname1() class3.getname2() class3.getname() # # 运行结果: BaseCalss1: Constructor called BaseCalss1: self name1 equals BaseClass1_Name1 BaseClass2: Constructor called BaseClass2: self name2 equals BaseClass2_Name2 BaseCalss1: Constructor called BaseClass2: Constructor called DerivedClass: Constructor called BaseCalss1: self name1 equals BaseClass1_Name1 BaseClass2: self name2 equals BaseClass2_Name2 BaseCalss1: getname called, name equal BaseClass2_Name
我们可以看到,当两个基类有方法重名的时候,python3会按照您继承类的从左到右的顺序查找您调用的方法DerivedClass2(BaseClass1,BaseClass2)。在这个例子中,是先找BaseClass1,然后再找BaseClass2。如果您的代码需要多层继承的话,可以参开多重继承的Diamond Problem问题。
class A1: def foo1(self): print("Call A1's foo1") class A2: def foo1(self): print("Call A2's foo1") def foo2(self): print("Call A2's foo2") class B1(A1, A2): pass class B2(A1, A2): def foo2(self): print("Call B2's foo2") class C(B1, B2): pass if __name__ == '__main__': class1 = C() class1.foo1() class1.foo2() # 运行结果: Call A1's foo1 Call B2's foo2
所以对于python3的多层继承来说,因为都是新式类,总是从左到右,广度优先的方式进行。
多态:
多态(英语:Polymorphism),是指面向对象程序运行时,相同的消息可能会送给多个不同的类之对象,而系统可依据对象所属类,引发对应类的方法,而有不同的行为。
简单来说,所谓多态意指相同的消息给予不同的对象会引发不同的动作称之。在面向对象程序设计中,多态一般指子类型多态(Subtypepolymorphism)。
上面的定义有点让初学者费解,黄哥用“打开”这个动作来描述面向对象的多态。"打开",可以是打开门,打开窗户,打开书等等。"打开"这个动作,碰到不同的对象门,窗户,书,有不同的行为模式。
这个就是多态。
# 示例一:
class Door(object): def open(self): print("打开门") class Windows(object): def open(self): print("打开窗户") class Book(object): def open(self): print("打开书") lst = [Door(), Windows(), Book()] for item in lst: item.open()
# 示例二 一般用继承来说明多态的例子
class Animal: def __init__(self, name): self.name = name def talk(self): raise NotImplementedError("Subclass must implement abstract method") class Cat(Animal): def talk(self): return 'Meow!' class Dog(Animal): def talk(self): return 'Woof! Woof!' animals = [Cat('Missy'), Cat('Mr. Mistoffelees'), Dog('Lassie')] for animal in animals: print(animal.name + ': ' + animal.talk())
# #python 内置有很多多态的应用 # 同样的 +号 可以用在不同的对象相加,体现(相仿:指相加这个事情)了多态的功能。 # print (1 + 2) # print ("hello " + 'world') # # # len 函数传不同的参数,也体现了多态的功能。 # print (len("python")) # print (len([2, 4, 5, 7])) #
成员:
字段:静态字段/普通字段
class Foo: stati = '静态字段' def F1(self): general = '普通字段' print(general) return 'F1返回值' print(Foo.stati) #静态字段加载类时自动创建,所以可以直接使用 obj = Foo() obj.F1()
方法:函数在类中就叫做方法。
普通方法 #由对象调用执行
@staticmethod #由类调用执行
@calssmethod #由类调用执行
class Foo: @classmethod def F1(cls,a1): #cls必须要的 print('f1',a1) @staticmethod def F2(a1): #参数至少一个 print(123,a1) Foo.F1(111) #由类调用,不需传入参数 Foo.F2(121) #由类调用,至少传入一个参数
属性:具有方法的写作形式,具有字段的访问形式,即增删改差
@property @x.setter @x.deleter
统计页数 class pager: def __init__(self,all_count): self.all_count = all_count @property def all_pager(self): a1,a2 = divmod(self.all_count,10) if a2 == 0: return a1 else: return a1+1 @all_pager.setter def all_pager(self,values): print('调用了setter') @all_pager.deleter def all_pager(self): print('调用了deleter') p = pager(11) #创建对象 ret = p.all_pager #对象调用类中的方法,不加property时应该是p.all_paper(),使用了property后调用方法不用加() #即加了@property后,调用该方法不用需要 对象.方法()而直接 对象.方法 print(ret) p.all_pager = 111 #类中的all_paper方法使用了@property,则在使用p.all_paper = 时就会调用 类中加了all_paper.setter下面的方法,并且all_paper.setter下面的方法名也必须为all_paper del p.all_pager
*反射:把字符串反射成内存地址
hasattr() 、 delattr() 、 setattr() 、 getattr()
反射即想到4个内置函数分别为:getattr、hasattr、setattr、delattr 获取成员、检查成员、设置成员、删除成员下面逐一介绍先看例子: class Foo(object): def __init__(self): self.name = 'abc' def func(self): return 'ok' obj = Foo() #获取成员 ret = getattr(obj, 'func')#获取的是个对象 r = ret() print(r) #检查成员 ret = hasattr(obj,'func')#因为有func方法所以返回True print(ret) #设置成员 print(obj.name) #设置之前为:abc ret = setattr(obj,'name',19) print(obj.name) #设置之后为:19 #删除成员 print(obj.name) #abc delattr(obj,'name') print(obj.name) #报错
对于反射小节:
1.根据字符串的形式导入模块。
2.根据字符串的形式去对象(某个模块)中操作其成员