python学习之路-8 面向对象之进阶
上篇内容回顾和补充
- 面向对象三大特性
-
封装
-
继承
-
多态
- 在python中没有多态的概念
- 变量的类型允许为多种数据类型称之为多态
# c#/java中的多态 # 伪代码 def func(int arg): print(arg) func(123) # 这样调用是没问题的 func("aa") # 这样是会报错的,因为func接受的参数必须是int类型 那么如果func函数中的arg参数需要接受多种类型的参数,就需要按照下面的代码来搞: class A: pass class B(A): pass class C(A): pass 调用的时候: # arg参数,必须是A类型或A的子类类型 def func(A arg): print(arg) # 下面这三种方式都可以赋值给func函数 # obj = B() # obj = C() # obj = A() func(obj)
-
面向对象中的成员
字段
- 静态字段(类变量,多个对象共用一个字段,主要用于对象的变量内容都一样的时候)
- 普通字段(对象变量)
- 注意:静态字段在代码加载时就被创建了,而普通字段在类被实例化的时候才会被创建
class Foo:
CC = 123 # 这个被称为字段(静态字段,属于类)
def __init(self):
self.name = "aaa" #这个被称为字段(普通字段,属于对象)
- 静态字段和普通字段的使用
class Province:
def __init__(self, name):
self.name = name
self.country = "中国"
# 实例化类
hn = Province("河南")
hn = Province("河北")
hn = Province("山东")
# 比如我需要实例化1000个像上面的对象,
每个对象中都会存在一个self.country="中国"的变量,
这样就会造成内存的浪费,这个时候就需要用静态字段来搞,代码如下:
class Province:
country = "中国"
def __init__(self, name):
self.name = name
# 实例化类
hn = Province("河南")
hn = Province("河北")
hn = Province("山东")
# 这样所有的对象就会共用一个类变量country
- 普通字段和静态字段的访问规则
- 普通字段只能用对象访问
- 静态字段用类访问(万不得已的时候可以使用对象访问)
方法
- 普通方法,至少一个self,由对象执行
class Province:
country = "中国"
def __init__(self, name):
self.name = name
def show(self): # 普通方法,由对象去调用执行(方法属于类)
print(self.name)
# 调用普通方法
p = Province() # 实例化成一个对象
p.show() # 调用对象的show方法
- 静态方法,使用staticmethod装饰器将该方法变为静态方法,由类直接调用执行(也可以用对象执行,轻易不要用)
class Province:
country = "中国"
def __init__(self, name):
self.name = name
@staticmethod
def show(arg1, arg2): # 静态方法 == 函数,放在这个位置,表示这个静态方法是跟Province类有关的
print(arg1, arg2)
# 执行静态方法
Province.show(111, 222)
- 类方法,静态方法的特殊形式,使用classmethod装饰器将该方法变为类方法,由类直接调用执行(也可以用对象执行,轻易不要用)
class Province:
country = "中国"
def __init__(self, name):
self.name = name
@classmethod
def show(cls): # 类方法,由类调用,最少要有一个参数cls,调用的时候这个参数不用传值,自动将类名赋值给cls
print(cls)
# 调用方法
Province.show()
属性
- 将类中的方法变为一个属性,该属性的调用方法和字段是一样的
# 使用装饰器 property 将一个方法变为属性,在调用改属性的时候不需要加括号调用,代码如下:
class Pager:
"""
计算分页的功能
"""
def __init__(self, all_count):
self.all_count = all_count
@property
def all_pager(self):
"""
计算需要分几页,比如以每页10条为例子
:return:
"""
a1, a2 = divmod(self.all_count, 10)
if a2 == 0:
return a1
else:
return a1 + 1
p = Pager(101)
ret = p.all_pager
print(ret)
- 给属性添加赋值、删除功能(第一种方式)
class Pager:
"""
计算分页的功能
"""
def __init__(self, all_count):
self.all_count = all_count
@property # 将一个方法变为属性
def all_pager(self):
"""
计算需要分几页,比如以每页10条为例子
:return:
"""
a1, a2 = divmod(self.all_count, 10)
if a2 == 0:
return a1
else:
return a1 + 1
@all_pager.setter # 让all_pager属性具有赋值的方法,提供一个关联方式,具体的创建变量的代码还是需要自己去写的
def all_pager(self, value):
print(value)
@all_pager.deleter # 让all_pager属性具有删除的方法, 将del和这个方法进行关联,具体的删除方法还是需要自己去写的
def all_pager(self):
print(“del all_pager”)
p = Pager(101)
ret = p.all_pager
print(ret)
p.all_pager = "100" # 给属性设置参数,会调用被装饰器@all_pager.setter装饰的方法
del p.all_pager # 删除 会调用被装饰器all_pager.deleter 装饰的方法
- 给属性添加赋值、删除功能(第二种方式)
class Pager:
def __init__(self, all_count):
self.all_count = all_count
def f1(self):
return 123
def f2(self, value):
pass
def f3(self):
pass
foo = property(fget=f1, fset=f2, fdel=f3) # 将foo实例化成一个属性,对foo进行调用的时候执行方法f1,对foo方法进行赋值的时候执行方法f2,对foo进行删除的时候调用方法f3
p = Pager(100)
result = p.foo
print(result)
p.foo = "aaa"
del p.foo
成员修饰符
- 私有,任何私有的东西都不能够在本类外部进行调用
-
私有字段
- 私有普通字段 只能够在本类中调用,被继承的都不能够被调用
class Foo: def __init__(self, name): self.__name = name # 定义一个私有的普通字段 def f1(self): print(self.__name) class Bar(Foo): def f2(self): print(self.__name) # 调用不到私有普通字段 obj = Foo("aaa") print(obj.__name) # 报错,私有字段只能够在本类中的方法进行调用 obj.f1() # 这个就是正常的
- 私有静态字段 # 需要将一个方法变成静态方法,在静态方法中调用静态字段,然后在类外面通过调用类的静态方法,就可以访问类中的静态字段了
class Foo: __cc = "123" # 定义一个私有的静态字段 def __init__(self, name): self.__name = name @staticmethod def f1(): print(Foo.__cc) # print(Foo.__cc) # 这样调用会报错 Foo.f1() # 这样就可以了
-
私有方法
- 私有普通方法
class Foo: def __init__(self, name): self.name = name # 定义一个私有的普通字段 def __print(self): print(self.name) def f1(self): self.__print() obj = Foo("aaa") obj.f1() # 通过调用类中的公有方法来执行私有方法
- 私有静态方法
class Foo: def __init__(self, name): self.name = name # 定义一个私有的普通字段 @staticmethod def __f2(num): print(num) @staticmethod def f3(num): Foo.__f2(num) Foo.f3(10)
-
- 私有属性
- 使用对象访问私有的字段或方法可以通过obj._类名私有方法 调用类中私有的字段和方法
class Foo:
"""
这是一个测试类
"""
def __init__(self, name):
self.name = name
self.__age = 10
def __print(self):
print(self.name)
obj = Foo("xx")
print(obj._Foo__age)
obj._Foo__print()
特殊成员
__init__
构造方法,也叫作初始化方法__del__
析构函数 垃圾回收__doc__
注释 对类的一个说明文档
class Foo:
"""
这是一个测试类
"""
def __init__(self, name):
self.name = name
obj = Foo("xx")
print(obj.__doc__)
# 输出
这是一个测试类
__class__
返回该对象属于哪个类 使用方法:对象.class
class Foo:
def __init__(self, name):
self.name = name
obj = Foo("xx")
print(obj.__class__)
# 输出
<class '__main__.Foo'> # 表示本模块中的Foo类
__call__
执行对象() 会调用__call__方法
class Foo:
def __init__(self, name):
self.name = name
def __call__(self):
print("__call__", self.name)
obj = Foo("xx")
obj()
__str__
直接print对象的时候会调用__str__方法,并且会将__str__方法的返回值赋值给obj进行输出
class Foo:
"""
这是一个测试类
"""
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
obj = Foo("xx")
print(obj)
# 输出
xx
-
__add__
-
__dict__
class Foo:
"""
这是一个测试类
"""
def __init__(self, name, age):
self.name = name
self.__age = age
obj1 = Foo("aaa", 100)
obj2 = Foo("bbb", 101)
ret = obj1.__dict__
print(ret)
# 输出
{'_Foo__age': 100, 'name': 'aaa'}
-
__getitem__
对字典通过key取值和列表通过切片取值底层的实现- 字典通过key取值
class Foo: def __init__(self, name, age): self.name = name self.__age = age def __getitem__(self, item): print(item) obj1 = Foo("aaa", 100) obj1["xxx"] # 会调用对象obj1的__getitem__方法 中括号内的参数赋值给item obj1[1:2] # 输出 xxx slice(1, 2, None) # slice是一个类
- 列表通过切片取值
class Foo: def __init__(self, name, age): self.name = name self.__age = age def __getitem__(self, item): print(type(item)) print(item) print(item.start) print(item.stop) print(item.step) obj1 = Foo("aaa", 100) obj1[1:20:2] # 输出 <class 'slice'> slice(1, 20, 2) 1 20 2
-
__setitem__
对字典通过key设置值和列表通过切片设置值底层的实现- 字典通过key设置值
class Foo: def __init__(self, name, age): self.name = name self.__age = age def __getitem__(self, item): print(type(item)) print(item) print(item.start) print(item.stop) print(item.step) def __setitem__(self, key, value): print(key, value) def __delitem__(self, key): print("del", key) obj1 = Foo("aaa", 100) obj1["key"] = "value" # 输出 key value
- 列表通过切片设置值
class Foo: def __init__(self, name, age): self.name = name self.__age = age def __getitem__(self, item): print(type(item)) print(item) print(item.start) print(item.stop) print(item.step) def __setitem__(self, key, value): print(key, value) print(key.start) print(key.stop) print(key.step) def __delitem__(self, key): print("del", key) obj1 = Foo("aaa", 100) obj1[1:20] = [1, 2, 3] # 输出 slice(1, 20, None) [1, 2, 3] 1 20 None
-
__delitem__
删除字典指定的key和列表指定的切片范围底层的实现方法- 删除字典指定的key
class Foo: def __init__(self, name, age): self.name = name self.__age = age def __getitem__(self, item): print(type(item)) print(item) print(item.start) print(item.stop) print(item.step) def __setitem__(self, key, value): print(key, value) print(key.start) print(key.stop) print(key.step) def __delitem__(self, key): print("del", key) obj1 = Foo("aaa", 100) del obj1["aaa"] # 输出 del aaa
- 删除列表指定的切片范围
class Foo: def __init__(self, name, age): self.name = name self.__age = age def __getitem__(self, item): print(type(item)) print(item) print(item.start) print(item.stop) print(item.step) def __setitem__(self, key, value): print(key, value) print(key.start) print(key.stop) print(key.step) def __delitem__(self, key): print("del", key) print(key.start) print(key.stop) print(key.step) obj1 = Foo("aaa", 100) del obj1[1:20] # 输出 del slice(1, 20, None) 1 20 None
-
__iter__
含有该方法,对象就可以被迭代了,默认不可迭代
class Foo:
def __iter__(self):
yield 1
yield 2
obj = Foo()
for item in obj:
print(item)
面向对象其他
- isinstance 查看对象是否是类和该类父类的实例
class Foo:
pass
obj = Foo()
ret = isinstance(obj, Foo)
print(ret)
# 输出
True
- issubclass 查看前者是否是后者的子类
class Foo:
pass
class Bar(Foo):
pass
ret = issubclass(Bar, Foo)
print(ret)
# 输出
Trues
- 执行父类的方法,在父类方法的基础之上再添加自己的内容
class Foo:
def f1(self):
print("Foo.f1")
class Bar(Foo):
def f1(self):
# 主动执行父类的f1方法
super(Bar, self).f1()
print("哈哈哈")
obj = Bar()
obj.f1()
# 输出
Foo.f1
哈哈哈
-
应用
- 自定义类型,对字典进行补充 --> 有序字典
class MyDict(dict): def __init__(self): self.li = [] super(MyDict, self).__init__() # 执行父类的__init__方法 def __setitem__(self, key, value): self.li.append(key) super(MyDict, self).__setitem__(key, value) # 执行父类的__setitem__方法 def __str__(self): temp_list = [] for key in self.li: value = self.get(key) temp_list.append("'%s': %s" % (key, value,)) temp_str = "{" + ",".join(temp_list) + "}" return temp_str obj = MyDict() obj["k1"] = 123 # 调用obj的__setitem__方法 obj["k2"] = 456 print(obj) # 调用obj的__str__方法
异常处理
- try except
- else 如果无异常,则执行
- finally 不管是否有异常,都执行
- raise 主动触发异常
- assert 断言 条件成立不报错,反之报错
设计模式之单例模式
单例模式就是一个类只能创建一个实例化对象
class Foo:
instance = None
def __init__(self, name):
self.name = name
@classmethod
def get_instance(cls):
if cls.instance:
return cls.instance
else:
obj = cls("aaa")
cls.instance = obj
return obj
obj1 = Foo.get_instance()
print(obj1)
obj2 = Foo.get_instance()
print(obj2)
# 输出
<__main__.Foo object at 0x1007f9550>
<__main__.Foo object at 0x1007f9550>