Python菜鸟编程第十二课之魔法方法一

Python菜鸟编程第十二课之魔法方法1

此篇博客,内容还不丰富,包括心得就只有寥寥几行,目前本人还在不断完善中。
博主QQ:1031748759,欢迎批评指正!

1.静态方法

通过装饰器@staticmethod来进行装饰。静态方法既不需要传递类对象也不需要传递实例对象。

静态方法也可以通过实例和类对象去访问。

demo:

class Dog:
    type = '狗'

    def __init__(self):
        name = None

    # 静态方法
    @staticmethod
    def introduce():  # 静态方法不会知道传递实例对象和类对象
        print('犬科哺乳动物,属于肉食目。')


dog = Dog()
Dog.introduce()
dog.introduce()
运行结果:
犬科哺乳动物,属于肉食目。
犬科哺乳动物,属于肉食目。

静态方法时类中的函数,不需要实例。静态方法主要是是用来存放逻辑性的代码,逻辑上属于类,但和类本身没有关系,也就是说,在静态方法中,不会涉及类中属性和方法的操作。静态方法是一个独立的,单纯的函数,仅仅是托管于某个类的名称空间中,便于维护和管理。

高老师 2019/7/31 11:05:39

1.1使用场景:

  • 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
  • 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
  • 如果在类外面写一个同样的函数来做这些事,打乱了逻辑关系,导致代码维护困难,使用静态方法。

2.类方法

类方法:类对象所拥有的方法,需要用装饰器@classmethod来标识其为类方法。对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数

使用场景:

  • 当方法中需要使用类对象(如访问私有类属性等)时,定义类方法。
  • 类方法一般和类属性配合使用。

注意:累涨定义了同名的对象方法,类方法以及静态方法时,调用

demo:

class Dog:
    __type = '狗'


    # 类方法
    @classmethod
    def get_type(cls):  # 静态方法不会知道传递实例对象和类对象
        return cls.__type

print(Dog.get_type())
运行结果:
狗

demo:

class Dog:
    def demo_method(self):
        print('对象方法。')
    @classmethod
    def demo_method(cls):
        print('类方法')

    @staticmethod #最后被定义,调用时优先执行
    def demo_method():
        print('静态方法。')

dog=Dog()
Dog.demo_method()
dog.demo_method()
运行结果:
静态方法。
静态方法。

3.Property

3.1概述:

在Python中主要为属性提供一个便利的操作方式。

demo:

如果我们现在需要设计一个银行账户类,这个类中包含人的姓名,余额,(假如现在不考虑具体的操作接口)。

class Account(object):
    def __init__(self, name, money):
        self.name = name
        self.balance = money

问题:不安全(设计简单方便,所有的属性,外部都可以访问修改)

改进1:隐藏实现细节

对于账户信息而言,金额不允许让用户直接修改。

class Account(object):
    def __init__(self, name, money):
        self.__name = name
        self.__balance = money

代码改进之后,将所有属性设计为所有属性。从外部使用时,不知道内部的属性,不能直接修改对象,隐藏了实现的细节。但仍存在一个问题:如何修改这个两个属性?

改进2:

经过修改,外部使用这个类的对象时,想使用对象中的属性,只能通过类中提供的 set/get 接口来操作,提高了程序的安全性。

这样,程序基本达到了设计需求,但是能不能更加完善呢?

如果在使用这个类的对象过程中,由于误操作,传入了不正常的数据,导致数据异常。该如何以避免这种情况发生呢?

比如:设置金额时出现了负数,或字符串,或其它类型的对象。

class Account(object):
    def __init__(self, name, money):
        self.__name = name
        self.__balance = money

    def get_name(self):
        return self.__name

    def set_balance(self,money):
        self.__balance=money

    def get_balance(self):
        return self.__balance

改进3:

set_balance对用户输入数据的有效性进行判断,无效则报错。

class Account(object):
    def __init__(self, name, money):
        self.__name = name
        self.__balance = money

    def get_name(self):
        return self.__name

    def set_balance(self,money):
        if isinstance(money,int):
            if money>0:
                self.__balance=money
            else:
                raise ValueError('输入金额不正确')
        else:
            raise ValueError('输入的金额不是数字')

    def get_balance(self):
        return self.__balance

改进4:

经过几个版本的迭代,程序看上去越来健壮,安全性也越来越高。但是使用过程中,可以不可以更精炼一些?

使用property类。

在Python中,提供了一个property类,通过对创建这个类的对象的设置,在使用对象的私有属性时,可以不再使用属性的函数调用方式,而是普通的公有属性一样去使用属性,为开发者提供便利。

property(fget=None,fest=None,fdel=None,doc=None)

property是一个类,__init__方法由四个参数组成,实例后返回一个用来操作属性的对象。

  • fget:属性的获取方法
  • fest:属性的设置方法
  • fdel:属性的删除方法
  • doc:描述属性
class Account(object):
    def __init__(self, name, money):
        self.__name = name
        self.__balance = money

    def __get_name(self):
        return self.__name

    def set_balance(self, money):
        if isinstance(money, int):
            if money > 0:
                self.__balance = money
            else:
                raise ValueError('输入金额不正确')
        else:
            raise ValueError('输入的金额不是数字')

    def get_balance(self):
        return self.__balance

    name = property(__get_name)
    balance = property(get_balance, set_balance)


ac = Account('Tom', 10000)
print(ac.name)
print(ac.balance)
运行结果:
Tom
10000

通过 property 类实例对象以后,在使用对象中的属性时,就可以像使用普通公有属性一样来调用,但是实际调用的还是 set/get 方法。 在实例 property 对象时,不是所有的参数都需要写,比如示例中的 name 只提供了 get 方法,并且是一个私有的方法。这样就完全隐藏了内部的实现细节 。

改进5:

class Account(object):
    def __init__(self, name, money):
        self.__name = name
        self.__balance = money

    @property
    def name(self):
        return self.__name

    @property
    def balance(self):
        return self.__balance

    @balance.setter
    def set_balance(self, money):
        if isinstance(money, int):
            if money > 0:
                self.__balance = money
            else:
                raise ValueError('输入金额不正确')
        else:
            raise ValueError('输入的金额不是数字')

    def get_balance(self):
        return self.__balance

    # name = property(__get_name)
    # balance = property(get_balance, set_balance)


ac = Account('Tom', 10000)
print(ac.name)
print(ac.balance)
运行结果:
Tom
10000

4.self

如果对象的方法中需要使用该对象的属性,怎么办?

关键字self主要用于对象方法中,表示调用该方法的对象。在方法中使用self,可以获取到调用当前方法的对象,进而获取该对象的属性和方法。

调用对象的方法时,为什么不需要设置self对应的参数?

某个对象调用其方法时,Python解释器会把这个对象作为第一个参数传递给方法,所以,开发者只需要在定义的时候‘预留第一个self’即可。

demo:

class Cat():
    # 方法
    def introduce(self):
        print('name is: %s,age is %d' % (self.name, self.age))


cat = Cat()
cat.name = 'Tom'
cat.age = 6
cat.introduce()
运行结果:
name is: Tom,age is 6

4.1方法内定义属性

使用self操作属性和对象的变量名在效果上类似,

demo:

class Cat():
    # 方法
    def introduce(self):
        self.type='小型动物'

cat=Cat()
cat.introduce()
print(cat.type)
运行结果:
小型动物

5.__new__方法

创建对象时,系统会自动调用__new__方法.开发者可以使用__new__方法来自定义对象的创建过程。

  • __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
  • __new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
  • __init__有一个参数self,就是这个__new__返回的实例,__init____new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
  • 如果创建对象时传递了自定义参数,且重写了new方法,则new也必须 “预留” 该形参,否则init方法将无法获取到该参数

demo1:

class Cat:
    def __new__(cls, name):
        print('创建对象')
        return object.__new__(cls)

    def __init__(self,name):
        print('对象初始化')
        self.name=name

    def __str__(self):
        return '%s' %self.name

cat=Cat('蓝猫')
print(cat)
#可以理解为:
#cat=object.__new__(Cat)
#Cat.__init__(cat,'蓝猫')
运行结果:
创建对象
对象初始化
蓝猫

demo2:

class Student:
    def __new__(cls, *args, **kwargs):
        print('this is new')
        print(*args)  # print(args)时,输出元组('Bob',)
        return object.__new__(cls)

    def __init__(self, name):
        print('this is init')
        self.name = name

    def __call__(self, classmate):
        print('我的名字是:%s,我的同桌是:%s' % (self.name, classmate))


stu = Student('Bob')
stu('Tom')
运行结果:
this is new
Bob
this is init
我的名字是:Bob,我的同桌是:Tom

6._call_()方法

对象后面加括号,触发执行。构造方法的执行时由创建对象触发的,即对象=类名()。

对于__call__方法的执行,是由对象后加括号触发的。即对象()或者类()。

demo:

class A(object):
    def __init__(self):
        pass

    def __call__(self, x):
        print('__call__ called,print x:',x)

a=A()
a('123')
运行结果:
__call__ called,print x: 123

7.__doc__方法

demo:

class Foo:
    '''这是一段说明'''
    pass

print(Foo.__doc__)
运行结果:
这是一段说明

8.个人心得总结

所有类默认的超类(父类)都是object。

当实例化一个类时,首先调用的是___new__。然后__new__会调用__init__函数。如果子类中没有重写___new__、__init__,子类会自动调用超类中的___new__、__init__。

执行对象()时,调用__call__()方法

print (对象)时,调用__str__方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值