面向对象进阶学习

面向对象高级语法部分

  • 经典类vs新式类  
  • 静态方法、类方法、属性方法
  • 类的特殊方法
  • 反射

classical vs new style:

  • 经典类:深度优先
  • 新式类:广度优先
  • super()用法

静态方法

首先看下面的例子

#创建一个Cat类
class Cat(object):
    def __init__(self,name):
        self.name = name

    def eat(self):#创建eat方法
        print("%s 在吃猫粮" %self.name)

c1 = Cat("蘑菇") #创建一个对象
c1.eat() #c1对象调用eat()类方法

运行后输出结果

D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
蘑菇 在吃猫粮

Process finished with exit code 0

把代码修改一下,

#创建一个Cat类
class Cat(object):
    def __init__(self,name):
        self.name = name


    @staticmethod
    def eat(self):#把eat()转变为静态方法
        print("%s 在吃猫粮" %self.name)

c1 = Cat("蘑菇") #创建一个对象
c1.eat() #c1对象调用eat()类方法

运行一下,输出结果报错了,提示eat()方法需要一个self参数,在eat()变成静态方法后,再通过实例调用eat()时,实例不会再把实例当做参数传入到self里了。换言之eat()实际上变成了普通的方法,与类已经没有关系了。

D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
Traceback (most recent call last):
  File "D:/7_Python/S14/Day6/学习笔记.py", line 13, in <module>
    c1.eat() #c1对象调用eat()类方法
TypeError: eat() missing 1 required positional argument: 'self'

Process finished with exit code 1

想让上面的代码可以正常工作有两种办法

1. 调用时主动传递实例本身给eat方法,即c1.eat(c1) 

#创建一个Cat类
class Cat(object):
    def __init__(self,name):
        self.name = name


    @staticmethod
    def eat(self):#把eat()转变为静态方法
        print("%s 在吃猫粮" %self.name)

c1 = Cat("蘑菇") #创建一个对象
c1.eat(c1) #c1对象调用eat()类方法

2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了

#创建一个Cat类
class Cat(object):
    def __init__(self,name):
        self.name = name


    @staticmethod
    def eat():#把eat()转变为静态方法
        print("%s 在吃猫粮" %"蘑菇" )

c1 = Cat("蘑菇") #创建一个对象
c1.eat() #c1对象调用eat()类方法

类方法

类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量

#创建一个Cat类
class Cat(object):
    def __init__(self,name):
        self.name = name


    @classmethod
    def eat(self):#创建eat方法
        print("%s 在吃猫粮" %self.name)

c1 = Cat("蘑菇") #创建一个对象
c1.eat() #c1对象调用eat()类方法

运行后报错,提示Cat没有name属性,因为name是个实例变量,类方法是不能访问实例变量的

D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
Traceback (most recent call last):
  File "D:/7_Python/S14/Day6/学习笔记.py", line 13, in <module>
    c1.eat() #c1对象调用eat()类方法
  File "D:/7_Python/S14/Day6/学习笔记.py", line 10, in eat
    print("%s 在吃猫粮" %self.name)
AttributeError: type object 'Cat' has no attribute 'name'

Process finished with exit code 1

再修改一下代码:

#创建一个Cat类
class Cat(object):
    name = "大黄"#添加类变量
    def __init__(self,name):
        self.name = name


    @classmethod
    def eat(self):#创建eat方法
        print("%s 在吃猫粮" %self.name)

c1 = Cat("蘑菇") #创建一个对象
c1.eat() #c1对象调用eat()类方法

执行结果

D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
大黄 在吃猫粮

Process finished with exit code 0

 属性方法

属性方法的作用就是通过@property把一个方法变成一个静态属性

#创建一个Cat类
class Cat(object):

    def __init__(self,name):
        self.name = name


    @property
    def eat(self):#创建eat方法
        print("%s 在吃猫粮" %self.name)

c1 = Cat("蘑菇") #创建一个对象
c1.eat() #c1对象调用eat()类方法

运行结果报错:

D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
Traceback (most recent call last):
蘑菇 在吃猫粮
  File "D:/7_Python/S14/Day6/学习笔记.py", line 14, in <module>
    c1.eat() #c1对象调用eat()类方法
TypeError: 'NoneType' object is not callable

Process finished with exit code 1

由于eat()方法现在已经变成了属性,所以在调用的时候不需要再加(),直接调用就可以了

#创建一个Cat类
class Cat(object):

    def __init__(self,name):
        self.name = name


    @property
    def eat(self):#创建eat方法
        print("%s 在吃猫粮" %self.name)

c1 = Cat("蘑菇") #创建一个对象
c1.eat #c1对象调用eat属性方法

结果如下:

D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
蘑菇 在吃猫粮

Process finished with exit code 0

我们为什么要使用属性方法呢,直接使用静态属性不就好了吗。但是在很多场景下,我们不能简单的定义静态属性

class Cat(object):
    def __init__(self,name):
        self.name = name


    def checking_status(self):
        print("看看%s在干什么" %self.name)
        return 1


    @property
    def cat_status(self):
        status = self.checking_status()
        if status == 0:
            print("睡觉")
        elif status == 1:
            print("吃饭")
        elif status == 2:
            print("喝水")
        else:
            print("不知道")


c = Cat("蘑菇")
c.cat_status

输出结果

D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
看看蘑菇在干什么
吃饭

Process finished with exit code 0

cat_status既然现在是静态属性,能不能给它赋值

c = Cat("蘑菇")
c.cat_status
c.cat_status = 2

报错了

D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
看看蘑菇在干什么
吃饭
Traceback (most recent call last):
  File "D:/7_Python/S14/Day6/学习笔记.py", line 26, in <module>
    c.cat_status = 2
AttributeError: can't set attribute

Process finished with exit code 1

怎么办

通过@proerty.setter装饰器再装饰一下,此时 需要写一个新方法, 对这个cat_status进行更改


class Cat(object):
def __init__(self,name):
self.name = name
self.status = 1


def checking_status(self):
print("看看%s在干什么" %self.name)
return self.status


@property
def cat_status(self):
self.status = self.checking_status()
if self.status == 0:
print("睡觉")
elif self.status == 1:
print("吃饭")
elif self.status == 2:
print("喝水")
else:
print("不知道")

@cat_status.setter
def cat_status(self,status):
status_dic = {
0 : "睡觉",
1 : "吃饭",
2 : "喝水",
}
print("\033[31;1m准备去 \033[0m",status_dic.get(status))
self.status = status

@cat_status.deleter #删除
def cat_status(self):
print("status got removed...")


c = Cat("蘑菇")
c.cat_status
c.cat_status = 0
c.cat_status

挺有意思

类的特殊成员方法

1. __doc__  表示类的描述信息

class Cat(object):
    '''描述猫咪的各种生活习惯'''

    def func(self):
        pass

print(Cat.__doc__)

 2. __call__ 对象后面加括号,触发执行。

class Cat(object):
    '''描述猫咪的各种生活习惯'''

    def func(self):
        pass


    def __call__(self, *args, **kwargs):
        print('喵喵')

c = Cat()
c()

3. __dict__ 查看类或对象中的所有成员 

class Cat(object):
    '''描述猫咪的各种生活习惯'''

    def __init__(self,name):
        self.name = name


    def func(self, *args, **kwargs):
        print('%s 喵喵'%self.name)

c = Cat("蘑菇")
c.func()

print(Cat.__dict__)
print(c.__dict__)

4 __str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

class Cat(object):
    '''描述猫咪的各种生活习惯'''

    def __init__(self,name):
        self.name = name


    def func(self, *args, **kwargs):
        print('%s 喵喵'%self.name)

    def __str__(self):
        return '蘑菇是只猫咪'
c = Cat("蘑菇")
c.func()

print(c)

5.__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

6 __new__ \ __metaclass__

反射

# hasattr(obj,func)  判断obj中有没有func
# getattr(obj,func)  从obj中获取func
# setattr(obj,func1,func/xyz) 在obj中以func1名称设置func或变量
# delattr(obj,func)  在obj中删除func





class Cat(object):
    def __init__(self,name,food):
        self.name = name
        self.food = food

    def eat(self):
        print("%s在吃%s" %(self.name,self.food))

def play(self):
    print("%s在玩耍" %self.name)


c = Cat("蘑菇","猫粮")
#c.eat()

user_option = input(">>:").strip()
if hasattr(c,user_option):
    func = getattr(c,user_option)
    func()
else:
    setattr(c,user_option,play)
    func = getattr(c,user_option)
    func(c)

print(c.__dict__)
# delattr(c,'eat')
# c.eat()

猜你喜欢

转载自www.cnblogs.com/goldtree358/p/11810185.html