类的补余
类
函数只有在对象中才能叫方法,在其他地方叫函数,静态方法是函数
在类的内部当中使用self变量的都是属于对象的命名空间的,而不使用self的变量都是属于类的命名空间的,可通过__dict__来查看
对象名.属性 = 值,当这个属性存在,则会修改值,当不存在,则会新建一个,但不会修改类下属性
对象查找属性的顺序:对象--类空间--父类空间--》。。。
类名查找属性的空间:类空间--》父类空间--》。。。
子类对象访问父类的方法:
子类名.父类属性或者子类对象名.父类属性
如果子类和父类中有同名方法,访问的顺序是:
子类命名空间、父类命名空间、父类的父类.....
当子类中有父类的同名方法,调用父类的方法的是:
父类.方法、super().方法
基础补余
class MySelf:
name = 'lord'
age = 999
def CallMe(self):
print('My lord')
print(MySelf.__dict__)#查看类或者对象中的所有内容
MySelf.age=666#修改属性的值
print(MySelf.age)
a = MySelf
print(a.age)
import random
import time
class play_roler:
def __init__(self,name,ad,hp):
self.name = name
self.ad = int(ad)
self.hp = int(hp)
def attack(self,enmeny):
enmeny.hp -= self.ad
print(f'{self.name}攻击了{enmeny.name}并造成了{self.ad}伤害!')
if enmeny.hp <= 0:
print(f'{enmeny.name}死了!')
sunwukong = play_roler('孙悟空',20,500)
caocao = play_roler('曹操',20,100)
anqila = play_roler('安其拉',50,80)
baigujing = play_roler('白骨精',30,450)
guanyu = play_roler('关羽',80,200)
diaochan = play_roler('貂蝉',60,150)
dongxie = [sunwukong,caocao,anqila]
xidu = [baigujing,guanyu,diaochan]
print(dongxie)
len1 = len(dongxie)
len2 = len(xidu)
while (len1 > 0) and (len2 > 0):
a = random.choice(dongxie)
b = random.choice(xidu)
a.attack(b)
if b.hp <= 0:
xidu.remove(b)
len2 -=1
b.attack(a)
if a.hp <= 0:
dongxie.remove(a)
len1 -= 1
if len1 > 0:
print('东邪获胜!')
else:
print('西毒获胜!')
依赖关系
class Kill:
def killSomething(self,obj1):
print('杀!')
obj1.voice()
print('死了')
class Animal:
def __init__(self,name):#双下方法/魔法方法
self.name = name
def voice(self):
print(f'{self.name}:ゴゴゴゴゴゴゴ')
a = Animal('Chicken')
b = Kill()
b.killSomething(a)
# 杀!
# Chicken:ゴゴゴゴゴゴゴ
# 死了
多继承
class Kill:#如果什么都不写,则默认继承自object类
def killSomething(self,obj1):
print('杀!')
obj1.voice()
print('死了')
class Animal:
def __init__(self,Name='abc'):
self.name = Name
def voice(self):
print(f'{self.name}:ゴゴゴゴゴゴゴ')
# a = Animal('Chicken')
# b = Kill()
# b.killSomething(a)
class trainee:
def skill(self):
print("唱跳rap篮球")
class beautiful(Animal,trainee):
def __init__(self,name):#如果子类没有init,会去父类找
Animal.__init__(self,name)#self一定要加,这里也可用super().__init__,调用顺序严格按照继承顺序
ChickenBrother = beautiful('Chicken')
ChickenBrother.voice()
ChickenBrother.skill()
经典类中采用的是深度优先,遍历方案,也就是一条路走到头再走下一条,可以使用对象的mro方法才查看,mro是一个有序列表,在类被创建时就被计算出来,可用__mro__来调用查看
新式类的基类继承自object,自2.2开始有,3中全是新式类。经典类在基类没有继承
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )(其中Child继承自Base1, Base2)
mro(A) = mro( A(B,C) )
原式= [A] + merge( mro(B),mro(C),[B,C] )
mro(B) = mro( B(D,E) )
= [B] + merge( mro(D), mro(E), [D,E] ) # 多继承
= [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承
mro(D(O))=[D,O] = [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D
= [B,D,E] + merge([O] , [O])
= [B,D,E,O] mro(C)
= mro( C(E,F) )
= [C] + merge( mro(E), mro(F), [E,F] )
= [C] + merge( [E,O] , [F,O] , [E,F] )
= [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除
= [C,E,F] + merge([O] , [O])
= [C,E,F,O] 原式
= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
= [A,B] + merge( [D,E,O], [C,E,F,O], [C])
= [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E
= [A,B,D,C] + merge([E,O], [E,F,O])
= [A,B,D,C,E] + merge([O], [F,O]) # 跳过O
= [A,B,D,C,E,F] + merge([O], [O])
= [A,B,D,C,E,F,O]
多态性
多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物,类似于抽象基类
@abc.abstractmethod#用于虚化方法的修饰器
def talk(self):
pass
class Cat(Animal): #动物的形态之一:猫
def talk(self):
print('say miaomiao')
class Dog(Animal): #动物的形态之二:狗
def talk(self):
print('say wangwang')
class Pig(Animal): #动物的形态之三:猪
def talk(self):
print('say aoao')
c = Cat()
d = Dog()
p = Pig()
def func(obj):
obj.talk()
func(c)
func(d)
func(p)
------------------------------
>>> say miaomiao
>>> say wangwang
>>> say aoao
反射
通过字符串的形式操作对象相关的属性,python中一切皆对象
hasattr:判断对象中是否有这个方法或变量,返回True\False
hasattr(a,'say')
判断a中是否存在say方法或者变量
getattr:获取对象中的方法或者变量的内存地址
getattr(p,'a','not find')
在p中查找a,如果没有打印not find
setattr:为对象添加变量或方法
setattr(p,'say','go!')添加变量say,值为go!
p.say(p)因为是额外添加的方法,需要手动传入对象
delattr:删除对象中的变量,不能删除方法
delattr(p,'name')
class Foo:
f = '类的静态变量'
def __init__(self,name,age):
self.name=name
self.age=age
def say_hi(self):
print('hi,%s'%self.name)
obj = Foo('张三',73)
# 检测是否含有某属性
print(hasattr(obj,'name'))
print(hasattr(obj,'say_hi'))
# 获取属性
n=getattr(obj,'name')
print(n)
func=getattr(obj,'say_hi')
func()
print(getattr(obj,'aaaaaaaa','不存在啊')) # 报错
# 设置属性
setattr(obj,'sg',True)
setattr(obj,'show_name',lambda self:self.name+'sg')
print(obj.__dict__)
print(obj.show_name(obj))
# 删除属性
delattr(obj,'age')
delattr(obj,'show_name')
# delattr(obj,'show_name111') # 不存在,则报错
print(obj.__dict__)
类的私有成员
对于每个类的成员都有两种形式:
- 公有:在任何地方都能访问
- 私有:只有在类的内部才能访问
静态属性:
- 公有静态:类、类内部、派生类可以访问
- 私有静态:仅内部可以访问
方法:
- 公有方法:对象、类内部、派生类可以访问
- 私有方法:仅类内部可以访问
但是py的私有成员可以通过对象._类__属性名来强制访问,所以不推荐
class C:
name = '公有静态'
__name = '私有静态'
def func(self):
print(f'inner name{self.name}')
print(f'inner __name{self.__name}')
class D(C):
pass
print('out name',C.name)
print('out __name',C.name)
son = D()
obj = C()
obj.func()
print('obj.name',obj.name)
print('D.name',son.name)
# print('obj.__name',obj.__name)
# print('D.__name',son.__name)
类的其他成员
普通方法(实例方法)、静态方法、类方法
普通方法的第一个参数必须是实例对象,即self,通过他来传递实例的属性和方法,调用只能由实例对象调用
类方法使用装饰器@classmethod,第一个参数必须是当前类对象,即cls,通过他来传递类的属性和方法,可通过实例对象或者类调用
静态方法使用@staticmethon,参数随意,但是方法体中不能使用类或实例的任何属性和方法,类和实例对象都可以调用
类方法
class A: company_name = '刷刷刷' # 静态变量(静态字段)
__iphone = '132333xxxx' # 私有静态变量(私有静态字段)
def __init__(self,name,age): #特殊方法
self.name = name #对象属性(普通字段)
self.__age = age # 私有对象属性(私有普通字段)
def func1(self): # 普通方法
pass
def __func(self): #私有方法
print(666)
@classmethod # 类方法
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """
print('类方法')
@staticmethod #静态方法
def static_func():
""" 定义静态方法 ,无默认参数"""
print('静态方法')
@property # 创建只读属性
def prop(self):
pass
class Game:
top_score = 0
def __init__(self,name):
self.player_name = name
def start_game(self):
print(f'{self.player_name}开始了游戏!')
@staticmethod
def show_help():
print('欢迎来到厦门最大的线上赌场')
@classmethod
def show_top_score(cls):
print(f'当前游戏的最高分是{cls.top_score}')
if __name__ == '__main__':
Game.show_help()
Game.show_top_score()
a = Game('张三')
a.start_game()
双下方法
__len__
class B:
def __len__(self):
return 666
b = B()
print(len(b)) # len 一个对象就会触发 __len__方法。
__str__
#如果一个类中定义了str方法,在打印对象时,默认会输出该方法的返回值
class A:
def __init__(self):
pass
def __str__(self):
return '123'
a = A()
print(a)
print('%s' % a)
__call__
class Foo:
def __init__(self):
print('__init__')
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
print(callable(obj))#判断是否可调用,如果删掉call会报false
__eq__
class A:
def __init__(self):
self.a = 1
self.b = 2
def __eq__(self,obj):
if self.a == obj.a and self.b == obj.b:
return True
a = A()
b = A()
print(a == b)#判断两个值是否相等,如果没有eq会报错
__new__
new方法是类准备将自身实例化时调用的,其始终是类的静态方法,通常来说,新式类开始实例化的时候,new方法会返回cls(当前类)的示例,然后init方法作为构造方法会接收这个实例(self)作为自己的第一个参数,然后依次传入new方法中接收的位置参数和命名参数
单例模式:使得一个类只有一个实例
class A:
__instance = None
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
obj = object.__new__(cls)
cls.__instance = obj
return cls.__instance
__enter__
,__exit__
,上下文管理器
#自定义文件管理器
class Diycontextor:
def __init__(self, name, mode):
self.name = name
self.mode = mode
def __enter__(self): #开启上下文管理器对象时触发
print("Hi enter here!!")
self.filehander = open(self.name, self.mode)
return self.filehander
def __exit__(self,*args): #退出时执行
print("Hi exit here")
self.filehander.close()
with Diycontextor('config', 'r') as f:
for i in f:
print(i.strip())
Property
我们可以用@peoperty装饰器来创建只读属性,他能把函数当作属性来访问并执行
class Goods(object):
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()
print(obj.price) # 获取商品价格
obj.price = 200 # 修改商品原价
print(obj.price)
del obj.price # 删除商品原价
评论已关闭