1、写一个类
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
return "this is function run"
def __getattr__(self, item):
return "111"
F = Foo("张三", 12)
print(F.age) # 12
print(F.run) # <bound method Foo.run of <__main__.Foo object at 0x000001292A4F71C0>>
print(F.run()) # this is function run
print(F.xxxxx) # 111
1、__getattr__方法,访问类中不存在的成员时触发,访问对象中存在的成员时不会触发
2、__getattribute__方法,访问任何成员都会先执行他,报错是因为返回的999,应该判断是否是函数再执行他,这里是示例代码:
class Foo:
count = 0
def __init__(self, name, age):
self.name = name
self.age = age
# 统计实例化了几个对象,所有对象能共享的数据
Foo.count += 1
def run(self):
return "this is function run"
def __getattr__(self, item):
return "111"
def __getattribute__(self, item):
print("__getattribute__执行了")
return 999
F = Foo("张三", 12)
print(F.age) # 999
print(F.run) # 999
print(F.run())
print(F.xxxxx)
3、property的使用,把方法变成不加括号可调用
class Foo:
def __init__(self, name, age):
self.__name = name
self.__age = age
def run(self):
return "self是" + str(self) + "这是Foo下边的run方法"
@property
def get_name(self):
return self.__name
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
self.__age = age
@age.deleter
def age(self):
del self.__age
F = Foo("张三", 12)
print("F的年龄", F.age) # F的年龄 12
print(F.get_name) # 张三
F.age = 1
print("F的年龄", F.age) # F的年龄 1
del F.age
print("F的年龄", F.age) # AttributeError: 'Foo' object has no attribute '_Foo__age'
print(Foo.run(F))
4、__str__方法,指定打印对象时的输出
5、__del__方法,对象销毁之前执行
2、写两个类(继承,封装,多态)
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
self.sleep()
return "self是" + str(self) + "这是Foo下边的run方法"
def sleep(self):
return "self是" + str(self) + "这是Foo下边的sleep方法"
class Boo(Foo):
def __init__(self):
self.x = 123
def sleep(self):
return "self是" + str(self) + "这是Boo下边的sleep方法"
F = Foo("张三", 12)
print(F.run())
### self是<__main__.Foo object at 0x000002BFF5FC71C0>这是Foo下边的run方法
B = Boo()
print(B.run())
### self是<__main__.Boo object at 0x000002BFF620C610>这是Foo下边的run方法
注意:子类调用父类的方法,self还是子类对象本身,所以,F.run()里执行的sleep是Foo的,B.run()执行的sleep是Boo的;
但是当sleep方法是隐藏方法(__sleep())的话,那就肯定访问的是Foo的sleep方法,因为隐藏方法的名字被改成了:_类名__方法名,父子的方法名不是一样的了;
继承( )
派生
子类除了父类还需实例化出更多的属性,先调用父类的init,再写自己需实例化的属性
class Human:
star = "earth"
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class Chinese(Human):
language = "Chinese"
def __init__(self, name, age, sex, account):
super().__init__(name, age, sex)
self.account = account
def speak(self):
print(self.name + "在说" + self.language)
class America(Human):
language = "English"
def speak(self):
print(self.name + "在说" + self.language)
C = Chinese("董永", 18, "男", 1000)
print(C.__dict__)
C.speak()
A = America("泰勒斯威夫特", 18, "女")
print(A.__dict__)
A.speak()
"""
输出:
{'name': '董永', 'age': 18, 'sex': '男', 'account': 1000}
董永在说Chinese
{'name': '泰勒斯威夫特', 'age': 18, 'sex': '女'}
泰勒斯威夫特在说English
"""
查找类的继承顺序:
非菱形继承不分新式类和经典类,也没有深度和广度的概念,就是一条分支走完走另一条,新式类继承object,经典类不继承object
对于菱形继承的深度优先和广度优先,都是按分支找完,区别就是深度优先会在第一条分支去找顶点类,广度优先最后找顶点类
1、python3(非菱形,新式类)F-C-A-D-B-E
python3(菱形,新式类)是广度优先,F-C-A-D-B-E-Z
2、python2(非菱形,新式类)F-C-A-D-B-E
python2(非菱形,经典类)F-C-A-D-B-E
python2(菱形,经典类),是深度优先,F-C-A-Z-D-B-E
python2(菱形,新式类),是广度优先,F-C-A-D-B-E-Z
print(Chinese.mro()),查找属性的顺序就是根据这个顺序来找的
MixIn只是一种概念
class Fowl: # 家禽类
pass
# 只是一种命名规范,类名以MixIn结尾,代表混入一些功能,含义是鸡鸭鹅是家禽,但鸭鹅有游泳的工能
class SwimMixIn:
def swimming(self):
pass
class Chicken(Fowl): # 鸡
pass
class Duck(Fowl, SwimMixIn): # 鸡
pass
class Goose(Fowl, SwimMixIn): # 鸡
pass
super()
严格意义上来说不是说是父类,而是Chinese.mro(),列表的下一个类
多态
父类的方法,子类都能调用(父类统一子类的所有方法),
class Car:
def run(self):
print("开始跑")
class Auto(Car):
def run(self):
super().run()
print("Auto开始跑")
class Benzi(Car):
def run(self):
super().run()
print("Benzi开始跑")
class tesla(Car):
def run(self):
super().run()
print("tesla开始跑")
1、抽象基类(规范子类必须有什么东西,不推荐)
子类Auto必须实现run方法
import abc
class Car(metaclass=abc.ABCMeta):
@abc.abstractmethod
def run(self):
print("开始跑")
class Auto(Car):
pass
auto = Auto()
"""
报错
Traceback (most recent call last):
File "C:/Users/凉生/AppData/Roaming/JetBrains/PyCharm2021.2/extensions/混入功能.py", line 33, in <module>
auto = Auto()
TypeError: Can't instantiate abstract class Auto with abstract methods run
"""
2、父类主动抛出异常,子类调用父类方法时会报错
class Foo:
def f1(self, a):
raise NotImplementedError("'子类必须实现此功能")
class Boo(Foo):
def run(self, a):
print(111)
b = Boo()
b.run(1) # 不报错
b.f1(1) # 报错
3、反射
class Human:
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print(self.name)
return self.name
def input_something(self):
self.cmd = input(">>>")
getattr(self, self.cmd, self.warning)()
def warning(self):
print("没有此方法", self.cmd)
human = Human("张三", 19)
print(hasattr(human, "age")) # True
print(getattr(human, "age")) # 19
print(getattr(human, "age1", 22)) # 22,指定默认值
print(getattr(human, "run")) # <bound method Human.run of <__main__.Human object at 0x00000251DF4A81C0>>
print(getattr(human, "run")()) # 张三
human.input_something()
4、元类
type是元类
# 第1步
class_name = "Human" # 类名
# 第2步
class_bases = (object,) # 基类
# 第3步
class_dic = {} # 执行子代码,产生名称空间
class_body = """
def __init__(self, name, age):
self.name=name
self.age=age
def speak(self):
print(self)
"""
exec(class_body, {}, class_dic)
# 第4步
Human = type(class_name, class_bases, class_dic) # type是元类
print(Human) # 输出:<class '__main__.Human'>
obj = Human("张三", 12)
print(obj) # 输出:<__main__.Human object at 0x000001CB1C1056D0>
自定义元类
# 自定义元类
class Mytype(type):
def __init__(self, class_name, class_bases, class_dic):
if "_" in class_name:
raise NameError("类名不能有下划线")
print("class_name:", class_name)
print("class_bases:", class_bases)
print("self.__bases__:", self.__bases__)
print("class_dic:", class_dic)
# 在 init方法前执行
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
# 定了这个方法,才能实例化对象,也就是 类型加(),例如 Chinese()
def __call__(cls, *args, **kwargs):
obj = cls.__new__(cls, *args, **kwargs)
cls.__init__(obj , *args, **kwargs)
class Chinese(metaclass=Mytype):
language = "Chinese"
def __init__(self, name, age, sex, x):
self.name = name
self.age = age
self.sex = sex
self.x = x
def speak(self):
print(self.name + "在说" + self.language)
class BeiJingR(Chinese):
pass
print("这个类继承了Chinese, 她也是由自定义的Mytype创建的")
Mytype()
5、单例模式
1、模块(用的最多)
python的模块就是一个天然的单例模式
base.py文件定义类,实例化出一个对象obj
class Human:
def __init__(self, name, age):
self.name = name
self.age = age
obj = Human("张大仙", 73)
在其他模块里导入这个对象obj,例如test.py里
from base import obj
2、类装饰器(面试问)
# 2、类装饰器(面试问)
def singleton_mode(func):
obj = None # 定义一个类,第一次是空,往后都会有值
def wrapper(*args, **kwargs):
nonlocal obj
if not obj: # 如果没有值,就实例化对象
obj = func(*args, **kwargs) # obj赋值
return obj # 返回对象
return wrapper
@singleton_mode # Human = singleton_mode(Human)
class Human:
def __init__(self, name, age):
self.name = name
self.age = age
obj1 = Human("张大仙", 73)
obj2 = Human("张大仙", 73)
print(obj1 == obj2) # True
3、类绑定方法(面试问)
# 3、类绑定方法(面试问)
class Human:
obj = None
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def get_obj(cls, *args, **kwargs):
if not cls.obj:
cls.obj = cls(*args, **kwargs)
return cls.obj
obj1 = Human.get_obj("张大仙", 73)
obj2 = Human.get_obj("张大仙", 73)
print(obj1 == obj2) # True
4、__new__方法(面试问)
# 4、__new__方法(面试问)
class Human:
obj = None
def __init__(self, name, age):
self.name = name
self.age = age
def __new__(cls, *args, **kwargs):
if not cls.obj:
cls.obj = super().__new__(cls)
return cls.obj
obj1 = Human("张大仙", 73)
obj2 = Human("张大仙", 73)
print(obj1 == obj2) # True
5、元类(面试问)
# 5、元类(面试问)
class MyType(type):
obj = None
def __call__(self, *args, **kwargs):
if not self.obj:
self.obj = super().__call__(*args, **kwargs)
return self.obj
class Human(metaclass=MyType):
def __init__(self, name, age):
self.name = name
self.age = age
obj1 = Human("张大仙", 73)
obj2 = Human("张大仙", 73)
print(obj1 == obj2) # True