python学习笔记

text = "我叫{0},今年{1}岁".format("cdh",23)
text = "我叫{0},今年{1}岁,真实姓名是{0}".format("cdh",23)
text = "我叫{n1},今年{1}岁,真实姓名是{0}".format(n1 = "cdh")
text = "我叫{0},今年{1}岁"
data1 = text.format("cdh",23)
data2 = text.format("ckj",23)
name = "cdh"
text = "我叫%s,今年23岁" %name
name = "cdh"
age = 23
text = "我叫%s,今年%d岁" %(name,age)
message = "%(name)s出货啦!" %{"name":"cdh"}
text = "%s,已经完成了90%%了" %"老板"
print(text)

2.3 f

到python3.6版本

text = f"我喜欢{'跑步'}"
action = "跑步"
text = f"我喜欢{action}"
name = "喵喵"
age = 5
text = f"我的猫叫{name},今年{age}岁"

可以传入表达式

text = f"我的猫叫喵喵,今年{5+1}岁"
#进制转换
text = f"我的猫今年{5}岁"

#转换为二进制
text2 = f"我的猫今年{5:#b}岁"
#八进制
text2 = f"我的猫今年{5:#o}岁"
#十六进制
text2 = f"我的猫今年{5:#x}岁"

3.1 运算符

成员运算,是否包含

in 
not in
优先级:算数运算符>比较> not and or
4 Python中的编码
字符串(str) unicode编码
字节(byte) utf-8或gbk编码
text = "巧克力"
text2 = "巧克力".encode("utf-8")
text2 = "巧克力".encode("gbk")
5 Python中的进制
v1 = bin(25) #十进制转换为二进制 0b11001
v1 = oct(25) #十进制转换为八进制 0o27
v1 = hex(25) #十进制转换为十六进制 0x1c

int("0b11001",base = 2) #二进制转换为十进制

数据类型

python3中去除了long只剩下:int(整型),并且int长度不再限制

1.1 地板除
  • Py3:

    v1 = 9/2
    print(v1) #4.5
    
  • Py2:

    v1 = 9/2
    print(v1) #4
    
    from _future_ import division
    
    v1 = 9/2
    print(v1) #4.5
    

字符串

#判断开头 结尾
str.startwith()
str.endwith()
#判断字符串是否为十进制整数
str.isdecimal()
#去除字符串两边的空格、换行符、制表符,得到一个新的字符串
str.strip()
str.lstrip()# 去除左边的空白
str.rstrip()# 去除右边的空白
# 去除字符串两边指定的内容
str.strip("something")
#字符串内容变大写 得到一个新的字符串
str.upper()
#字符串变小写
str.lower()
# 字符串内容替换
str.replace("old","new")
# 字符串切割,得到一个列表
data = "dd|root|dd@qq.com"
result = data.split('|') #['dd','root','dd@qq.com']
result2 = data.split('|',1) #['dd','root|dd@qq.com'] 数字控制切几个
result2 = data.rsplit('|',1) #['dd|root','dd@qq.com'] 从右边开始切
# 字符串拼接 形成一个字符串
data_list = ['cdh','like','dog']
v1 = "*".join(data_list) #用"*"拼接字符串 cdh*like*dog
# 字符串格式化见上面
# 字符串转换为字节类型
data = "cdh" # unicode,字符串类型
v1 = data.encode("utf-8") # utf-8,字节类型
a1 = v1.decode("utf-8") #cdh
# 字符串内容居中、居左、居右
v1 = "cdh"
data = v1.center(21,"*") # *********cdh*********
data = v1.ljust(21,"*") #居左 cdh******************
data = v1.rjust(21,"*") #居右 ******************cdh
# 填充0
str.zfill(num)
# 应用:处理二进制数据
data = "101"
v1 = data.zfill(8) # 00000101
#字符串长度
len(str)
#可以通过索引取值无法修改值
#获取字符串中的子序列 只能读取不能修改
str[num1:num2] #num1取 num2不取
str[num1:num2:num3] #num3步长
range(10) #[0,1,2,3,4,5,6,7,8,9]
range(1,10) #[1,2,3,4,5,6,7,8,9]
range(1,10,2) #[1,3,5,7,9]
range(10,1,-1) #[10,9,8,7,6,5,4,3,2]

字符串不可被修改

列表

列表(list)有序可变,可以存放多个不同类型的元素
不可变类型:字符串、布尔、整型
list.append("something") #添加元素
#批量追加
list.extend(list)
# 插入
list.insert(index,thing)
# 删除
list.remove(value)# 存在才能删,否则报错
list.pop(index)# 按照索引删除 可以将删除的值赋值给另一个变量
list.index(value)# 找值的索引位置 值需要存在
list.sort() #排序
list.sort(reverse = True) #从大到小排序
ord(char) #获取unicode值(十进制形式)
#列表可以相加、相乘
# in 关键字可以判断元素是否在列表中
if str in list:
    ...

len(list) #获取列表长度
del list[index] #删除元素
#切片
list[index1:index2] #前取后不取
list[index1:index2:step]
#实例:列表翻转
list = ["cdh","ckj","asd"]
new_list = list[::-1]
print(new_list)

list = ["cdh","ckj","asd"]
list.reverse() #列表独有的功能
print(list)
#for循环
list = ["cdh","ckj","asd"]
for item in list:
    print(item)
    
list = ["cdh","ckj","asd"]
for index in range(len(list)):
	item = list[index]
    print(item)
# !!!循环中对数据进行删除,结果会出错
for item in list:
    if ...:
        list.remove(item)#错误!!!!!
        
#正确做法:倒着删除
for index in range(len(list)-1,-1,-1):
	item = list[index]
    if ...:
        list.remove(item)
#列表中可以嵌套列表

元组

元组(tuple):有序、不可变的容器

#example
v1 = (11,22,33)
v2 = ("cdh","ckj")
v3 = (True,11,"cdh")
#建议:在元组的最后加一个",",表明这是一个元组
d1 = (1) #整型1
d2 = (1,) #元组(1,)
#与列表相似,元组可以相加、相乘、取长度、索引、切片、步长、for循环
#其他类型数据变元组 tuple(其他类型) 暂时只有str、list、set可以转换
name = "cdh"
data = tuple(name)
print(data) #输出("c","d","h")

name = ["cdh","ckj"]
data = tuple(name)
print(data) #输出("cdh","ckj")
#元组中可以嵌套元组

集合(set)

集合:无序、可变、不允许数据重复的容器

v1 = {11,22,33,"cdh"}
  • 无序:无法通过索引取值

  • 可变:可以添加或删除元素

  • 不允许数据重复。

    v1 = {11,22,33}
    v1.add(11)
    print(v1) #{11,22,33}
    
注意:定义空集合时,只能用v = set(),不能v = {} (这样是空字典)
v1 = [] #空列表
v11 = list()

v2 = () #空元组
v22 = tuple()

v3 = set() #空集合

v4 = {} #空字典
v44 = dict()
独有功能

1.添加元素

data = {"cdh","ckj"}
data.add("asd")

2.删除元素

data = {"cdh","ckj"}
data.discard("cdh")

3.交集

set1.intersection(set2)
set1 & set2

4.并集

s1.union(s2)
s1 | s2

5.差集

s1 - s2
s1.difference(s2) #s1中有s2中没有的值
公共功能

求长度、for循环

转换
set(其他类型) #可以用来去重!!!
集合中的元素必须是可哈希的!

目前可哈希的数据类型:int、bool、str、tuple,而list、set是不可哈希的

总结:集合中的元素只能是int、bool、str、tuple

None类型

相当于其他语言中的null,意味着这个值啥都不是或表示空

字典(dict)

字典是无序、键不重复且元素只能是键值对的可变容器

  • 元素必须是键值对
  • 键不重复,重复则会被覆盖
  • 无序(python3.6+字典是有序的了,之前是无序的)
data = {"k1":1,"k2":2}
info = {
    "age":12,
    "status":True,
    "name":"ckj",
    "hobby":["游泳","阅读"]
}

键值的要求:

  • 键:必须可哈希。目前为止,可哈希的 int/bool/str/tuple;不可哈希的 list/set/dict
  • 值:任意类型
独有功能

1.获取值

info = {
    "age":12,
    "status":True,
    "name":"ckj",
    "hobby":["游泳","阅读"]
}

data = info.get("name")
print(data) #输出:ckj

data2 = info.get("email")
print(data2) #键不存在返回None

data3 = info.get("email",123)
print(data3) #键存在,返回对应的值,键不存在,返回123

2.所有的键

info = {
    "age":12,
    "status":True,
    "name":"ckj",
    "hobby":["游泳","阅读"]
}

data = info.keys()
print(data) #dict_keys(['age','status','name','hobby'])

3.所以的值

info = {
    "age":12,
    "status":True,
    "name":"ckj",
    "hobby":["游泳","阅读"]
}

data = info.values()
print(data) #dict_keys([12,True,'ckj',['游泳','阅读']])

4.所有的键值

info = {
    "age":12,
    "status":True,
    "name":"ckj",
    "hobby":["游泳","阅读"]
}

data = info.items()
print(data) #dict_keys([('age',12),('status',True),('name','ckj'),('hobby',['游泳','阅读'])])
for key,value in info.items():
	print(key,value) #可以将键值从元组中拆分出来
#设置值
data.setdefault("key",value) #不存在则添加,存在就不设置了

#更新键值对
data.update(dict) #传入的是一个字典,不存在则添加,存在则修改

#移除键值对
data = dict.pop("key") #data获取到移除的键对应的值

#按顺序移除(后进先出)
data = dict.popitem() #data是一个元组包含键值
#3.6之后移除最后一个
#3.6之前随机移除
公共功能
求并集(python3.9 后加入)
dict3 = dict1 | dict2
求长度
len(dict)
是否包含
if "key" in dict: #判断键是否在字典里
    ...

if "key" in dict.keys():
	...
 
if "value" in dict.values():
    ...
 
if ("key","value") in dict.items():
    ...
索引(键)
dict["key"]

#根据键可以修改、添加、删除键值对
dict["key"] = "value" #没有则添加,有则修改

del dict["key"] #删除键值对 不存在时报错
转换(对转换的类型格式有要求)
字典会对键进行哈希处理!

浮点型(float)

浮点型转换为整型,小数点之后的内容舍弃

#保留小数点后N位,会完成四舍五入
v1 = 3.1415926
result = round(v1,3)
print(result) #3.142

若需要精确的小数运算

import decimal

v1 = decimal.Decimal("0.1")
v2 = decimal.Decimal("0.2")
v3 = v1 + v2
print(v3) #0.3

is 和 == 的区别

  • == 比较两个值是否相等
  • is 表示内存地址是否一致

位运算

  • &,与

  • |,或

  • ^,异或

  • ~,取反

  • <<,左移

  • >> #右移
    

模块

导入路径

会去指定路径下查找导入的模块,现在当前目录下找,之后去python内部路径下找

导入模块时添加路径

import sys
sys.path.append('pathA') # sys.path返回一个列表
import xxxxx # 导入的路径下的py文件
import os
os.path.abspath(__file__) #当前文件所在绝对路径
os.path.dirname(pathA) #pathA的上一层路径
pycharm会自动把项目目录加入到 sys.path!
导入方式
导入一个模块
import xxx #xxx.fun()
import xxx.xxx # 使用模块下函数时需写出完整路径 xxx.xxx.fun()
import xxx.xxx as aa # aa.fun()
导入成员
from xxx import fun #fun()
from xxx import xx #xx.fun()
  • import:导入项目根目录的包或模块
  • from:导入嵌套的包或模块

导入同名的模块或成员时取别名!

  • 执行一个py文件时

    __name__ = "__main__"
    
  • 导入一个py文件时

    __name__ = "模块名"
    

python 中主文件可以通过如下代码识别

if __name__ = '__main__': #也可用来进行模块测试
    ...
第三方模块

pip默认安装最新版本,如果想指定安装的版本

pip3.9 install 模块名称==版本

#例如
pip3.9 install django==2.2

从国内的源下载模块

  • 一次性使用

    pip3.9 install 模块名称 -i https://pypi.douban.com/simple/
    
  • 永久使用

    配置

    # 在终端执行如下命令
    pip3.9 config set global.index-url https://pypi.douban.com/simple/
    # 也可打开文件直接修改源
    User/name/.config/pip/pip.conf
    

其他源

阿里云 http://mirrors.aliyun.com/pypi/simple/
清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/

函数

默认参数
def func(a1, a2, a3 = 10):
    print(a1 + a2 + a3)
    
#位置传参
func(4,12)
func(4,12,33)

#关键字传参(位置和关键混合时,关键字传参要在后面)
func(12,9,a3=90)
func(12,a2=3,a3=90)
动态参数
    def func(*args):
    	print(args) #args为元组类型
        
    #只能按位置传参
    func(22)
    func(22,33)
    func()
    

def func(**kwargs):
    print(kwargs) #字典类型
    
#只能按关键字传参
func(n1 = "cdh") #{"n1":"cdh"}
func(n1 = "cdh",n2 = "ckj") #{"n1":"cdh","n2":"ckj"}
  • ,*

    def func(*args,**kwargs):
        print(args,kwargs)
        
    #根据传值的方式自动将数据放进元组或字典
    func(22,12)
    func(22,n1 = "cdh")
    
    #**必须放在*后面
    #参数和动态参数混合时,动态参数放在后面
    
查看某个值在内存中的地址
v1 = "cdh"
addr = id(v1)

print(addr)
python函数执行传参时,传递的是内存地址!!!

好处:

  • 节省内存
  • 对可变类型进行修改时,所有地方都会修改。可变类型:字典、列表、集合

在python中如果想只传递值,可以先拷贝一份

import copy
new_data = copy.deepcopy(data)
func(new_data)
python中函数的返回值是内存地址!!!
函数中的默认参数

python在创建函数(未执行)时,如果发现函数存在默认参数,则在函数内部会创建一块区域并维护这个默认值

  • 执行函数未传值时,则让a2指向函数维护的那个值的地址
  • 执行函数传值时,则让a2指向新传入的值的地址
当默认参数的值是可变类型(list/dict/set)并且在函数内部会修改这一值时,会出现问题!
#在函数内存中维护一块区域存储 100010001
def func(a1,a2=[1,2]):
    a2.append(666)
    print(a1,a2)

#a1 = 100
#a2 -> 100010001
func(100) # 100 [1,2,666]

#a1 = 200
#a2 -> 100010001
func(200) # 200 [1,2,666,666]

#a1 = 99
#a2 -> 111111101
func(99,[77,88]) # 99 [77,88,666]

#a1 = 300
#a2 -> 100010001
func(300) # 300 [1,2,666,666,666]

在定义函数时可以用*和** ,在执行函数时,也可以使用

  • 形参固定,实参用*和**

    def func(a1,a2):
        print(a1,a2)
        
    func(11,22)
    func(a1=1,a2=2)
    
    func(*[11,22])
    func(**{"a1":11,"a2":22})
    
  • 形参用*和**,实参也用

    def func(*args,**kwargs):
        print(args,kwargs)
        
    func(11,22)
    func(11,22,name="cdh",age=18)
    
    #小坑, ([11,22,33],{"k1":1,"k2":2}),{}
    func([11,22,33],{"k1":1,"k2":2})
    
    #args=(11,22,33),kwargs={"k1":1,"k2":2}
    func(*[11,22,33],**{"k1":1,"k2":2})
    
    #注意:按这种方式传参,数据会拷贝一份
    

所以,在使用format字符串格式化时,可以这样:

v1 = "我是{},年龄:{}".format("cdh",18)
v2 = "我是{name},年龄{age}".format(name="cdh",age=18)

v1 = "我是{},年龄:{}".format(*["cdh",18])
v2 = "我是{name},年龄{age}".format(**{"name":"cdh","age":18})

函数名其实就是一个变量,可以作为列表或字典中的元素
def func():
    return 123

data_list = ["cdh","func",func,func()]

print(data_list[0]) #字符串"cdh"
print(data_list[1]) #字符串"func"
print(data_list[2]) #函数func
print(data_list[3]) #执行函数,获得返回值,整数123

res = data_list[2]()
print(res) #执行函数,输出返回值

#注意:函数可以被哈希,所以函数名可以作为集合的元素、字典的键

使用场景:

def send_message(phone,content):
    """发送消息"""
    pass

def send_image(img_path,content):
    """发送图片"""
    pass

def send_emoji(emoji):
    """发送表情"""
    pass

def send_file(path):
    """发送文件"""
    pass

function_dict = {
    "1":[send_message, ['18861524789','hello!']],
    "2":[send_image, ['xxx/xxx/xxx.png','content']],
    "3":[send_emoji, ["some_emoji"]],
    "4":[send_file, ['xx.zip']]
}

print("欢迎使用xx系统")
print("请选择:1.发送消息;2.发送图片;3.发送表情;4.发送文字")
choice = input("请输入选择的序号")

item = function_dict(choice) #如果没有会返回None
if not item:
    print("输入错误!")
else:
    #执行函数
    func = item[0]
    param_list = item[1]
    func(*param_list)

使用场景2

def send_msg(mobile, content):
    """发送短信"""
    pass

def send_email(to_email, subject, content):
    """发送邮件"""
    pass

def send_wechat(user_id, content):
    """发送微信"""
    pass

func_list = [
    {"name": send_msg, "params": {'mobile':"18852462589","content":"你有新消息"}},
    {"name": send_email, "params": {'to_email':"1845236589@qq.com","subject":"你有新消息","content":"你好"}},
    {"name": send_wechat, "params": {'user_id':"12","content":"你有新消息"}}
]

for item in func_list:
    func = item['name']
    param_dict = item['params']
    func(**param_dict)
在局部可以读取全局变量或修改全局变量的内部元素(可变类型),但无法对全局变量重新赋值
若要在局部修改全局的值,可以使用global关键字
COUNTRY = "China" #全局变量名尽量用大写

def upload():
    global COUNTRY
    COUNTRY = "中华人民共和国"
函数如果返回两个值,用逗号","分割,那么返回的是一个元组!
函数嵌套:可以防止函数重名
装饰器
  • 实现原理:基于@语法和函数闭包,将原函数封装在闭包中,然后将函数赋值为一个新的函数(内层函数),执行函数时在内层函数中执行闭包中的原函数。

  • 实现效果:可以在不改变原函数内部代码和调用方式的前提下,实现函数执行和执行扩展功能

  • 适用场景:多个函数系统统一在执行前后自定义一些功能

  • 装饰器示例

    import functools
    
    def outer(origin):
        @functools.wraps(func) # inner.__name__ = func.__name__  inner.__doc__ = func.__doc__
        def inner(*args, **kwargs):
            #执行前
            res = origin(*args, **kwargs)#调用原来的unc函数
            #执行后
            return res
        return inner
    
    @outer
    def func():
        pass
    
    func()
    
python中@的用法
#在某个函数上方使用:
@函数名
def xxx():
    pass
#python 内部会自动执行 函数名(xxx),执行完之后再将结果赋值给xxx
#相当于执行了
#xxx = 函数名(xxx) 函数名所指代的函数需在之前申明!!
匿名函数

基于Lambda定义的函数,格式为:lambda 参数:函数体

  • 参数,支持任意参数

    lambda x: 函数体
    lambda x1,x2: 函数体
    lambda *args, **kwargs: 函数体
    
  • 函数体,只支持单行的代码

    lambda x:x+100
    
  • 返回值,默认将函数体单行代码执行的结果返回给函数的执行者

    func = lambda x: x+100
    
    v1 = func(10)
    print(v1) #110
    
三元运算
结果 = 条件成立时 if 条件 else 不成立
生成器
记录在函数中的执行位置,下次执行next时,会从上一次的位置基础上再继续向下执行
当函数中有yield时,这个函数就是生成器函数
执行生成器函数时,会返回一个生成器对象
注意:执行生成器函数时,函数内部代码不会执行!!
def func():
    print(123)
    yield 123
    
v1 = func()#函数体默认不会执行,返回一个生成器对象
#next里面放生成器对象,进入生成器函数并执行其中的代码,执行到yield为止
next(v1)
#n1 = next(v1) n1接收yield的返回值
推导式

用一行代码创建list、dict、tuple、set的同时初始化一些值

  • 列表

    num_list = [i for i in range(10)]
    
    num_list = [[i,i] for i in range(10)]
    
    num_list = [[i,i] for i in range(10) if i > 6]
    
    v = [lambda :x for x in range(10)] #列表中存放10个函数
    
  • 集合

    num_set = {i for i in range(10)}
    
    num_set = {(i,i,i) for i in range(10)}
    
    num_set = {(i,i,i) for i in range(10) if i > 3}
    
  • 字典

    num_dict = {i:i for i in range(10)}
    
    num_dict = {i:(i,11) for i in range(10)}
    
    num_dict = {i:(i,11) for i in range(10) if i > 7}
    
  • 元组,不同于其他类型。

    #不会立即执行内部循环去生成数据,而是得到一个生成器。
    data = (i for i in range(10))
    print(data)
    for item in data:
        print(item)
    

生成器函数实现斐波那锲数列

def fib(max_count):
    first = 1
    second = 0  #前两个值的设置是关键!!!!
    count = 0
    while count < max_count:
        next_value = first + second
        first = second
        second = next_value
        yield next_value
        count += 1
        
limit_count = imput("输入要生成的斐波那锲数列的个数")
limit_count = int(limit_count)
fib_generator = fib(limit_count)
for num in fib_generator:
    print(num)
正则表达式
1.字符相关
  • cdh 匹配文本中的cdh

    import re
    text = "..."
    data_list = re.findall("cdh",text)
    
  • [abc] 匹配a或b或c字符

    data_list = re.findall("[abc]",text)
    
    data_list = re.findall("q[abc]",text) #qa、qb、qc
    
  • [^abc]匹配除了abc以外的其他字符

  • [a-z]匹配a-z的任意字符([0-9]也可以)

  • . 代指处换行符以外的任意字符

    data_list = re.findall("r.o",text) #rao、roo,.只能指代一个字符
    
    data_list = re.findall("r.+o",text) #贪婪匹配,中间可以有任意个字符,获得最长的符合要求的字符
    
    data_list = re.findall("r.+?o",text) #非贪婪匹配,获得最短的符合要求的字符
    
  • \w 指代字母或数字或下划线(汉字)

  • \d 代指数字

  • \s 代指任意的空白符,包括空格、制表符等

2.数量相关
  • *重复0次或更多次
  • +重复1次或更多次
  • ?重复0次或1次
  • {n}重复n次
  • {n,}重复n次或更多次
  • {n,m}重复n到m次
3.括号(分组)
  • 提取数据区域
  • 获取指定区域+条件

要求用户的内容必须是指定的内容开头和结尾

  • ^开始
  • $结束

特殊字符匹配前用\转义

面向对象

初识面向对象

通过面向对象实现某个功能时,需要两步:

  • 定义类,在类中定义方法,在方法中实现具体功能
  • 实例化类的一个对象,通过对象去调用并执行方法
class Message:
    def send_email(self, email, content):
        data = "给{}发邮件,内容是{}".format(email,content)
        print(data)
        
msg_object = Message() #实例化一个对象
msg_object.send_email("1836581045@qq.com","注册成功")

注意:1.类名首字母大写&驼峰式命名;2.py3之后默认类都继承object;3.在类中编写的函数称为方法;4.每个方法第一个参数为self

对象和self

每个类中都可以定义一个特殊的:__init__初始化方法,在实例化创建对象时自动执行

class Message:
    
    def __init__(self, content):
        self.data = content
    
    def send_email(self, email):
        data = "给{}发邮件,内容是{}".format(email,self.data)
        print(data)
        
#对象 = 类名()  #自动执行类中的 __init__方法
#self指代创建的那个对象,self.data即在对象中创建一个data变量

msg_object = Message("注册成功") #实例化一个对象
msg_object.send_email("1836581045@qq.com")
常见成员
  • 实例变量,属于对象,只能通过对象调用
  • 绑定方法,属于类,通过对象调用或通过类调用
class Person:
    def __init__(self, name, age):
        #实例变量
        self.name = name
        self.age = age
        
    #绑定方法
    def show(self):
        msg = "我叫{},今年{}岁。".format(self.name, self.age)
        print(msg)
继承
class Base:
    
    def func(self):
        print("Base.func")
        
class Son(Base):
    
    def show(self):
        print("Son.show")
        
s1 = Son()
s1.show()
s1.func() #优先在自己的类中找,自己没有才去父类

b1 = Base()
b1.func()
python支持多继承
class TCPServer:
    def f1(self):
        print("TCPServer")
        
class ThreadingMixIn:
    def f1(self):
        print("ThreadingMixIn")
        
class ThreadindTCPServer(ThreadingMixIn, TCPServer):
    def run(self):
        print("before")
        self.f1()
        print("after")
        
        
obj = ThreadingTCPServer()
obj.run()

>>> before
>>> ThreadingMixIn #优先去第一个继承的类中找f1
>>> after
变量
  • 实例变量:属于对象,每个对象各自维护自己的数据
  • 类变量:属于类,可以被所有对象共享,一帮用于给对象提供公共数据
class Person():
    country = "中国"
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def show(self):
        message = "{}-{}-{}".format(Person.country, self.name, self.age)
        #message = "{}-{}-{}".format(self.country, self.name, self.age) 
        print(message)
        
print(Person.country) #中国

p1 = Person("cdh", 18)
print(p1.name)
print(p1.age)
print(p1.country) #中国

p1.show() #中国-cdh-18

p1.name = "ckj" #在对象p1中将name重置
p1.num = 12 #在对象p1中新增变量 num = 19
p1.country = "China" #在对象p1中新增变量 country = "China"

print(p1.country) #China
print(Person.country) #中国
方法
  • 绑定方法:默认有一个self参数,由对象进行调用(此时self就等于调用方法的这个对象)【对象和类均可调用】
  • 类方法:默认有一个cls参数,用类或对象都可以调用(此时cls就等于调用方法的这个类)【对象和类均可调用】
  • 静态方法:无默认参数,用类和对象都可以调用
class Foo(object):
    def __init__(self, name):
        self.name = name
        
    def f1(self):
        print("绑定方法", self.name)
        
    @classmethod
    def f2(cls):
        print("类方法", cls)
        
    @staticmethod
    def f3():
        print("静态方法")
        
#绑定方法
obj = Foo("cdh")
obj.f1()

#类方法
Foo.f2() #cls就是当前调用这一方法的类
obj.f2() #cls就是当前调用这个方法的对象的类

#静态方法
Foo.f3()
obj.f3()
属性

由绑定方法+特殊装饰器组合创造出来,在调用方法时可以不加括号,例如:

class Foo(object):
    def __init__(self, name):
        self.name = name
        
    def f1(self):
        return 123
    
    @property
    def f2(self):
        return 123
    
    
obj = Foo("cdh")

v1 = obj.f1()
print(v1)

v2 = obj.f2
print(v2)
成员修饰符
  • 公有,在任何地方都可以调用这个成员
  • 私有,只有在类的内部才可以调用该成员(成员是以两个下划线开头,则表示该成员为私有,方法和属性前也可以加双下划线变为私有),父类中私有成员,子类无法继承
class Foo(object):
    
    def __init__(self, name, age):
        self.__name = name
        self.age = age
        
    def get_data(self):
        return self.__name
    
    def get_age(self):
        return self.age

obj = Foo("cdh", 18)
obj.age
# obj.__name #无法访问
obj.get_data()
特殊成员

在python中存在一些特殊的方法,这些方法都是__方法__格式,均有特殊含义

  • __init__,初始化方法

    class Foo(object):
        def __init__(self, name):
            self.name = name
            
    obj = Foo("cdh")
    
  • __new__,构造方法,在init方法前执行

    class Foo(object):
        def __init__(self, name):
            print("第二步,初始化对象,在空对象中创建数据")
            self.name = name
            
        def __new__(cls, *args, **kwargs):
            print("第一步,先创建空对象并返回")
            return object.__new__(cls)
        
    obj = Foo("cdh")
    
  • __call__

    class Foo(object):
        def __call__(self, *args, **kwargs):
            print("执行call方法")
            
    obj = Foo()
    obj() #执行call方法
    
  • __str__

    class Foo(object):
        def __str__(self):
            return "something"
        
    obj = Foo()
    data = str(obj)
    print(data) #something
    
  • __dict__

    class Foo(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
            
    obj = Foo("cdh", 18)
    print(obj.__dict__) #{"name":"cdh", "age":18}
    
  • __getitem____setitem____delitem__ #可以像列表一样操作类中的成员变量

  • __enter____exit__ #上下文管理

  • __add__ #让两个对象可以相加

  • __iter__

    迭代器
    # 迭代器类型的定义:
    1. 类中定义了 __iter__ 和 __next__两个方法
    2. __iter__ 方法需要返回对象本身,即:self
    3. __next__ 方法,返回下一个数据,如果没有数据了,则需要抛出一个StopIteration的异常
    
    #创建迭代器类型
    class IT(object):
        def __init__(self):
            self.counter = 0
            
        def __iter__(self):
            return self
        
        def __next__(self):
            self.counter += 1
            if self.counter == 3:
                raise StopIteration()
            return self.counter
        
    #根据类实例化创建一个迭代器对象:
    obj = IT()
    
    #V1 = obj.__next__()
    #V1 = obj.__next__()
    #V1 = obj.__next__() #抛出异常
    
    v1 = next(obj) #obj.__next__()
    print(v1)
    
    v2 = next(obj) 
    print(v1)
    
    v3 = next(obj) 
    print(v1)
    
    obj2 = IT()
    for item in obj2: #首先会执行迭代器对象的__iter__方法并获取返回值,然后一直执行next(对象)
        print(item)
    
posted @ 2022-10-14 10:11  糯岩  阅读(40)  评论(0)    收藏  举报