函数只有在对象中才能叫方法,在其他地方叫函数,静态方法是函数

在类的内部当中使用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)

avatar

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__)

类的私有成员

对于每个类的成员都有两种形式:

  1. 公有:在任何地方都能访问
  2. 私有:只有在类的内部才能访问

静态属性:

  1. 公有静态:类、类内部、派生类可以访问
  2. 私有静态:仅内部可以访问

方法:

  1. 公有方法:对象、类内部、派生类可以访问
  2. 私有方法:仅类内部可以访问

但是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 # 删除商品原价

标签: none

评论已关闭