面向对象是一种编程的思想,是一种解决问题的思路。
在编程当中,有面向过程的编程思想和面向对象的编程思想。
面向过程:
# 龟兔赛跑
import time
DISTENCE = 500
name_t = "turtle"
speed_t = 100
t1 = DISTENCE / speed_t
name_r = "rabbit"
speed_r = 10000
t2 = DISTENCE / speed_r
面向对象:
定义:类是对象的模板,对象是类的实例,类是创建对象用的,对象是实际实现功能的。
class MammalAnimal:
name = "Turtle"
speed = 100
def run(self):
print("i can run")
def jump(self):
print("i can jump")
类的命名空间
class MammalAnimal:
name = "Turtle"
speed = 100
def run(self):
print("i can run")
def jump(self):
print("i can jump")
print(MammalAnimal.__dict__)
{‘module’: ‘main’, ‘name’: ‘Turtle’, ‘speed’: 100, ‘run’:
, ‘jump’: , ‘dict’: dict’ of ‘MammalAnimal’ objects>, ‘weakref’: weakref’ of ‘MammalAnimal’ objects>, ‘doc’: None}
类的属性访问方式
class MammalAnimal:
name = "Turtle"
speed = 100
def run(self):
print("i can run")
def jump(self):
print("i can jump")
print(MammalAnimal.__dict__["name"])
print(MammalAnimal.name)
Turtle
Turtle
class MammalAnimal:
name = "Turtle"
speed = 100
def run(self):
print("i can run")
def jump(self):
print("i can jump")
cat = MammalAnimal()
print(cat.dict) # 打印对象,显示结果第一行
cat.__dict__["name"] = "cat"
cat.__dict__["speed"] = 10
print(cat.__dict__) # 打印对象的命名空间,显示结果第二行
{}
{‘name’: ‘cat’, ‘speed’: 10}
对象产生的过程
cat = MammalAnimal()
在对象的命名空间中添加数据
cat.__dict__["name"] = "cat"
cat.__dict__["speed"] = 10
__init__
方法class MammalAnimal:
def __init__(self):
self.name = "Turtle"
self.speed = 100
def run(self):
print("i can run")
def jump(self):
print("i can jump")
obj = MammalAnimal() # 此处已经将obj当成参数传入到MammalAnimal()中,如果再写一个字符串进去,会显示已经传递了两个位置参数
print(obj.__dict__)
{‘name’: ‘Turtle’, ‘speed’: 100}
class MammalAnimal:
def __init__(self, *args): # 采用可变长位置参数传递对象的属性
self.name = args[0]
self.speed = args[1]
def run(self):
print("i can run")
def jump(self):
print("i can jump")
obj = MammalAnimal("cat", 5)
print(obj.__dict__)
dog = MammalAnimal("dog", 9)
print(dog.__dict__)
{‘name’: ‘cat’, ‘speed’: 18}
{‘name’: ‘dog’, ‘speed’: 9}
将实例化好的对象返回出来
class MammalAnimal:
fly = "" # 类属性
def __init__(self, *args):
self.name = args[0] # 实例属性
self.speed = args[1]
def fly_cap(self):
MammalAnimal.fly = "yes"
def run(self):
print("i can run")
def jump(self):
print("i can jump")
cat = MammalAnimal("cat", 5)
dog = MammalAnimal("dog", 9)
print(cat.__dict__)
cat.fly_cap() # 通过对象调用方法
print(cat.fly)
print(cat.__dict__)
MammalAnimal.run(cat) # 通过类执行cat对象的run方法
{‘name’: ‘cat’, ‘speed’: 5}
yes
{‘name’: ‘cat’, ‘speed’: 5}i can run
self.
则为实例方法self.
是类方法通过对象封装数据
switch_info = {"CE1": {"ip": "192.168.1.1", "username": "admin", "password": "Huawei@121"},
"CE2": {"ip": "192.168.1.2", "username": "admin", "password": "Huawei@122"},
"CE3": {"ip": "192.168.1.3", "username": "admin", "password": "Huawei@123"},
"CE4": {"ip": "192.168.1.4", "username": "admin", "password": "Huawei@124"}, }
print(switch_info["CE2"]["ip"])
192.168.1.2
class SwitchInfo:
def __init__(self, ip, username, password):
self.ip = ip
self.username = username
self.password = password
CE1 = SwitchInfo("192.168.100.1","python","Huawei@123")
CE2 = SwitchInfo("192.168.100.2","python","Huawei@123")
CE3 = SwitchInfo("192.168.100.3","python","Huawei@123")
CE4 = SwitchInfo("192.168.100.4","python","Huawei@123")
print(CE2.ip) # 通过对象调用
192.168.100.2
在实例化时可以完成必要操作:
import os
class Files:
def __init__(self, path):
self.path = path
if not os.path.exists(self.path):
os.makedirs(self.path)
def open_file(self):
pass
L1 = list([1, 2, 3, 4, 5]) # list是类;l1是对象;[1,2,3,4,5]是初始化的参数
L1.append(3) # 将自己作为第一参数加入方法append计算
print(L1)
list.append(L1, 5) # 直接通过类调用两个参数L1列表,添加值5
print(L1)
[1, 2, 3, 4, 5, 3]
[1, 2, 3, 4, 5, 3, 5]
__init__
完成初始化,并将初始化好的数据存放在对象的内存空间中,方便之后进行调用。class Animal:
def __init__(self,name,age):
self.name = name
self.age = age
def run(self):
print("我会跑")
def jump(self):
print("我会跳")
def swimming(self):
print("我会游泳")
class Humanbeing(Animal):
def swimming(self): # 父类中存在该方法,此时重写该方法,叫做方法的重写
print("我不会游泳")
obj = Humanbeing("张三",18)
print(obj.name)
print(obj.age)
obj.run()
obj.swimming()
方法在父类和子类中都存在,会优先调用子类当中的方法,如果说我们想要调用父类当中的方法,需要执行以下操作:
class Humanbeing(Animal):
def swimming(self):
Animal.swimming(self) # 指明父类中的方法
class Humanbeing(Animal):
def swimming(self):
super(Humanbeing, self).swimming()使用super函数调用父类中的函数swimming()
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print("我会跑")
def jump(self):
print("我会跳")
def swimming(self):
print("我会游泳")
class Intelligence(Animal): #
def study(self):
print("我能学习")
def control(self):
print("我能控制自己")
class Humanbeing(Intelligence):
def swimming(self):
super(Humanbeing, self).swimming()
obj = Humanbeing("张三", 18)
print(obj.name)
print(obj.age)
obj.run()
obj.swimming()
obj.study()
张三
18
我会跑
我会游泳
我能学习
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print("我会跑")
def jump(self):
print("我会跳")
def swimming(self):
print("我会游泳")
def control(self):
print("我不能控制自己")
class Intelligence():
def study(self):
print("我能学习")
def control(self):
print("我能控制自己")
class Humanbeing(Animal, Intelligence): # 如果两个父类中都存在相同的方法,则采用最左侧的Animal的方法作为方法使用
def swimming(self):
super(Humanbeing, self).swimming()
obj = Humanbeing("张三", 18)
print(obj.name)
print(obj.age)
obj.run()
obj.swimming()
obj.study()
obj.control() # 该方法在两个父类中都存在,选择最左侧的类中方法执行
张三
18
我会跑
我会游泳
我能学习
我不能控制自己
class A:
def f1(self):
print("A")
def f2(self):
print("AA")
def f3(self):
print("AAA")
class B(A):
def f1(self):
print("B")
def f2(self):
print("BB")
class C(A):
def f1(self):
print("C")
def f3(self): print("CC")
class D(B, C): # 先继承B再继承C方法
def f1(self):
print("D")
obj = D()
obj.f1()
obj.f2()
obj.f3()
D
BB
CC
类.mro
可以得到一个mro列表,里面存放的时继承的关系。class A:
def f1(self):
print("A")
def f2(self):
print("AA")
def f3(self):
print("AAA")
class B(A):
def f1(self):
print("B")
def f2(self):
print("BB")
class C(A):
def f1(self):
print("C")
def f3(self): print("CC")
class D(B, C): # 先继承B再继承C方法
def f1(self):
print("D")
print(D.mro()) # 查看该类的继承顺序
[
main.D’>, main.B’>, main.C’>, main.A’>, ]
Mixint是一种规范,一个类继承了多个类,那么通过Minxint机制能够区分出哪个是主类,那个是附加性的。
class Animal:
pass
class EggMinIn:
speak = "我有翅膀"
def egg_func(self):
print("我会下蛋")
class Duck(EggMinIn, Animal):
pass
class Chicken(EggMinIn, Animal):
def Egg(self):
print("我会下蛋")
speak = "我有翅膀"
pass
class Cat(Animal):
pass
多态其实指的就是一种食物的多种形态;水: 气体:水蒸气;液体:水;固体:冰
class Animal:
def speak(self):
print("我是动物,我会叫")
class Humanbeing(Animal):
def speak(self):
super().speak()
print("我是人,我的叫声是啊啊啊")
class Dog(Animal):
def speak(self):
super().speak()
print("我是狗,我的叫声是汪汪汪")
class Duck(Animal):
def speak(self):
super().speak()
print("我是鸭子,我的叫声是嘎嘎嘎")
obj = Dog()
obj.speak()
定义了一个叫做Animal的类,Humanbeing,Dog,duck类,人、狗、鸭子继承了动物类,那么此时动物类里面定义了一个speak方法,就意味着他的所有子类都拥有了speak这个方法。
这么讲的含义是什么呢,就是说假设我们有一个类,他存在某些特征,那么之后我们在遇到一些类,只要他属于挪个类,那么他就不需要思考,就能直接使用这些特征。
此时的Animal,起到的作用,就是即便下面的子类当中没有定义这个方法,但是由于他们属于Animal这个类,因此也可以直接调用Speak方法。
但是在python当中,其实并不推崇这个约束方式,而是按照规范来创建类,假如定义一个类需要具备某些特征,那么我们就应该自主的吧这个特征加到定义的类里面。比如在这个例子当中,不是应为继承了Animal才有speak这个方法,而是以为属于Animal的子类,而Animal拥有speak的方法,所以也要在自己的类中定义speak方法。
鸭子类型:
拓展:
import abc
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def speak(self):
print("I am an Animal")
class HumanBeing(Animal):
def speak(self):
pass
class Dog(Animal):
def speak(self):
pass
class Duck(Animal):
def speak(self):
pass
obj = HumanBeing()
obj1 = Dog()
class Foo:
def __init__(self, name, age):
self.__name = name # 变量名前加上__,则该变量为隐藏属性,无法被对象调用。
self.age = age
obj = Foo('张三', 21)
print(obj._Foo__name) # 隐藏后的属性如果一定要调用,采用该方式调用
通过对象.属性
的方式来获取属性值,而如果定义类的时候属性名之前加上__
,那么此时该属性成为隐藏属性,通过之前的方式调用则会失败,必须通过对象._类名__属性名
的方式可以调用,但是不建议该隐藏后又再次被调用。
类.__属性名
class Foo:
def __init__(self, name, age):
self.__name = name # 变量名前加上__,则该变量为隐藏属性,无法被对象调用。
self.age = age
def get_name(self):
# print("看什么看,不准查看")
# return
print(self.__name)
def set_name(self, val):
if val == str(val):
self.__name = val
print(self.__name)
else:
print("更改的类型必须是字符串")
def del_name(self):
del self.__name
obj = Foo("张三", 18)
obj.set_name(123)
更改的类型必须是字符串
import config # 引入另一个文件中的代码,代码如下:
# Switch_info = {"CE1": {"IP": "192.168.1.1", "username": "admin", "password": "Huawei@123"},
# "CE2": {"IP": "192.168.1.2", "username": "admin", "password": "Huawei@123"},
# "CE3": {"IP": "192.168.1.3", "username": "admin", "password": "Huawei@123"},
# "CE4": {"IP": "192.168.1.4", "username": "admin", "password": "Huawei@123"}, }
class SwitchMonitor:
def __init__(self, ip, username, password):
self.ip = ip
self.username = username
self.password = password
print(self.ip, self.username, self.password)
@classmethod # 加了该命令后,不在将对象当成第一个参数传函数中,而是将类当成第一个参数传递进来
def config_info(cls, arg): # cls相当于类名,是一个类
return cls(SwitchMonitor(config.Switch_info[arg]["IP"], config.Switch_info[arg]["username"],
config.Switch_info[arg]["password"]))
obj = SwitchMonitor.config_info("CE1")
192.168.1.1 admin Huawei@123
class Foo:
def __init__(self, x):
self.x = x
def f1(self):
print(self.x ** 2)
def f2(self):
print(self.x ** 3)
obj = Foo(10)
obj.f1()
obj.f2()
class Foo:
def __init__(self, x):
self.x = x
def f1(self):
print(self.x ** 2)
@property # 装饰器实现的功能,即可以通过调用属性的方式调用方法。
def f2(self):
print(self.x ** 3)
obj = Foo(10)
obj.f2 # 调用属性的方法,如果是调用方法则obj.f2()
class Foo:
def __init__(self, x):
self.__x = x
def get_x(self):
print(self.__x)
def set_x(self,val):
self.__x = val
def del_x(self):
del self.__x
obj = Foo(10)
obj.get_x()
obj.set_x(22)
obj.get_x()
装饰器配合property
class Foo:
def __init__(self, x):
self.__x = x
@property
def x(self):
print(self.__x)
@x.setter
def x(self, val):
self.__x = val
print(self.__x)
@x.deleter
def x(self):
del self.__x
obj = Foo(10)
obj.x = 20 # 像对对象属性一样的进行赋值,格式为x = val,则会自动匹配x.setter这个装饰器进行执行
del obj.x # 删除参数只要前面加了del,则匹配x.deleter删除参数
obj.x # 参数已经被删除,执行该语句报错
动态语言
反射的定义:
作用:
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
pass
obj = Foo("张三", 21)
print(obj.__dict__) # 查询对象的属性,返回字典
print(dir(obj)) # 查询对象的属性和方法
print(obj.name) # 执行该属性,如果该属性不存在则会报错。
对象.属性
的形式,或者对象.方法
的形式来进行调用,也可以通过反射功能,采用字符串
的类型事项相应多功能反射的方法:
lass Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
pass
obj = Foo("张三", 21)
res = hasattr(obj, "name") # obj是对象,"name"属性对应的字符串,判断,返回结果是True或者False
print(res)
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
pass
obj = Foo("张三", 21)
res = getattr(obj, "name",None) # obj是对象,"name"属性对应的字符串,存在则返回name值,不存在则返回None
print(res)
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
pass
obj = Foo("张三", 21)
setattr(obj, "name", "李四")
print(getattr(obj, "name"))
李四
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
pass
obj = Foo("张三", 21)
delattr(obj, "name")
res = getattr(obj, "name", "None")
print(res)
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print("123")
def choose_function(self):
option = input("please input a function's name:") # 输入run,结果返回到res,res()就是run()。
if hasattr(self, option):
res = getattr(obj, option)
res()
else:
print("Invalid function")
obj = Foo("张三", 21)
obj.choose_function()
from importlib import import_module
r = import_module('random')
res = r.randint(1, 10)
print(res)
from importlib import import_module
r = import_module('telnetlib')
r1 = import_module('telnetlib.Telnet') # 错误方式
__init__
__init__
的方法__dict__
__dict__
的方法。__str__
print(对象)
的时候会自动触发__str__
,必须为该方法顶一个字符串的返回值,否则会报错。class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
pass
def jump(self):
pass
def __str__(self):
return "这是一个动物的对象" # 该函数调用一个字符串,否则会报错,在打印对象的时候会调用
obj = Animal('Bob', 18)
print(obj)
__del__
当执行删除对象的操作时,会自动的触发__del__
执行
默认在程序执行完成之后,会回收程序代码资源,等于说这个时候会将对象回收,也就意味着触发了方法__del__
的执行。
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
pass
def jump(self):
pass
def __str__(self):
return "这是一个动物的对象" # 该函数调用一个字符串,否则会报错,在打印对象的时候会调用
def __del__(self):
print("程序终止了")
obj = Animal('Bob', 18)
__del__
的方法下关闭一个文件,防止文件一直占用系统资源。class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
self.f = open("config.py", "r") # 打开文件
print("文件打开完毕")
def run(self):
pass
def jump(self):
pass
def __str__(self):
return
def __del__(self):
self.f.close()
print("文件关闭了") # 关闭文件
obj = Animal('Bob', 18)
__new__
创建对象的时候会用到的魔法方法
创建对象的过程:
__new__
方法创建出来的。__init__
方法初始化对象,需要注意,一定要有一个空对象才会触发__init__
obj = Animal('Bob', 18) # 值传递给__init__方法
创造空对象是自动触发__new__
方法,并且返回好一个创建好的空对象
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
print("haha")
def run(self):
pass
def jump(self):
pass
def __str__(self):
return "这是一个动物的对象" # 该函数调用一个字符串,否则会报错,在打印对象的时候会调用
def __new__(cls, *args, **kwargs):
return super().__new__(cls)
obj = Animal('Bob', 18) # 实例化对象
print(obj) # 显示结果为空
print(dir(Animal))
__call__
__call__
方法的执行,并且可以将__call__
return的结果当成返回值。__call__
方法,也就说明了,我们在做对象实例的时候,默认触发的就是Animal父类中的__call__
方法。__init__
方法初始化对象。class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
print("haha")
def run(self):
pass
def jump(self):
pass
def __str__(self):
return "这是一个动物的对象" # 该函数调用一个字符串,否则会报错,在打印对象的时候会调用
def __new__(cls, *args, **kwargs):
return super().__new__(cls)
def __call__(self, *args, **kwargs):
return 123
obj = Animal('Bob', 18)
res = obj()
print(res)
__getitem__
、__setitem__
、__delitem__
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
print("看到我这句,表示打印了__init__中的属性")
def run(self):
pass
def jump(self):
pass
def __str__(self):
return "这是一个动物的对象" # 该函数调用一个字符串,否则会报错,在打印对象的时候会调用
def __new__(cls, *args, **kwargs):
return super().__new__(cls)
def __call__(self, *args, **kwargs):
return 123
def __getitem__(self, item):
print(item)
pass
def __setitem__(self, key, value):
print(key)
print(value)
def __delitem__(self, key):
print(key)
pass
obj = Animal('Bob', 18) # Animal()触发的应该是Animal类中的call方法。
obj["gender"] = "male" # 该语句自动执行setitem的方法
obj["name"] # 自动触发geitem方法的执行
del obj["age"] # 自动触发delitem执行
__add__
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
pass
def jump(self):
pass
def __str__(self):
return "这是一个动物的对象" # 该函数返回一个字符串,否则会报错,在打印对象的时候会调用
def __new__(cls, *args, **kwargs):
return super().__new__(cls)
def __call__(self, *args, **kwargs):
return 123
def __add__(self, other):
print(other)
obj1 = Animal('Bob', 18) # Animal()触发的应该是Animal类中的call方法。
obj2 = Animal('Alice', 19)
obj3 = obj1 + 3 # 触发__add__方法
print(obj3)
__enter__
、__exit__
打开文件时采用的方法(回顾):
f = open("config.py", "r") # 打开后,需要手工关闭。
print(f.read())
f.close()
with open("config.py", "r") as f: # 打开后当退出with语句块的时候,关闭文件。
print(f.read())
__enter__
、__exit__
方法
__enter__
方法,然后获得一个返回值,赋值给f,接着执行with 对象as下对应的代码块,执行完毕之后触发__exit__
方法。class Foo:
def __init__(self, name):
self.name = name
def __enter__(self):
return 5
pass
def __exit__(self, exc_type, exc_val, exc_tb):
print("-------")
obj = Foo("张三")
with obj as f:
print(f)
print(123)
__inter__
、__next__
__iter__
和__next__
方法__iter__
方法返回自身(对象)__next__
提取,如果没有数据可以提取,那么抛出一个StopIteration的错误class Foo:
def __init__(self):
self.counter = 0
def __iter__(self):
return self
def __next__(self):
self.counter += 1
if self.counter == 5:
raise StopIteration
else:
return self.counter
obj = Foo()
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj))
class Foo:
def __init__(self, num):
self.counter = -1
self.num = num
def __iter__(self):
return self
def __next__(self):
self.counter += 1
if self.counter == self.num:
raise StopIteration
else:
return self.counter
obj = Foo(5)
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj))
__iter__
方法__iter__
方法返回一个迭代器对象class Foo:
def __init__(self, num):
self.counter = -1
self.num = num
def __iter__(self):
return self
def __next__(self):
self.counter += 1
if self.counter == self.num:
raise StopIteration
else:
return self.counter
class Xoo:
def __iter__(self):
return Foo(100)
obj = Xoo()
for i in obj:
print(i)
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print("我会跑")
def jump(self):
print("我会跳")
obj = Animal("cat", 8)
print(type(obj)) # 显示结果obj类的父类是Animal
print(type(Animal)) # 显示结果Animal的父类是type,时一个元类。
main.Animal’>
cls_name = "Animal"
cls_base = (object,)
cls_content = """
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print("我会跑")
def jump(self):
print("我会跳")
"""
cls_namespace = {}
exec(cls_content, {}, cls_namespace)
Animal = type(cls_name, cls_base, cls_namespace) # 通过元类创造对象Animal,第一个参数是字符串,第二个参数是元组类型,第三个参数是字典类型
obj = Animal("张三", 18)
print(obj.__dict__)
class MyMeta(type):
def __init__(self, a1, a2, a3): # a1代表类名,a2代表继承的父类,a3代表命名空间。
if a1.isupper():
self.a1 = a1
else:
print("类名必须全大写")
class Animal(object, metaclass=MyMeta): # 将该类的父类设置为MyMeta类
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print("我会跑")
def jump(self):
print("我会跳")
obj = Animal("cat", 8)
print(obj)
__new__
和__call__
class MyMeta(type):
def __call__(self, *args, **kwargs):
print(args, kwargs)
obj = self.__new__(self) # 创建空对象,对于MyMeta而言,self是Animal,调用Animal中的__new__方法,如果Animal中不存在__new__方法,则查找父类中的__new__方法。
self.__init__(obj, *args, **kwargs) # 初始化参数
return obj # 返回初始化好的对象
class Animal(object, metaclass=MyMeta): # 将该类的父类设置为MyMeta类
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print("我会跑")
def jump(self):
print("我会跳")
def __new__(cls, *args, **kwargs): # 因此Animal中该方法也可以删除,删除后,将调用父类中的__new__函数,父类中没有,将调用到元类。
return super().__new__(cls)
obj = Animal("cat", 8) # 相当于执行父类中的__call__类型,进而调用
print(obj)