一、Python一切皆对象
1、函数的返回值
在Python开发当中,编写一个函数即便不写return关键字,Python也会隐式添加上return None。通过print打印函数只会得到一个None的结果,在Python中函数和类也是可以赋值给一个变量的。函数可以接受的的返回值有:列表、元组、字符串、整数、字典、函数、类等。当然在Python最自由的还是可以返回一个函数或者类,通过打印得到输出的一个地址:<function outer at 0x000001F72BAD3CA0>。代表当前变量接收的一个函数地址。通过变量名加上('返回的函数有参数注意要添加参数')括号调用返回的函数,Python中类也是同理,得到对象<class 'main.Person'>。
def outer(name): | |
print(name) | |
return 1 | |
class Person: | |
def __init__(self,x,y) -> None: | |
self.x = x | |
self.y = y | |
def sum(self, data): | |
print(data) | |
print(self.x + self.y) | |
def decorator_func(): | |
print('start...') | |
return Person #返回的是一个类对象<class '____main____.Person'> | |
return outer #返回一个函数<function outer at 0x000001F72BAD3CA0> | |
return max #在python中也可以返回内置函数,<built-in function max> | |
my_object = decorator_func() | |
my_object(3, 4).sum('调用sum方法') #调用类实例 | |
my_object(name:'有参数必须加上参数,有约束加上约束的参数类型') #调用函数 | |
# print(decorator_func()) | |
print(my_func) | |
#输出结果: | |
""" | |
start... | |
调用sum方法 | |
7 | |
<class '__main__.Person'> | |
""" | |
2、函数的参数传递
在Python中函数可以作为另外一个函数的参数进行传参。同时这个也是装饰器所用到的必要操作之一,装饰器通过装饰函数可以对该装饰的函数添加新的方法。装饰器:通过一个装饰器类或者一个装饰器函数对被装饰的函数或者类进行装饰,为其添加新的方法。
def a(): | |
print('a函数的输出') | |
def b(func): | |
print('b函数的输出') | |
return func | |
c = b(a) #将a函数对象当成b的参数 | |
c() #调用a函数 | |
# 输出结果 | |
""" | |
>>>b函数的输出 | |
>>>a函数的输出 | |
""" |
3、dir内置函数
在Python开发中,不管是初学者还是精通Python开发的都不能保证能够记住其所有的方法,这个时候Python内置的dir()函数就非常有用了,使用 dir()函数可以查看对象内的所有的属性和方法。除了常用的方法之外,其他的你并不需要去记住他,交给dir()函数来帮你进行列举。如下:
dir([]) # 查看列表的所有方法 | |
# >>>['__add__', '__class__', '__contains__', '__delattr__', ········] | |
dir(max) # 查看max函数的所有方法 | |
# >>>['__call__', '__class__', '__delattr__', '__dir__', '__doc__',············] | |
# dir()里面的参数是你想要查看的Python对象,dir函数会帮你罗列该对象里面所有的方法,你并不需要完全记住这些方法名,通过dir函数可以帮你进行罗列。 |
4、type、object和class之间的关系
在Python当中所有的类、对象、类型都是type创建的,通过type(类名)可以查看到结果是type创建的,type()函数除了可以查看对象的数据类型,还可以查看是谁创建的。还可以通过____bases____方法查看自己是继承自谁,Python中所有的类和类型都继承自object类,object是Python中所有类和类型的基类。在Python2.0版本可以在类后面写上(objects)代表继承,不加上则代表为经典类,差别就是类里面的方法增加或减少。在Python3.0以后不写(object)解释器会隐式添加上。Ps:简单来说就是Python中所有的类、类型、对象都是type创建的(包括object类),而所有的类和类型都是继承自object类(包括type方法)。
class Person: # class只是声明了一个类,创建还是type创建的 | |
pass | |
type(Person) | |
Person.__class__ # 一样是查看当前对象时谁创建的 | |
# >>> type | |
type(int) # >>> type | |
type(str) # >>> type | |
type(list) # >>> type | |
type(type) # >>> type type也是其自身创建的 | |
Person.__bases__ # >>> (object,) | |
int.__bases__ # >>> (object,) | |
type.__bases__ # >>>(object,) 当然type本身也是继承自object类 | |
# 对象的三个特征:身份(内存id)、类型、值。 |
5、鸭子类型(多态)
鸭子类型:多个类实现了同一个方法(方法名称相同),只关注方法名不关注方法的具体实现方式,只看当前方法的名称是否相等被称为鸭子类型(可以不继承父类)。多态:在面向对象编程思想中分别有三个概念,封装、继承、多态。其中Python中多态指的是类继承父类使用同一种方法产生的结果不同,称之为多态。两个要点:(1)继承:多态必须发生在父类与子类之间。(2)重写:子类重写父类方法
# 在鸭子类型中,关注点在于对象的行为,即提供的方法,而不在于对象所属的类型。 | |
class Duck: | |
def walk(self): | |
print('I walk like a duck') | |
def swim(self): | |
print('i swim like a duck') | |
class Person: | |
def walk(self): | |
print('this one walk like a person') | |
def swim(self): | |
print('this man swim like a Person') |
6、Python抽象类
(1)抽象基类不能实例化(2)抽象基类必须重载内部方法。抽象基类主要场景是类型判断、限制用户继承抽象基类必须按照规则使用内置的接口(方法)。除非对Python面向对象开发非常熟悉,否则尽量不去使用,约束过多导致代码规则繁乱。一般使用多继承方法。
import abc | |
class CacheBase(metaclass=abc.ABCMeta): # 定义一个抽象基类 | |
@abc.abstractmethod # 限制使用者按照规则继承 | |
def get(self, key): | |
pass | |
@abc.abstractmethod | |
def set(self ,key, value): | |
pass | |
class RedisCache(CacheBase): | |
def get(self, key): | |
pass | |
def set(self, key, value): | |
pass | |
redis_cache = RedisCache() # 没定义get和set方法实例化将会报错 |
7、super函数调用顺序
在super函数一般用于类之间继承使用,一般是为了继承类的方法的同时同时使用父类的属性。super函数在多继承中并不是调用的父类,简单来收就是super()调用多个类之间的继承关系是采用的顺序为MRO顺序。
class A: | |
pass | |
class B(A): | |
pass | |
class C(A): | |
pass | |
class D(B , C): | |
# super().__init__() | |
pass | |
D.__mro__ # 调用mro方法查看super调用多继承之间的顺序 | |
# super().__init__()执行顺序如下 | |
# 实际开发中D调用了B类不管它构造函数里是否调用了自己的super父类(A),都是直接执行C不会执行A,顺序类似于广度优先算法。 | |
# >>>(__main__.D, __main__.B, __main__.C, __main__.A, object) | |
8、Mixin模式
Mixin类里面的功能一般比较单一,和普通的Python类不同Mixin只是定义了一些功能比较单一的方法用来被继承使用。在继承Mixin中不要去使用super这种用法。
9、property装饰器
@property装饰器主要是将类里面的方法进行修饰,将类里面的方法修饰成可以像属性一样被访问。
class DataSet(object): | |
@property | |
def method_with_property(self): ##含有@property | |
return 15 | |
def method_without_property(self): ##不含@property | |
return 15 | |
data_set = DataSet() | |
print(data_set.method_with_property) # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()。 | |
print(data_set.method_without_property()) # 没有加上@property装饰器修饰方法按照正常的访问方法 |