python基础篇_006_面向对象
面向对象
1.初识类:
# 定义一个函数,我们使用关键字 def """ def 函数名(参数): '''函数说明''' 函数体 return 返回值 """ def func(): print("func execute...")
# 定义一个类 使用关键字 class """ class 类名: '''类说明''' 类体 """ class C: pass
class Person: role = 'person' # 属性 def walk(self): print("person is walking ... ") # 动态属性
2.类属性引用和实例化
属性引用:类型.属性
class Person: role = 'person' def walk(self): print("person is walking...") print(Person.role) # 查看人的role属性 print(Person.walk) # 引用人的走路方法,注意,这里不是在调用,引用的是函数地址
实例化:类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
class Person: role = 'person' def __init__(self, name): self.name = name def walk(self): print("person is walking...") # 类实例化-->对象 对象 = 类名(参数) p1 = Person("zhangsan") # Person("zhangsan") 调用__init__(self, name)方法,构造方法 # 查看对象的属性 调用对象的方法 print(p1.role) p1.walk()
3.类命名空间与对象、实例的命名空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性 而类有两种属性:静态属性和动态属性 静态属性就是直接在类中定义的变量 类的数据属性是共享给所有对象的 动态属性就是定义在类中的方法 类的动态属性是绑定到所有对象的 创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性 在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
4.面向对象三大特性
继承:
新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
python中类的继承分为:单继承和多继承
class ParentClass1: # 定义父类 pass class ParentClass2: # 定义父类 pass class SubClass1(ParentClass1): # 单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1, ParentClass2): # python支持多继承,用逗号分隔开多个继承的类 pass
先抽象在继承:
增强代码重用性
子类可以自己实现新的属性和方法,或者重新定义父类的,不会影响父类。
在python3中,子类执行父类的方法也可以直接用super方法.
抽象类与接口类
继承有两种用途:
一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
接口定义:
from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): pass class Wechatpay(Payment): def pay(self, money): print("Wechatpay pay...") def fuqian(self, money): print('微信支付了%s元' % money) p = Wechatpay() p.pay(100)
依赖倒置原则:
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程
抽象类:
只能被继承,不能实例化
# 一切皆文件 import abc # 利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type = 'file' @abc.abstractmethod # 定义抽象方法,无需实现功能 def read(self): '子类必须定义读功能' pass @abc.abstractmethod # 定义抽象方法,无需实现功能 def write(self): '子类必须定义写功能' pass # class Txt(All_file): # pass # # t1=Txt() #报错,子类没有定义抽象方法 class Txt(All_file): # 子类继承抽象类,但是必须定义read和write方法 def read(self): print('文本数据的读取方法') def write(self): print('文本数据的读取方法') class Sata(All_file): # 子类继承抽象类,但是必须定义read和write方法 def read(self): print('硬盘数据的读取方法') def write(self): print('硬盘数据的读取方法') class Process(All_file): # 子类继承抽象类,但是必须定义read和write方法 def read(self): print('进程数据的读取方法') def write(self): print('进程数据的读取方法') wenbenwenjian = Txt() yingpanwenjian = Sata() jinchengwenjian = Process() # 这样大家都是被归一化了,也就是一切皆文件的思想 wenbenwenjian.read() yingpanwenjian.write() jinchengwenjian.read() print(wenbenwenjian.all_type) print(yingpanwenjian.all_type) print(jinchengwenjian.all_type)
抽象类与接口类:
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
多继承接口,接口定义一种规范
多态:多态指的是一类事物有多种形态
import abc class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod def talk(self): pass class Person(Animal): def talk(self): print("person .. ") class Dog(Animal): def talk(self): print("Dog .. ") def talk(obj): obj.talk() talk(Person())
封装:
隐藏对象的属性和实现细节,仅对外提供公共访问方式
【封装原则】 1. 将不需要对外提供的内容都隐藏起来; 2. 把属性都隐藏,提供公共方法对其访问。
私有变量和私有方法:使用双下划线
# 其实这仅仅这是一种变形操作 # 类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式: class A: __N = 0 # 类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N def __init__(self): self.__X = 10 # 变形为self._A__X def __foo(self): # 变形为_A__foo print('from A') def bar(self): self.__foo() # 只有在类内部才可以通过__foo的形式访问到. # A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
这种自动变形的特点: 1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。 2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。 3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
class A: __N = 0 # 类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N def __init__(self): self.__X = 10 # 变形为self._A__X def __foo(self): # 变形为_A__foo print('from A') def bar(self): self.__foo() # 只有在类内部才可以通过__foo的形式访问到. # A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形 a = A() # a.bar() print(a._A__N) # 知道类名,属性名 就可以访问 print(a._A__foo())
私有方法:在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
5.property属性:
一个静态属性property本质就是实现了get,set,delete三种方法
class Goods: def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() obj.price # 获取商品价格 obj.price = 200 # 修改商品原价 print(obj.price) del obj.price # 删除商品原价
classmethod:
class Classmethod_Demo(): role = 'dog' @classmethod def func(cls): print(cls.role) Classmethod_Demo.func()
staticmethod:
class Staticmethod_Demo(): role = 'dog' @staticmethod def func(): print("当普通方法用") Staticmethod_Demo.func()
6.isinstance和issubclass
class A(object): pass a = A() # isinstance(obj,cls)检查是否obj是否是类 cls 的对象 print(isinstance(a, object)) # issubclass(sub, super)检查sub类是否是 super 类的派生类 print(issubclass(A, (object)))
7.反射
通过字符串的形式操作对象相关的属性 -- 自省
hasattr 是否有该属性
getattr 获取属性
setattr 设置属性
delattr 删除属性
class Person(): role = 'person' def __init__(self, name): self.name = name def walk(self): print("person is walking ...") p = Person("zhangsan") print(hasattr(p, 'name')) print(getattr(p, 'role')) print(setattr(p, 'name', 'lisi')) print(getattr(p, 'name')) print(delattr(p, 'role')) print(getattr(p, 'role')) # AttributeError
__str__和__repr__
format_dict={ 'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型 'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址 'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名 } class School: def __init__(self,name,addr,type): self.name=name self.addr=addr self.type=type def __repr__(self): return 'School(%s,%s)' %(self.name,self.addr) def __str__(self): return '(%s,%s)' %(self.name,self.addr) def __format__(self, format_spec): # if format_spec if not format_spec or format_spec not in format_dict: format_spec='nat' fmt=format_dict[format_spec] return fmt.format(obj=self) s1=School('oldboy1','北京','私立') print('from repr: ',repr(s1)) print('from str: ',str(s1)) print(s1) ''' str函数或者print函数--->obj.__str__() repr或者交互式解释器--->obj.__repr__() 如果__str__没有被定义,那么就会使用__repr__来代替输出 注意:这俩方法的返回值必须是字符串,否则抛出异常 ''' print(format(s1,'nat')) print(format(s1,'tna')) print(format(s1,'tan')) print(format(s1,'asfdasdffd'))