Day -8
Author: Denny YU
Created: January 15, 2022 9:09 PM
文章目录
类与对象进阶
属性和方法
1. 类的私有属性和私有方法实现封装
- 通畅约定两个下划线开头的属性是private,其他为公共的public
- 类内部可以访问私有属性(方法)
- 类外部不能直接访问私有属性(方法)ps:但是可以以某种方式访问
- 类外部可以通过“_类名__私有属性名”访问私有属性
class Employee:
def __init__(self,name,age):
self.name=name
self.__age=age ##私有属性
def work(self):
print("I like work")
def __work(self):
print("after {1} was {0} heavy work".format(self.name,self.__age)) ##私有方法
e=Employee("jing", 18)
print(e.name)
#print(e.age) #会输出错误AttributeError: 'Employee' object has no attribute 'age'
print(e._Employee__age) #输出18
e._Employee__work() #输出“heavy work”
e.work()
2. 方法没有重载
在其他语言,可以定义多个重名的方法,只要保证方法签名唯一即可。 方法签名包含三个部分:方法名、参数数量、参数类型
Python总共方法的参数没有类型,参数的数量也是可变的。因此python中没有方法重载,定义多个同名函数之后最后定义的那个会生效
3. 方法的动态性
动态地修改方法
class Person:
def work(self):
print("hard working")
def play_game(s):
print("{0} is playing games".format(s))
Person.paly=play_game
P=Person()
print("id of P is {0}; id of Person class is {1}".format(id(P),id(Person)))
P.work()
P.paly()
############################output
id of P is 1987890177984; id of Person class is 1987882918672
hard working
<__main__.Person object at 0x000001CED77CE7C0> is playing games
4. 装饰器@property
@property可以将一个方法的调用方式编程属性调用
get,set访问用以访问和设置私有属性
class Employee:
def __init__(self,name,salary):
self.name = name
self.__salary = salary
def get_salary(self):
return self.__salary
def set_salary(self,a):
if 1000<a<10000:
self.__salary=a
return self.__salary
else:
raise ValueError
emp1=Employee("Jing", 2000)
print(emp1._Employee__salary) ##访问私有属性的方式一
emp1.get_salary() ##通过实例方法访问私有属性
emp1.set_salary(5000)
emp1.get_salary()
试用@property装饰器的方法
class Employee:
def __init__(self,name,salary):
self.name = name
self.__salary = salary
@property
def salary(self):
return self.__salary
@salary.setter
def salary(self,a):
if 1000<a<10000:
self.__salary = a
return self.__salary
else:
raise ValueError
emp1=Employee("Jing", 2000)
print(emp1._Employee__salary) ##访问私有属性的方式一
emp1.salary ##通过实例方法访问私有属性
emp1.salary= 5000
emp1.salary
类的继承
继承是代码复用的重要手段,子类(派生类)继承了父类(基类)的属性和方法.
- 用
父类.__init__()
来继承父类的构造方法 - 也可以在子类中添加自己的属性和方法
## 类的继承
class Person:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.__gender = gender
@property
def gender(self):
return self.__gender
@gender.setter
def gender(self,a):
self.__gender = a
print(self.__gender)
return self.__gender
class Student(Person):
def __init__(self,name,age,gender,score):
Person.__init__(self, name, age, gender) ##这里调用父类构造函数需要用显示方法,用super会报错
self.score = score
def study():
print("study hard")
S1=Student('Jing', 18, 'formale',80)
print(S1.gender)
S1.gender='male'
1. 类成员的继承和重写
在子类中对父类已经出现的方法重新定义,则调用子类重命名之后的方法
2. 重写__str__()方法
str()方法用来打印信息
class Student:
def __init__(self,name,major):
self.name = name
self.__major= major
S = Student('Jing', "Chem")
print(S)
##输出<__main__.Student object at 0x000001E1507BE7C0>
## 重写__str__()方法
class Student:
def __init__(self,name,major):
self.name = name
self.__major= major
def __str__(self):
return("{0}'s major is {1}".format(self.name,self.__major))
S = Student('Jing', "Chem")
print(S)
##输出Jing's major is Chem
3. 查看类的继承层次结构
通过类的方法 mro()
或者 __mro__
属性
dir()查看对象属性
4. 多重继承
python中一个子类可以有多个直接的父类,这样也就具备了多个父类的特点,但是这样会被类的整体层次搞得异常复杂,尽量避免试用
5. super()获得父类定义
在定义子类时可以用super()函数调用父类的方法
## super()获取父类的定义
class A:
def say(self):
print("A:",self)
class B(A):
def say(self):
# A.say(self)
super().say()
print("B:",self)
B().say()
####输出
# A: <__main__.B object at 0x0000019A4C44E310>
# B: <__main__.B object at 0x0000019A4C44E310>
6. MRO()
Python支持多继承,如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将“从左向右”按顺序进行
MRO: Method Resolution Order
## MRO规则
class A:
def aa(self):
print("aa")
class B:
def aa(self):
print("bb")
class C(B,A):
pass
c=C()
c.aa()
##输出 bb
多态
多态(polymorphism)指同一个方法调用用于不同对象可能会产生不同的行为
- 多态是方法的多态,属性没有多态
- 多态的存在有2个必要条件:继承、方法重写
## 多态
class Man:
def eat(self):
print("饿了,吃饭啦!")
class Chinese(Man):
def eat(self):
print("中国人用筷子吃饭")
class English(Man):
def est(self):
print("英国人用叉子吃饭")
class Indian(Man):
def eat(self):
print('印度人用右手吃饭')
def manEat(m):
if isinstance(m,Man):
m.eat()
else:
print("不用吃饭")
manEat(Chinese()) ##中国人用筷子吃饭
manEat(Indian()) ##印度人用右手吃饭
manEat(Man()) ##饿了,吃饭啦!
1. 特殊方法和运算符重载
Python中的运算符实际上是通过调用对象的特殊方法实现的,比如“+” 是调用__add__,见下表
还有其他的一些特殊方法
- 重新定义一个加法
##自定义加法
class Person:
def __init__(self,name,family_name):
self.name = name
self.family_name = family_name
def __add__(self,other):
if isinstance(other, Person):
return "{0}---{1}".format(self.name,other.name)
else:
raise TypeError("不同类型不能相加")
p1=Person("Jing", 'Yu')
p2=Person('Gao', 'Qi')
p3=1
print(p1+p2) ##输出 Jing---Gao
#print(p1+p3) ##输出TypeError: 不同类型不能相加
3. 组合
组合是一种可以实现类方法复用的计数,是继承的一种替代方法
##测试组合
class A1:
def say_a1(self):
print("a1,a1,a1")
class B1(A1):
pass
b1=B1()
b1.say_a1()
## 同样地,可以用组合实现代码的复用
class A2:
def say_a2(self):
print('a2,a2,a2')
class B2:
def __init__(self,a):
self.a = a
a2 = A2()
b2=B2(a2)
b2.a.say_a2() ## 输出 a2, a2, a2
3. 特殊属性
Python对象中包含了很多双下划线开始和结束的属性,这些是特殊属性,有特殊的用法,实例:
设计模式
设计模式是面向对象语言特有的内容,是我们在面临一类问题是固定的做法,设计模式有很多种,比较流行的是GOF23种设计模式,当然,我们没有必要全部学习,学习几个常用的极客
最常用的两个模式:工厂模式,单例模式
- 工厂模式实现了创建者和调用者的分离,试用专门的工厂类将选择实现类、创建对象进行统一的管理和控制
- 单例模式的核心作用是确保i各类只有一个实例,并且提供访问一个访问该实例的全局访问点。减少开销