Loading

python基础2(函数 内置函数 类)

函数

定义

def 关键字 -- 定义
    func 函数名 -- 和变量定义规则一样
    ()   必须要写格式
    :    声明语句结束
        
def my_len()
    函数体
例子:
def my_len():
    s = (1,2,3,4,5,6)
    count = 0
    for i in s:
        count += 1
        print(count)

def yue():                           
    print("打开手机")              # 打开手机
    print("打开微信")              # 打开微信
    print("找到女友")              # 找到女友
    print("晚上约么")              # 晚上约么
yue()

函数的返回值

关键字 return
print(12)
def yue():
    print("打开手机")
    print("打开微信")
    return 111
    print("找到女友")
    print("晚上约么")
    return "萝莉小姐姐","大妈","人妖" # return 返回
    print("确实有点累")
print(yue())   #111

有return和没有return
lst = [1,2,3,4,5,6]
def func():
    for i in lst:
        print(i)
print(func())   # None

lst = [1,2,3,4,5]
def func():
    for i in lst:
        print(i)
    lst.append(input(">>>"))
    return lst
print(func())
'''
1
2
3
4
5
>>>9
[1, 2, 3, 4, 5, '9']

注意事项

return的内容返回给了函数的调用

return下方的代码不执行,终止这个函数

return 返回多个内容的时候还是元组形式

return 没有写返回值的时候返回的是None,不写return返回的也是None

位置传参

def yue(a,b,c):    # 形参
    print("打开手机")
    print(f"打开{a}{c}{b}")
    print("附近的人")
    print("找个妹子")
    print("聊一聊")

yue(True,(12,4,3),[1,2,3,4])   # 实参

def func(a,b=1):    # b=1 默认参数
    print(a,b)
func(3,8)



def userinfo(name,age,sex="男"):     位置参数 > 默认参数
    print(name,age,sex)
count = 5
while count:
    name = input("name:")
    sex = input("sex:")
    age = input("age")
    if sex == "女":
        userinfo(name,age,sex)
    else:
        userinfo(name,age)
    count -= 1
    
    
def func(a,c,b=1):         a,c位置参数 ,b=1 是默认参数
    print(a,b,c)
func(1,2,5)

func(a=1,b=5,c=2)           # a=1,b=5,c=2 是关键字参数

def func(a,b,c):
    print(a,b,c)
func(1,2,c=5)               # 混合参数
形参: 函数的定义中括号里是形参
实参: 函数的调用括号里是实参
位置传参时 形参和实参必须一一对应
传参: 将实参传递给形参的过程就是传参
    

总结:# 函数的参数:
    # 形参: 函数定义的时候叫做形参
        # 位置参数
        # 默认参数
        # 混合参数

    # 实参: 函数调用的时候叫做实参
        # 位置参数
        # 关键字参数
        # 混合参数

    # 传参: 将实参传递给形参的过程叫做传参
 

1.函数的动态参数

动态参数

*args,**kwargs (能够接受动态的位置参数和动态的关键字参数)

定义阶段(*args,**kwargs) 聚合

*args - tuple

**kwargs -- dict

使用阶段args,kwargs 打散

*args - 源数据类型

*kwargs - 打散是字典的键

*args

def func(a,b,*args):           
print(a,b,args)                
func(1,2,3,4,5,6,7,8,9)     
# 1 2 (3, 4, 5, 6, 7, 8, 9)

def func(a,b,*args):  
# *args 是万能(接受任意多个)的位置参数 
# *在函数定义的时候叫做聚合
    print(a,b,*args) 
    # * 打散     1 2 3 4 5 6 7 8 9

**kwargs

def func(a,b,**kwargs):  
	print(a,b,kwargs)  
	# 字典(接受的关键字的参数)
func(1,2,c=1,d=2)  
# 1 2 {'c': 1, 'd': 2}



def func(a,b,*args,c=1,d=2,**kwargs): 
	print(a,b,*args,c,d,kwargs)
func(1,2,3,4,c=8,d=10,e="alex",f="wusir")  
#1 2 3 4 8 10 {'e': 'alex', 'f': 'wusir'}

万能传参

def func(*agrs,**kwargs):  
	print(agrs,kwargs)func(1,2,3,4,5,6,7,8,a=1,b=2,c=3)
	# (1, 2, 3, 4, 5, 6, 7, 8) {'a': 1, 'b': 2, 'c': 3}

重点总结:

1.参数的优先级:位置参数 > 动态位置参数 > 默认参数(关键字参数) > 动态关键字参数
2.万能传参:动态位置参数,动态关键字参数(常用)
3.动态位置参数,关键字参数,动态关键字参数

2.函数的注释

def func(a,b):    
		"""    注释:敲六个' " ',回车    
		:param a:    
        :param b:     
        :return:    
        """    
        print(a,b)    
        
def func1(user,password):
	"""    密码加密  
	:param user: 用户名 str 
	:param password: 密码 str
    :return: 加密的密码 MD5   
    """   
    print(user,password)  
    print(func.__doc__)       
    # 查看函数注释print(func.__name__) 
    # 查看函数命名

3.名称空间

def fun():     
	a = 10       
	print(a)fun()print(a)   
    # a不存在了已经..

命名空间分类:

内置空间 : print input len 全局空间 : 当前py文件需要开辟的空间存放在全局空间 局部空间 : 函数中开辟的空间就是局部空间

加载顺序:

内置空间 > 全局空间 > 局部空间

取值顺序:

局部空间 > 全局空间 > 内置空间(找不到就报错了!)

作用域:

全局作用域: 内置空间 + 全局空间

局部作用域: 局部空间

4.函数的嵌套

def func():        
	print(1)    
    
def f1():               
	print(2)        
    return 
f1()
func()                    
# 1 2
不管在什么位置,只要是函数名+() 就是在调用此函数函数调用执行后,函数体中开辟的空间就自动销毁了

示例

def func():  
	a = 1    
def foo():      
	b = 2       
	print(b)  
	print(a)  
    
def f1():          
	print(b)     
	return f1()    
	return foo()
	print(func())                
# 2 1 2 None

globle 与 nonlocal


# 报错局部空间内没有a的值
global : 修改全局空间的变量对应的值
nonlocal :在外层的函数中,修改局部空间的变量值.完全不涉及全局变量,只修改离它最近的一层,最近的一层没有变量继续向上找,直到找到最外层函数

函数名的第一类对象及使用

函数名可以当做值被赋值

def func():    
	print(1)print(func)a = funca()        
# <function func at 0x000001A24F8E9B70>     1

函数名可以当做元素存放在容器中

def func():   
	print(1)
	
lst = [func,func,func]
for i in lst:   
	i()            
    # 1 1 1

函数名可以当做另一个函数的参数

函数名可以当做返回值

函数与方法

通过打印函数名的方式区别方法和函数

def func1(): 
	passclass A:   
def func(self):       
	pass
	# 通过类名调用的类中的实例方法叫做函数
	print(func1)
	print(A.func)
	# 通过对象调用的类中的实例方法叫方法
obj = A()print(obj.func)

from types import FunctionTypefrom types 
import MethodTypedef 
func():    
	passclass A:    
	def func(self):   
    passobj = A()print(isinstance(func, FunctionType))
    print(isinstance(A.func, FunctionType))
    print(isinstance(obj.func, FunctionType))
    print(isinstance(obj.func, MethodType))
    """TrueTrueFalseTrue"""

总结

python 中一切皆对象, 类在某种意义上也是一个对象, python中自己定义的类, 以及大部分内置类, 都是由type元类(构建类)实例化得来的

python 中一切皆对象, 函数在某种意义上也是一个对象,函数这个对象是从FunctionType这个类实例化出来的

python 中一切皆对象, 方法在某种意义上也是一个对象,方法这个对象是从MethodType这个类实例化出来的

如何判断方法还是函数

函数都是显性传参, 方法都是隐性传参

特殊的双下方法

特殊的双下方法:

原本是开发python这个语言的程序员用的, 源码中使用的

双下方法: 你不知道你干了什么就触发某个双下方法

len

class B:    def __init__(self, name, age):    
	self.name = name      
	self.age = age   
	def __len__(self):   
	print(self.__dict__)     
	return len(self.__dict__)
	b = B("liye", 28)print(len(b))
	"""{'name': 'liye', 'age': 28}2"""print(len({"name": "leye", "age":28}))"""2"""
	# len()就会触发__len__方法

hash

class A:    
	def __init__(self):   
    self.a = 1        
    self.b = 2  
    def __hash__(self):    
    return hash(str(self.a)+str(self.b))
    
    a = A()print(hash(a))"""-855395274340638840"""

str ***

class A: 
	def __init__(self, name, age):       
    self.name = name        
    self.age = age   
    def __str__(self):    
    	print(666)        
    	return
        (f"姓名:{self.name} 年龄:{self.age}")
        a = A("赵海狗", 35)
        b = A("李业", 56)
        c = A("华丽", 18)
        print(f"{a.name}{a.age}")print(f"{b.name}{b.age}")
        print(f"{c.name}{c.age}")
        """赵海狗35李业56华丽18
"""
        # 打印对象触发__str__方法
        print(a)
        print(b)
        print(c)
        """666
        
        姓名:赵海狗 年龄:35666姓名:李业 年龄:56666姓名:华丽 年龄:18"""
        # 直接str转化也可以触发print(str(a))
        """666姓名:赵海狗 年龄:35"""

repr

class A:    def __init__(self,name,age):        self.name = name        self.age =age    def __repr__(self):        print(666)        return f'姓名: {self.name} 年龄: {self.age}'a = A('赵海狗',35)b = A('李业',56)c = A('华丽',18)print(a)print(repr(a))"""666姓名:赵海狗 年龄:35666姓名:赵海狗 年龄: 35"""# 用法同 __str__

call ***

# 对象() 自动触发对象从属于类(父类)的__call__方法
class Foo:    
	def __init__(self):  
	pass   
	def __call__(self, *args, **kwargs):   
	print('__call__')
obj = Foo()obj()
"""__call__"""

eq

class A(object): 
	def __init__(self):  
		self.a = 1       
		self.b = 2   
	def __eq__(self,obj):  
	if  self.a == obj.a and self.b == obj.b:    
		return True       
x = A()y = A()print(x == y)"""True"""

del

# 析构方法,当对象在内存中被释放时,自动触发执行。
# 注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。class A:   
	def __del__(self):    
	print(666)


obj = A()del 
obj"""666"""

new

class A(object):  
	def __init__(self):       
        self.x = 1     
		print("in init function")  
	def __new__(cls, *args, **kwargs): 
		print("in new function")    
		return object.__new__(A)a = A()

"""in new functionin init function"""
# 对象是object类的__new__方法 产生一个对象# 类名()
# 1.先触发 object 的__new__方法, 此方法在内存中开辟一个对象空间.
# 2.执行__init__方法,给对象封装属性

单例模式

class A:    
	__instance = None   
	def __init__(self, name):   
		self.name = name   
	def __new__(cls, *args, **kwargs): 
		if not cls.__instance:       
		cls.__instance = object.__new__(cls)   
		return cls.__instanceobj = A("alex")
		print(obj)
obj1 = A("李业")obj2 = A("wusir")
print(obj1.name)
print(obj.name)
print(obj2.name)
"""<__main__.A object at 0x000001E4CFC676A0>wusirwusirwusir"""

item

# __getitem__
__setitem__
__delitem__ 
对对象做类似于字典的 (增删改查) 触发__item__系列
# __delattr__ del 
obj.属性 就会触发此方法
class Foo:    
	def __init__(self, name): 
		self.name = name
	def __getitem__(self, item):  
		print(item)       
		print(666)    
		return self.__dict__[item]  
	def __setitem__(self, key, value):   
		self.__dict__[key] = value    
		print(key)       
		print(value)   
	def __delitem__(self, key):   
		print("del obj[key]时, 我执行") 
	def __delattr__(self, item):    
		print(f"对象的{item}属性已经删除")
f1 = Foo("sb")print(f1["name"])
f1[1] = 2del
f1[1]del
f1.name
"""name666sb12del obj[key]时, 我执行对象的{name}属性已经删除"""

enter exit

class A:   
	def __init__(self, name):  
		self.name = name    
	def __enter__(self): 
	print(666)       
	def __exit__(self, exc_type, exc_val, exc_tb):  
		print(777)
# 第一种实例化方式obj = A("海狗")
# 第二种实例化方式, 必须基于__enter__ 和 __exit__这两个方法with A("海狗") as obj:    print(obj.name)

class A:   
	def __init__(self, text):  
		self.text = text  
	def __enter__(self): 
		# 开启上下文管理器对象时触发此方法  
		self.text = self.text + '您来了'  # 第一步  
		print(11111)      
		return self
		# 必须!!!将实例化的对象返回f1 
	def __exit__(self, exc_type, exc_val, exc_tb):  
		# 执行完上下文管理器对象f1时触发此方法     
		print(333)  
		# 第三步     
		self.text = self.text + ',这就走了'with A('大爷') as f1:    print(2222)    			print(f1.text)  
		# 第二步print(f1.text)  
        # 第四步"""111112222大爷您来了333大爷您来了,这就走了"""

iter

class A:  
	def __init__(self, name):      
		self.name = name  
	def __iter__(self):    
		for i in range(10):       
		yield i   
# def __next__(self): 
#     passobj = A("李业")
print('__iter__' in dir(obj))
print(hasattr(obj, "__iter__"))
# 以上两行都在判断对象是否具有__iter__for i in obj:    print(i)

内置函数(一)

函数名 描述
all() 判断可迭代参数中的所有元素是否都为 True
any() 判断可迭代参数中的所有元素是否都为 False如果有一个为True则返回True
bytes() 返回一个根据参数 source 生成的字节数组(bytes)对象
callable() 查看是否可调用
chr() 用一个范围在0~255整数作参数,返回一个对应的字符
complex() 创建一个值为 real + imag * j 的复数或者转化一个字符串或数为复数
divmod() 返回一个包含商和余数的元组
eval() 执行一个字符串表达式,并返回表达式的值
exec() 动态执行python代码
format() 增强字符串格式化的功能
frozenset() 返回一个冻结的集合
globals() 以字典类型返回当前位置的全部全局变量
hash() 用于获取取一个对象(字符串或者数值等)的哈希值
help() 查看函数或模块用途的详细说明
id() 获取对象的内存地址
input() 接受一个标准输入数据,返回为 str 类型
int() 将一个字符串或数字转换为整型
iter() 生成迭代器
locals() 以字典类型返回当前位置的全部局部变量
next() 返回迭代器的下一个项目
oct() 将一个整数转换成8进制字符串
ord() 以一个字符作为参数,返回对应的 ASCII 数值,或者 Unicode 数值
pow() 方法返回x的y次方的值。
repr() 将对象转化为供解释器读取的形式
round() 返回浮点数x的四舍五入值
eval() 执行字符串类型的代码,并返回最终结果exec() 执行字符串类型的代码以上两个函数很强大,工作中禁止使用hash() 获取一个对象(可哈希对象:int,str,bool,tuple)的哈希值help() 函数用于查看函数或模块用途的详细说明callable() 函数用于检查一个对象是否是可调用的,如果返回True,仍然可能调用失败;但如果返回False,调用对象object绝对不会成功int() 函数用于将一个字符串或数字转换为整型float() 函数用于将整数和字符串转换成浮点数complex:函数用于创建一个值为 real + imag*j 的复数.如果第一个参数为字符串,则不需要指定第二个参数bin() 将十进制转换成二进制oct() 将十进制转换成十六进制字符串并返回divmod() 计算除数与被除数的结果,返回一个包含商和余数的元组round() 保留浮点数的小数位数,默认保留整数pow() 求x**y次幂bytes() 用于不同编码之间的转化ord() 输入当前编码的位置数字找出其对应的字符repr() 返回一个对象的string形式all() 可迭代对象中,全都是True才是Trueany() 可迭代对象中,有一个True 就是True

内置函数(二)

函数名 描述 语法
abs() 绝对值 abs(数字)
filter() 过滤,返回一个迭代器对象的内存地址 filter(函数名,可迭代对象)
map() 指定元素操作,返回一个迭代器对象的内存地址 map(函数名,可迭代对象)
zip() 拉链,可迭代对象是字典的时候只获取键,返回一个迭代器对象的内存地址 zip(可迭代对象,...可迭代对象)
sorted() 排序,默认为升序,返回一个新列表不修改原基础,指定reverse为True 时为降序 sorted(可迭代对象,key=函数名,reverse=True)
reversed() 反转,返回一个迭代器对象的内存地址 reversed(可迭代对象)
max() 最大值,可以自定义规则 max(可迭代对象,key=规则)
min() 最小值,可以自定义规则 min(可迭代对象,key=规则)
sum() 求和,不能使用字符串 sum(可迭代对象)
reduce() 累计算,函数要有两个形参,不能使用字符串 reduce(函数名,可迭代对象)
format() 除了格式化还可以进行进制转换,b二进制 d十进制 o八进制 x16进制,>右对齐,<左对齐,^居中,可以指定位数 format(整数."8b")format(元素,">20")

内置函数

1.abs( ) print([abs(i) for i in lst])# 绝对值 -- 返回的都是正数
2.enumerate( )lst = [(0,1)(1,2)(2,3)]print([i for i in enumerate(lst,10)])# 枚举("可迭代对象","序号的起始值") 默认的起始值是 0 
3.max( ) print(max([1,2,3,4,56,7,8]))# 求最大值print(max([1,2,-33,4,5],key=abs))# key指定查找最大值的规则
4.min( )print(min([1,2,3,4,-56,7,8]))# 求最小值
5.sum( )print(sum([1,2,3,4,5],100))# 求和
6.python3 中:range( )g = range(0,10)g.__iter__()# 范围 本身是一个可迭代对象 有__iter__()方法python2 中:range( )# 获取的是一个列表Xrange( )# 获取的是一个可迭代对象
7.open( )# 文件操作
8.print( )print(sep=" ",end="\n" )print(1,2,3,sep="  ")# sep是多个元素的连接符
9.len( )# 公共方法,求长度的函数(除数字和bool值)
10.list( )# 列表
11.dict( )print(dict([i for i in enumerate(range(20),1)]))# 字典
12.zip( )lst = [1,2,3,4,5]lst1 = ["a","b","c","d","f","e"]print(dict(list(zip(lst,lst1))))# 拉链 -- 按照最少的进行合并
13.dir( )print(dir(list))# 查看当前函数的方法

匿名函数

f = lambda x,y:(x,y)
print(f(1,2))print(f.__name__)   
print((lambda x:x)(2)) 
# 同一行定义 同一行调用lambda 
# 关键字 -- 定义函数x,y   
# 形参:x+y   
# 返回值 -- 只能返回一个数据类型   
示例:
lst = [lambda i:i*i for i in range(10)]print(lst[2](2))

拆解
lst = []
for i in range(10):   
	def func(i):    
	return i*i   
lst.append(func)
print(lst[2](2))
示例

lst = [lambda :i*i for i in range(10)]print(lst[2]())# 81# 
拆解
lst = []
for i in range(10):  
	def func():      
	return i*i   
lst.append(func)
print(lst[2]())
# 一行函数# 形参可以不写# 返回值必须要写,返回值只能返回一个数据类型

内置函数(重要)

1.format( )print(format(13,">20"))
# 右对齐print(format(13,"<20"))
# 左对齐print(format(13,"^20"))
# 居中print(format(13,"08b"))   
# 2进制print(format(13,"08d"))    
# 10进制print(format(13,"08o"))  
# 8进制print(format(12,"08x"))# 16进制
2.filter( )
# 过滤
lst = [1,2,3,4,5,6]
def func(s):  
	return s > 3
	print(list(filter(func,lst)))
	# func就是自己定义一个过滤条件,lst 要迭代的对象
	lst = [1,2,3,4,5,6,7]
	print(list(filter(lambda x:x % 2 == 1,lst)))
3.map( ) 
print(list(map(lambda x:x*x,[1,2,3,8,4,5])))
# 对象映射
# 对可迭代对象中的每个元素进行加工
4.reverse( )  
reversed( )
# 两者都是反转 前者在源数据上进行反转 后者开辟新空间进行反转,不影响源数据
5.sort( )sorted( )
# 两者都是排序 前者在源数据上进行排序 后者开辟新空间进行排序,不影响源数据
lst = [1,23,34,4,5,213,123,41,12,32,1]print(sorted(lst)) 
print(lst)# 升序lst = [1,23,34,4,5,213,123,41,12,32,1]print(sorted(lst,reverse=True))  
# 降序dic = {"key":1,"key1":2,"key3":56}print(sorted(dic,key=lambda x:dic[x],reverse=True))
# 指定key的排序规则
6.reduce( )
from functools import reduceprint
(reduce(lambda x,y:x+y,[1,2,3,4,5]))# 累计算 

面向对象初识

1.函数式编程 对 面向过程编程的两个特点

  1. 减少代码的重复性
  2. 增强代码的可读性

2.面向对象编程 对 面向过程编程

2.1 什么是面向对象

面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。

2.2 什么是类,什么是对象

类:就是具有相同属性和功能的一类事物。

对象:就是类的具体表现。

3.类的结构

class Human:   
"""    此类主要是构建人类  
"""    mind = '有思想' 
# 第一部分:静态属性 属性 静态变量 静态字段   
dic = {}   
l1 = []   
def work(self):
# 第二部分:方法 函数 动态属性     
print('人类会工作')
class 是关键字与def用法相同,定义一个类。Human是此类的类名,类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头。类的结构从大方向来说就分为两部分:静态变量。动态方法。

从类名的角度研究类

class Human:    
"""    类的具体结构    """   
# 第一部分:静态属性    
mind = '有思想' 
# 类的属性  (静态属性, 静态字段)  
language = '使用语言'   
# 第二部分: 动态方法   
def work(self):        
print('人类都会工作')  
def eat(self):    
print('人类都需要吃饭')
1. 类名操作类中的属性   
1. 类名查看类中所有的内容print(Human.__dict__) 
2. 类名操作类中的静态属性  万能的点.增:Human.body = '有头和四肢'删:del Human.mind改:Human.mind = 'liye脑残'查:print(Human.language)print(Human.__dict__)
2. 类名调用类中的方法(一般类中的(静态方法,类方法)方法不会通过类名调用)Human.work(111)总结:一般类名就是操作类中的属性.

从对象角度研究类

class Human:    
"""    类的具体结构    """  
# 第一部分:静态属性  
mind = '有思想'   
# 类的属性  (静态属性, 静态字段) 
language = '使用语言'   
def __init__(self):        
# print(f'self---->: {self}') 
# print(666)       
self.name = '李业'     
self.age = 18   
# 第二部分: 动态方法    
def work(self):      
print('人类都会工作') 
def eat(self):      
print('人类都需要吃饭')obj = Human() 
# 实例化过程得到一个返回值,这个返回值就是 对象,实例.print(f'obj---> {obj}')实例化一个对象发生了三件事:'''  
1. 开辟一个对象空间.   
2. 自动执行__init__方法,并且将对象地址传给self.   
3. 运行__init__方法内的代码,给对象空间封装属性.'''class Human:    """    类的具体结构    """   
# 第一部分:静态属性   
mind = '有思想'  
# 类的属性  (静态属性, 静态字段)   
language = '使用语言' 
def __init__(self, name, age):     
# print(f'self---->: {self}')     
# print(666)        self.n = name    
self.a = age   
# 第二部分: 动态方法  
def work(self):     
# print(f'self---> {self}') 
print(f'{self.n}都会工作')  
def eat(self):       
print(f'{self.n}都需要吃饭')
obj = Human('李业',18) 
# 实例化过程print(obj.n)print(obj.a)print(obj.__dict__)

对象操作对象空间的属性

1. 对象查看对象的空间的所有属性

obj = Human('李业',18)
print(obj.__dict__)

2. 对象操作对象空间的属性

obj = Human('李业',18)
增:obj.sex = 'laddy_boy'
删:del obj.a
改:obj.a = 1000
查:print(obj.n)print(obj.__dict__)

对象查看类中的属性

obj = Human('李业',18)
# print(obj.mind)
obj.mind = '无脑的'
print(obj.mind)
print(Human.mind)

对象调用类中的方法

obj = Human('孙戴维', 23)
# print(f'obj---> {obj}')
obj.work()obj.eat()

一个类可以实例化多个对象

obj1 = Human('李业',18)
obj2 = Human('小可爱', 16)
obj3 = Human('怼姐', 18)
变量,函数名:
age_of_oldboy = 73Ageofoldboy

1.类的空间问题

1.1何处可以添加对象属性

class A:   
def __init__(self,name):   
self.name = name  
def func(self,sex):       
self.sex = sex
# 类外面可以:
obj = A("barry")
obj.age = 18print(obj.__dict__)
# ("name": "barry", "age": 18)
# 类内部也可以
obj = A("barry")
obj.func("男")# __init__方法可以
# func 方法也可以

总结:

对象的属性不仅可以在__init__里面添加,还可以在类的其他方法或者类的外面添加

1.2何处可以添加类的静态属性

class A:    
def __init__(self,name):     
self.name = name  
def func(self,sex):   
self.sex = sex     
def func1(self):     
A.bbb = 'ccc'
# 类的外部可以添加A.aaa = 'taibai'print(A.__dict__)
# 类的内部也可以添加。A.func1(111)print(A.__dict__)

总结:

类的属性不仅可以在类内部添加, 还可以在类的外部添加

1.3对象如何找到类的属性

总结:

对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->.....

类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> ........

上面的顺序都是单向不可逆,类名不可能找到对象的属性。

2.类与类之间的关系

2.1依赖关系

将一个类的类名或者对象传入另一个类的方法中

class Elephant:   
	def __init__(self, name):    
		self.name = name   
	def open(self, obj): 
		print(f"{self.name}开门")   
		obj.be_open()   
	def close(self):
		print(f"{self.name}关门")
		
		
class Refrigerator: 
	def __init__(self, name): 
		self.name = name 
	def be_open(self):   
		print(f"{self.name}被打开")   
	def be_close(self):      
		print(f"{self.name}被关闭")
daxiang = Elephant("大象")
bingxiang = Refrigerator("冰箱")daxiang.open(bingxiang)

2.2组合关系

给一个类的对象封装一个属性,此属性为另一个类的对象

class Boy: 
	def __init__(self, name,girlfriend=None):   
		self.name = name  
		self.girlfriend = girlfriend  
	def have_a_diner(self):    
		if self.girlfriend:      
			print(f'{self.name}请他的女朋友{self.girlfriend}一起烛光晚餐')   
		else:          
			print('单身狗,吃什么吃')
			
liye = Boy('李业')
# 只是给李业封装了一个属性:
girlfriend 为一个字符串的数据
liye.girlfriend = '乔碧萝'
liye.have_a_diner()

class Boy: 
	def __init__(self, name,girlfriend=None): 
		self.name = name      
		self.girlfriend = girlfriend  
	def have_a_diner(self):      
		if self.girlfriend:        
			print(f'{self.name}请他的{self.girlfriend.age}岁的,{self.girlfriend.body}的女朋友{self.girlfriend.name}一起烛光晚餐')    
		else:         
			print('单身狗,吃什么吃')   
	def girl_skill(self):   
		print(f'{self.name}的女朋友的技能:')     
		self.girlfriend.skill()class Girl:  
	def __init__(self,name,age,body):      
		self.name = name   
		self.age = age     
		self.body=body  
	def skill(self):      
		print(f'{self.name} 会用萝莉音直播')
		
liye = Boy('李业')
qiao = Girl('乔碧萝', 58, '小钢炮')
# 给liye封装了另一个类中的对象
liye.girlfriend = qiao
liye.have_a_diner()
# liye.girl_skill()

组合与依赖的例子

class GameRole:   
	def __init__(self, name, ad, hp):     
		self.name = name   
		self.ad = ad 
		self.hp = hp  
	def attack(self, p1):    
		p1.hp = p1.hp - self.ad     
		print(f"{self.name}攻击{p1.name}, 谁掉了{self.ad}血, 还剩{p1.hp}血")   
		print(f"{p1.name}的血量{p1.hp}")   
	def equipment_wea(self, wea):     
		self.weapon = weaclass Weapon: 
		def __init__(self, name, ad):      
		self.name = name     
		self.ad = ad  
	def weapon_attack(self, p1, p2):  
		p2.hp = p2.hp - self.ad   
		print(f"{p1.name}利用{self.name}给了{p2.name}一下子,{p2.name}掉了{self.ad}血,还剩{p2.hp}血")gailun = GameRole("盖伦", 10, 100)
		
xin = GameRole("赵信", 20, 80)
sword = Weapon("大宝剑", 15)
musket = Weapon("长缨枪", 30)gailun.equipment_wea(sword)
gailun.weapon.weapon_attack(gailun, xin)

继承

1.继承初识

如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。

2.继承的优点

继承的优点也是显而易见的:

1,增加了类的耦合性(耦合性不宜多,宜精)。

2,减少了重复代码。

3,使得代码更加规范化,合理化。

3.单继承和多继承

单继承

1.类名执行父类属性方法
class Animal:   
	live = "有生命的"   
	def __init__(self, name, sex, age):  
		self.name = name    
		self.age = age     
		self.sex = sex   
	def eat(self):     
		print("会吃")class Human(Animal): 
body = "有头有脸"
print(Human.live)
Human.eat(123)
2.对象执行父类属性方法
class Animal:   
	live = "有生命的"    
	def __init__(self, name, sex, age):      
		self.name = name    
		self.age = age    
		self.sex = sex 
	def eat(self):  
		print("会吃")
		
class Human(Animal):
	live = "有思想的活着"  
	body = "有头有脸"
liye = Human("李业", "男", 18)
print(liye.live)
liye.eat()
3.在子类中既执行子类方法,又执行父类方法
不依赖继承的方法
class Animal: 
	def __init__(self, name, sex, age):    
		self.name = name     
		self.sex = sex    
		self.age = age   
	def eat(self):  
		print("动物都需要吃饭")
class Human:   
	def __init__(self, name, sex, age, hobby):    
		Animal.__init__(self, name, sex, age)    
		self.hobby = hobby 
    def eat(self):     
		print(f"{self.name}都需要吃饭")
obj = Human("李业", "男", 23, "旅游")print(obj.hobby)
依赖继承的方法
class Animal:   
	def __init__(self, name, sex, age):        
		self.name = name     
		self.sex = sex  
		self.age = age   
	def eat(self):   
		print("动物都需要吃饭")
class Human(Animal):   
	def __init__(self, name, sex, age, hobby):  
		super().__init__(name, sex, age)     
		self.hobby = hobby  
	def eat(self):    
		super().eat()      
		print(f"{self.name}都需要吃饭")
obj = Human("李业", "男", 23, "旅游")
print(obj.hobby)

多继承

在python2x版本中存在两种类.:   ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写,就什么都不继承   ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。 python3x版本中只有一种类: python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object

经典类

不继承object类, 深度优先原则

新式类

新式类:继承object类. mro(C3)算法

经典类的深度优先
class A:  
passclass B(A): 
passclass C(A):    
passclass D(B, C):   
passclass E:  
passclass F(D, E): 
passclass G(F, D): 
passclass H:    
passclass Foo(H, G):    pass

三大特性

封装

把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了⼀个很⽜B的函数. 那这个也可以被称为封装. 在⾯向对象思想中. 是把⼀些看似⽆关紧要的内容组合到⼀起统⼀进⾏存储和使⽤. 这就是封装.

继承

⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容. 说⽩了, ⼉⼦可以随便⽤爹的东⻄. 但是朋友们, ⼀定要认清楚⼀个事情. 必须先有爹, 后有⼉⼦. 顺序不能乱, 在python中实现继承非常简单. 在声明类的时候, 在类名后⾯添加⼀个⼩括号,就可以完成继承关系. 那么什么情况可以使⽤继承呢? 单纯的从代码层⾯上来看. 两个类具有相同的功能或者特征的时候. 可以采⽤继承的形式. 提取⼀个⽗类, 这个⽗类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的好处是我们可以避免写很多重复的功能和代码. 如果从语义中去分析的话. 会简单很多. 如果语境中出现了x是⼀种y. 这时, y是⼀种泛化的概念. x比y更加具体. 那这时x就是y的⼦类. 比如. 猫是⼀种动物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的"动"这个属性. 再比如, ⽩骨精是⼀个妖怪. 妖怪天⽣就有⼀个比较不好的功能叫"吃⼈", ⽩骨精⼀出⽣就知道如何"吃⼈". 此时 ⽩骨精继承妖精.

多态

同⼀个对象, 多种形态. 这个在python中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没有具体的说. 比如. 我们创建⼀个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = "alex", 这时, a⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量a可以是多种形态

类的约束

类的约束有两种:

第一种:抛出异常

提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.

class Payment:  
	def pay(self,money):    
	raise Exception("子类设置pay方法")
class QQpay(Payment):   
	def pay(self,money):      
		print(f"QQ支付{money}金额")
class Alipay(Payment):   
	def pay(self,money):      
		print(f"支付宝支付{money}金额")
class Wechatpay(Payment):   
	def zhifu(self,money):        
		print(f"微信支付{money}金额")
	def pay(obj,money):  
		obj.pay(money)
obj1 = QQpay()
pay(obj1,100)
obj2 = Alipay()
pay(obj2,200)
obj3 = Wechatpay()
pay(obj3,300)
"""QQ支付100金额

Traceback (most recent call last):支付宝支付200金额File "D:/pycharm demo/练习/代码练习.py", line 30, in <module>  pay(obj3,300)File "D:/pycharm demo/练习/代码练习.py", line 20, in pay  obj.pay(money)File "D:/pycharm demo/练习/代码练习.py", line 3, in pay  raise Exception("子类设置pay方法")Exception: 子类设置pay方法"""

第二种:使用元类

使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.

from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):  
	@abstractmethod    
	def pay(self,money):   
		passclass QQpay(Payment): 
	def pay(self,money):     
		print(f"QQ支付{money}金额")
class Alipay(Payment):   
	def pay(self,money):       
		print(f"支付宝支付{money}金额")
class Wechatpay(Payment): 
	def zhifu(self,money):       
		print(f"微信支付{money}金额")
	def pay(obj,money):  
		obj.pay(money)
		
obj1 = QQpay()
pay(obj1,100)
obj2 = Alipay()
pay(obj2,200)
obj3 = Wechatpay()
pay(obj3,300)

"""QQ支付100金额Traceback (most recent call last):支付宝支付200金额File "D:/pycharm demo/练习/代码练习.py", line 63, in <module>  obj3 = Wechatpay()TypeError: Can't instantiate abstract class Wechatpay with abstract methods pay"""

super的深度剖析

class A:    
	def f1(self):     
		print('in A f1')      
	def f2(self):      
		print('in A f2')
	class Foo(A):    
		def f1(self):      
		super().f2()       
		print('in A Foo')       
obj = Foo()obj.f1()
"""'in A f2''in A Foo'"""
super可以执行下一个类的其他方法
class A:    
	def f1(self):    
		print('in A')
class Foo(A):   
	def f1(self):      
		super().f1()     
		print('in Foo')
class Bar(A):   
	def f1(self):     
	print('in Bar')
class Info(Foo,Bar): 
	def f1(self):      
	super().f1()      
	print('in Info f1')
obj = Info()
obj.f1()
'''in Barin Fooin Info f1'''
print(Info.mro()) 
# [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]super()严格按照类的mro顺序执行class A:    def f1(self):        print('in A')class Foo(A):    def f1(self):        super().f1()        print('in Foo')class Bar(A):    def f1(self):        print('in Bar')class Info(Foo,Bar):    def f1(self):        super(Foo,self).f1()        print('in Info f1')obj = Info()obj.f1()"""in Barin Info f1"""

类的私有成员

私有类的属性

在类的内部可以访问

class A:  
	name = "李业"  
	__name = "钢哥"  
	def func(self):      
		print(self.name)      
		print(self.__name)
obj = A()obj.func()"""李业钢哥"""

在类的外部不能访问

class A:   
	name = "李业"
	__name = "钢哥"  
	def func(self):   
		passobj = A()
		print(obj.name)
		print(A.__name)
print(obj.__name)"""李业无法找到无法找到"""

在类的派生类不能访问

class A:  
	name = "李业"  
	__name = "钢哥"
class B(A):  
	def func(self): 
		print(self.__name)
		obj = B()
		print(obj.__name)
obj.func()

私有对象属性

只能在类的内部使用,不能在类外部以及派生类使用

class A:  
	def __init__(self, name, pwd):
		self.name = name     
		self.__pwd = pwd
	def md5(self):  
		self.__pwd = self.__pwd + "123"
obj = A("李业", "liyedsb")
print(obj.__pwd)"""无法找到"""

私有类的方法

class A:    
	def func(self):
    self.__func()     
	print("in A func") 
def __func(self):    
	print("in A __func")
	obj = A()
	obj.func()
"""in A __funcin A func"""obj.__func()"""无法找到"""

对于私有成员来说: 当你遇到重要的数据,功能,(只允许本类使用的一些方法,数据)设置成私有成员

特殊方法(默认不使用)

class A:  
	name = "李业"   
	__name = "钢哥"   
	def __func(self):       
		print("in __func")
		print(A.__dict__)
"""{'__module__': '__main__', 'name': '李业', '_A__name': '钢哥', '_A__func': <function A.__func at 0x000002F6FFB79A60>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}"""print(A._A__name)"""钢哥"""
# 类从加载时, 只要遇到类中的私有成员, 都会在私有成员前面加上 _类名 

类的其他方法

类方法

class A:   
	def func(self): 
		print("实例方法")  
	@classmethod  
	def cls_func(cls):    
		print(f"cls---->{cls}")     
obj = cls()     
print(obj)
print("类方法")
print(A)
A.cls_func()

"""<class '__main__.A'>cls----><class '__main__.A'><__main__.A object at 0x000001C3B5F874E0>类方法"""obj = A()obj.cls_func"""输出为空,因为cls_func是一个类方法,传入cls的是类的内存地址,所以对象无法调用"""
# 类方法,一般就是通过类名去调用的方法,并且自动将类名地址传给cls,但是如果通过对象调用也可以,但是传的还是类名地址A.cls_func()"""cls----><class '__main__.A'><__main__.A object at 0x00000234B9C17630>类方法"""   

类方法有什么用

1.得到类名可以实例化对象

2.可以操作类的属性

简单引用

创建学生类,只要实例化一个对象,写一个类方法,统计一下具体实例化多少个学生

class Student:  
	count = 0   
    def __init__(self,name,id):    
    	self.name = name        
    	self.id = id       
        Student.addnum()  
        @classmethod  
        def addnum(cls):   
        cls.count = cls.count + 1 
        @classmethod  
        def getnum(cls):   
        return cls.count
        
        
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        obj1 = Student('liye', 12343243243)
        print(Student.getnum())

静态方法

class A:   
	def func(self):     
    	print("实例方法") 
        @classmethod    
        def cls_func(cls): 
            pass    
            @staticmethod   
        def static_func():    
            print("静态方法")
            A.static_func()
            """静态方法"""
            # 静态方法是不依赖于对象与类的,其实静态方法就是函数,保证代码的规范性,合理的划分,后续维护性高,但是调用依然用类名调用
# 实例import timeclass 
TimeTest(object):  
	area = "中国"  
	def __init__(self, hour, minute, second):   
		self.hour = hour   
		self.minute = minute  
		self.second = second 
	def change_time(self): 
		print(f"你想调整的时间:{self.hour}时{self.minute}分{self.second}秒")  
	@staticmethod   
	def showTime():       
		return time.strftime("%H:%M:%S",time.localtime())
t = TimeTest(2, 10, 10)
t.change_time()
print(TimeTest.showTime())
# showTime函数,与类和对象没有任何关系,但是都是与时间有关,所以为了规范合理,放在一起,调用时用类名调用

属性

示例:

BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32  
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86

class Bmi:   
	def __init__(self, name, height, weight):    
		self.name = name       
		self.height = height 
		self.weight = weight 
	def bmi(self):       
		return self.weight/self.height**2
obj = Bmi("赵嘎",1.83, 65)
# 结果虽然实现了,但是逻辑上感觉不合理,bmi应该是类似于name,age,height,等名词,但是把它当做方法使用了

property

class Bmi:  
	def __init__(self, name, height, weight):   
		self.name = name  
		self.height = height      
		self.weight = weight   
	@property  
	def bmi(self):       
		return self.weight/self.height**2  
obj = Bmi("赵嘎", 1.83, 65)
print(obj.bmi)
property 将执行一个函数需要函数名()变换成直接函数名,将动态方法 伪装 成了一个属性,虽然在代码级别上没有什么提升,但是让你看起来更合理

组合

class Foo:  
	@property    
	def bmi(self):  
		print("get的时候运行我") 
	@bmi.setter    
	def bmi(self, value):    
		print(value)      
		print("set的时候运行我") 
	@bmi.deleter  
	def bmi(self):      
		print("delete的时候运行我")
obj = Foo()
obj.bmiobj.bmi = 666
del obj.bmi
"""get的时候运行我666set的时候运行我delete的时候运行我"""
# 应用场景:
# 1.面试会考一些基本的调用,流程
# 2.工作中如果遇到了一些类似于属性的方法名,可以让其伪装成属性

设置属性的两种方式

1.利用装饰器设置属性

class Foo:   
	@property    
		def bmi(self):    
	print('get的时候运行我啊') 
	@bmi.setter  
	def bmi(self,value):    
		print(value)    
		print('set的时候运行我啊')     
		# return 111  # 无法得到返回值 
	@bmi.deleter   
	def bmi(self):
		print('delete的时候运行我啊')  
		# return 111  # 无法得到返回值

2.利用实例化对象的方式设置属性

class Foo: 
	def get_AAA(self):   
		print('get的时候运行我啊')  
	def set_AAA(self,value):   
		print('set的时候运行我啊')  
	def delete_AAA(self):     
		print('delete的时候运行我啊') 
AAA = property(get_AAA,set_AAA,delete_AAA)  
#内置property三个参数与get,set,delete一一对应
f1=Foo()
f1.AAAf1.AAA='aaa'del 
f1.AAA

isinstance和issubclass

isinstance

判断的对象与类的关系
class A:   
	passclass B(A):   
	passobj = B()
	print(isinstance(obj,B))
	print(isinstance(obj,A))
"""TrueTrue"""
# isinstance(a,b)
# 判断的是 a 是否是 b类 或者 b类派生类实例化的对象

issubclass

 判断的是类与类的关系
class A:
    pass
class B(A):
    pass
class C(B):
    pass

print(issubclass(B,A))
print(issubclass(C,A))
"""
True
True
"""

# issubclass(a,b)
# 判断的是 a类 是否是 b类 或者 b类派生类的 派生类
# 判断的是 a类 是否是 b类的子孙类
posted @ 2021-02-24 21:50  丨渍丨  阅读(121)  评论(0)    收藏  举报