Python基础之语句、函数、类(二)

188 阅读8分钟

1.语句

1.1 print语句

print('age',42)
print('age',42,sep = "-")#自定义分割符
print('age',42,end = '!')#自定义结束符

1.2 import语句

import math可以调用math.sqrt(),from math import sqrt可以直接用sqrt()

1.3 赋值语句

  • 序列解包:"="的左右两边互相对应时赋值,'*'可以接受多余的值
name = 'a b c d'
first, *middle, last = name.split()#middle是['b', 'c']
  • 链式赋值
a = b = 3

1.4 条件语句


if else,elif = else if,注意==是判断引用变量的值是否相等,is是判断两个变量的引用对象是否相同

1.5 断言

assert充当判断

assert 0 < age < 100, 'the age must be realistic'

1.6 循环语句

  • for(range), while, break, continue等关键字。
    while可以和else直接配合,没执行break时会执行else
from math import sqrt
for n in range(99, 81, -1):
    root = sqrt(n)
    if root == int(root):
        print(n)
        break 
else:
    print("Didn't find it!")
  • zip(list1, list2) 得到可迭代对象,用list()转化后可以解包,长度不同时按照最小序列长度
names = ['anne', 'beth', 'george', 'damon']
ages = [12, 45, 32, 102]
list(zip(names,ages))#[('anne', 12), ('beth', 45), ('george', 32), ('damon', 102)]
for name, age in zip(names, ages): 
    print(name, 'is', age, 'years old')
  • enumerate方便迭代时获取索引

1.7 简单推导语句

print([x*x for x in range(10) if x % 3 == 0])
print([(x, y) for x in range(10) for y in range(3)])#2重循环

1.8 pass语句

1.9 del语句

注意:python中'='符号只是对象的引用,当r=s表示指向了同一个空间,如果这个空间不删掉,就算r=None,s=None也是没用的;del可以删除名称r,s,但也没删除空间

s = {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
r = s
s = None#现在令s指向另一块存储空间,r指向的空间没变,所以也有值!!!'='并不是改变的原空间,即r和s都是对象的引用而已
print(r)
r = None#但如果把r也转移,那这个字典就漂浮在计算机内存中,Python解释器直接将其删除,另一种方法是用del
del r#删除名称r,并不是删除了空间,若还有指向空间的,则也有值

1.10 exec语句

  • 将字符串作为代码执行
exec("print('hello world')")
  • 用来避免命名空间的错误 只有一个参数时会出现问题
from math import sqrt
scope = {}
exec('sqrt = 1', scope)
print(sqrt(4))#正常执行
print(scope['sqrt'])#scope最为字典从中取值
print(scope)#key有两个:sqrt和__builtins__,__builtins__是包含所有内置函数和值的字典

1.11 eval语句

计算用字符串表示的Python表达式的值,并返回结果(exec什么都不返回,因为它本身是条语句) (神奇,可以自动计算)

2.函数

2.1 __doc__属性

2.2局部作用域

  • 不可变类型不会被改变
def try_to_change(n):
    n = 'Mr.Gumby'
name = 'Mrs.Gumby'
try_to_change(name)
print(name)#name不会变,因为n=name后,n=xx,则n的指向变了

#或者说,传入的是不可变类型,于是新建一个a,这个a是2的引用(并且是局部的),与传入的a没关系
def func(a):
    a = 2
    return a

a = 1
print(func(a))#2
print(a)#1
  • 可变类型会被改变
def change(n):
    n[0] = 'Mr. Gumby'
names = ['Mrs. Entity', 'Mrs. Thing']
change(names)
print(names)#names是变了的,很简单,因为指向的列表,列表内容变了,并不是让他指向别处了
#但是如果传入切片就不用变
change(names[:])
print(names)#不会变,因为切片是副本

2.3 参数

  • 关键字参数
def hello_4(name, greeting='Hello', punctuation='!'):
    print('{}, {}{}'.format(greeting, name, punctuation))
  • 收集参数时用:*用在定义的地方
    • *接收元组,** 接收字典
 def in_the_middle(x,*y,z):
    print(x,z,y)
in_the_middle(1,2,3,4,5,z=6)#如果不在最后,最后一个必须指定=

def demo(num, *args,**kwargs):
    print(num)
    print(args)#(2, 3)
    print(kwargs)
demo(1,2,3,name = "ab",age = 18)#{'name': 'ab', 'age': 18}

def demo2(*args,**kwargs):
    print(args)
    print(kwargs)
p1 = (1,2,3)
p2 = {"name" : "ab","age" : 18}
demo2(p1, p2)#args会把p1p2当作2个参数,放在一个元组里,实际需要拆包,把p1p2的值都分出来,然后再让定义中的args kwargs接收
'''
((1, 2, 3), {'name': 'ab', 'age': 18})
{}
'''
demo2(*p1, **p2)
  • 分配参数时用,*用到调用函数的地方
def add(x, y):
    return x + y
params = (1, 2)#参数是元组,用*
add(*params)#自动拆开

def hello_3(greeting='Hello', name='world'):
    print('{}, {}!'.format(greeting, name))
params = {'name': 'Sir Robin', 'greeting': 'Well met'}#参数是字典,用**,相当于多指定了名字而已
hello_3(**params)#自动拆开

2.4 变量

  • 局部变量与全局变量 局部变量:函数内,全局变量:在函数内如果有局部变量和他同名可能出现问题,常用globals来访问,globals[key]
def combine(parameter): 
    print(parameter + globals()['parameter'])
parameter = 'berry'
combine('Shrub')
  • 重新关联
x = 1
def change_global():
    global x
    x=x+1
change_global()
print(x)

2.5 新函数

  • map(func, seq[, seq, ...]):对序列中的所有元素执行函数
  • filter(func, seq):返回一个列表,其中包含对其执行函数时结果为真的所有元素
  • reduce(func, seq[, initial]):等价于 func(func(func(seq[0], seq[1]), seq[2]), ...)
  • sum(seq):返回 seq 中所有元素的和
  • apply(func[, args[, kwargs]]):调用函数(还提供要传递给函数的参数)

3.对象

3.1 多态

通俗来说是只关心对象的实例方法是否同名,不关心对象所属的类型

class Duck(object):                                  # 鸭子类
    def fly(self):
        print("鸭子沿着地面飞起来了")

class Swan(object):                                  # 天鹅类
    def fly(self):
        print("天鹅在空中翱翔")

class Plane(object):                                 # 飞机类
    def fly(self):
        print("飞机隆隆地起飞了")

def fly(obj):                                        # 实现飞的功能函数
    obj.fly()

duck = Duck()
fly(duck)

swan = Swan()
fly(swan)

3.2 封装

向外部隐藏不必要的细节:无需知道对象的构造就能使用它,多态则是无需知道类型

3.3 继承

创建一个与之很像的类(可能只是新增了几个方法)

3.4 类

  • self

指向对象本身,每次创建实例的时候,传入的第一个参数就是对象本身

  • 隐藏

    补充单下划线和双下划线的对比

    • 双下滑线开头和结尾:Python的魔法函数,比如_init_()和__str__等等。不用要这种方式命名自己的变量或者函数。
    • 双下划线开头:在前面加上“__”,表示它是私有成员实例和子类不能访问。比如 “__xxx” 如果要访问得通过** _class__xxx 的方式进行访问**。虽然不能防止修改私有属性,但可以有效降低有意或者无意的修改。(其实dir(实例a)会有一个'_class_xxx'的)
    • 单下划线开头:不能用from module import * 导入,其他方面和公有一样访问。
class Secretive:
    def __inaccessible(self):
        print("Bet you can't see me ...")
    def accessible(self):
        print("The secret message is:") 
        self.__inaccessible()
s = Secretive()
#s.__inaccessible()#不能访问,错误
s.accessible()#可以访问,在类里面
#s._Secretive__inaccessible()#在开头加上一个下划线和类名可以访问,但不应该这样做
  • 类的命名空间

在class语句中的代码是特殊的命名空间,相当于全局

#类的所以成员都要访问这个空间,比如拿来计算实例的数量;
#相当于那个空间是全局的,默认情况下m1.members和m2.members都指向那个空间,但是m1.members = 'Two'后它的指向就变了
class MemberCounter: 
    members = 0
    def init(self): 
        MemberCounter.members += 1
m1 = MemberCounter()
m1.init()
print(MemberCounter.members)#是1
m2 = MemberCounter()
m2.init()
print(MemberCounter.members)#是2
m1.members#是2
m2.members#是2
m1.members = 'Two'#m2.members不会变还是2,相当于这个是全局,重新命名的是另一个新空间吧,或者说=让m1.members指向了'two'
  • 类的继承

内置方法:issubclass(子,父);
属性:子.__bases__找父类;
属性:对象.__class__找对象属于哪个类
多个类:按照广度优先寻找,按照括号继承顺序找

  • 多个超类

如果有同名方法,会在class语句中按照顺序覆盖

  • 接口

实现特定的方法,依赖于多态来调用这些方法

  • 抽象基类
from abc import ABC, abstractmethod
class Talker(ABC): 
    @abstractmethod #@是装饰器,这里表示方法是抽象的,该类不应该实例化,职责是定义必须在子类中实现的方法:如果子类也不重写这个方法,则也不能实例化
    def talk(self):
        pass
  • 其他和对象相关的方法
callable(object):判断对象是否是可调用的(如是否是函数或方法)
getattr(object,name[,default]):获取属性的值,还可提供默认值
hasattr(object, name):确定对象是否有指定的属性
isinstance(object, class):确定对象是否是指定类的实例
issubclass(A, B):确定A是否是B的子类
random.choice(sequence):从一个非空序列中随机地选择一个元素
setattr(object, name, value):将对象的指定属性设置为指定的值
type(object):返回对象的类型
dir(ogject):查看对象所有方法
- __new__:在创建对象时自动调用
- __init__:初始化时自动调用
- __del__:对象从内存中销毁时自动调用
- __str__:返回对象描述信息时,例如print()时调用
- __call__:平时自定义的函数、内置函数、类都是可调用对象,可以加()使用的,用callable(a)判断是不是可调用