Python探险--类的”多重规则“

日期:20170916


抒情(前言了啦)

噢噢!今天一下子差不多看完Python类的知识点,但是没怎么练习,很多都没记住,感觉好多啊。印证了一句话,看一百页书,不如写一行代码。

比Java的类难学。(虽然我是个Java小白,嘻嘻,但是学Java类时都是,略略略。。。)
原因可能是Python作为集合多种语言语义的上层语言,为配合不同语言的人的编程习惯,所以有很多种编程语法。例如:
1、实例可以直接在加变量(属性)。
2、若你想限制实例不能直接加属性可以用__slots__。
3、内部属性用双下划线__来定义。(虽然只是个骗局。为什么所骗局呢?以后有机会再写一篇博客讨论)
。。。

Python的理念是,能写一行的代码,绝不写十行。能写简单的,绝不写复杂的(类似,原话不知道)。
但是上面两句话并不相容,或许只存在超高级语言中。(很意味深长的一句话)

可以说,Python编程是习惯约束的。在Python中你完全可以按自己习惯来写代码。但是要想看懂别人的代码,或者想别人看懂你的代码,建议(必须)还是要学一下常用的语法。


最简单的类

现在先讲最简单的类定义。

代码

#!/usr/bin/python

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

        def print_info(self):
                print("Student")
                print("Name: %s"%(self.name))
                print("Age: %s"%(self.age))

Stu1=student("Penx", 13) 
Stu1.print_info()

运行

[penx@ali01 python2]$ ./simple_class.py 
Student
Name: Penx
Age: 13
[penx@ali01 python2]$

一个类的实例,至少要有属性,要有方法。就像现实中,所有东西都有属性,有行为。(非生物的行为,比如,鸡蛋和石头都可以被敲,鸡蛋容易被敲破,石头则很难被敲碎,被敲后的表现则是鸡蛋和石头的行为)

代码分析
1、第13行,是创建student类的实例Stu1,而student类是第3行以class开头定义的。第14行,是调用实例的方法。

2、第3行括号里是写student继承的类。如果没有想要继承的类,可以写object。object是最原始的类,是其他全部类的“始祖”。

3、第4行和第8行以def开始的是定义类方法。

4、_ _init_ _()是创建实例时,自动调用的方法。(__init__是以双下划线开头和以双划线结尾)

5、类方法的第一个参数,习惯用名字self。self是实例自己本身。


剖析,(都是我自己的测试)
1、定义类时,不继承任何类,即连object都不继承,括号里是空的。运行成功。(网上说python3定义类时,默认继承object类)

2、不写__init__()。运行成功。应该是调用了父类的__init__()。

3、定义类方法时,第一个参数不是名字self。运行成功。猜测,调用类方法时,第一个参数默认传入实例本身。

4、定义类方法时,没有参数。调用时,传入一个参数。运行失败
报错如下,

TypeError: print_info() takes exactly 1 argument (2 given)

证明了第3点的猜想是正确的。


实例可自增加属性(不建议用)

实例可以自己增加属性的。

代码,

#!/usr/bin/python

class student():
        def __init__(self, name, age):
                self.name=name
                self.age=age

        def print_info(self):
                print("Student")
                print("Name: %s"%(self.name))
                print("Age: %d"%(self.age))

Stu1=student("Penx", 13) 
Stu1.print_info()

Stu1.height=15 #实例可以在创建后自增加属性
print("Height: %d"%Stu1.height)

运行,

[penx@ali01 python2]$ ./add_new_attr.py 
Student
Name: Penx
Age: 13
Height: 15
[penx@ali01 python2]$ 

分析,
除了类定义时的实例属性name和age,我们还可以在创建属性时,增加新的属性height(第16行)。
但是我不建议在定义完一个类后,实例自己增加属性。你想想,你在用别人编写的类时,会增加属性吗?通常不会吧。

剖析,
1、可以知道,实例的属性是在__init__()创建的。


实例可自增加方法(不建议用)

这条和“实例可自增加属性”一样,不建议用的理由也一样。
(大家自行脑补)


使用__slots__限制实例属性(少用)

哇哇,在python2中貌似没有啊,不知道python3有没有用。
我看的是python3的教程,用的是python2。

算了,我不打算用它,就不纠结了。
前面也说过,python很多语法都是习惯约定的。我们在用实例时,应不轻易增加属性和方法。

所以,以后看别人代码,知道有这条规则就好。

注意:
1、slots定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。

2、除非在子类中也定义slots,子类实例允许定义的属性就是自身的slots加上父类的slots


实例属性可直接修改

这条很多类编程语言都可以,就是在创建实例后,直接修改实例属性。


实例数据封装

如果用上面那条,实例属性直接修改,那么属性值的修改就限制。

代码,

#!/usr/bin/python

class student():
        def __init__(self, name, age):
                self.name=name
                self.age=age
        def print_info(self):
                print("Student")
                print("Name: %s"%(self.name))
                print("Age: %s"%(self.age))

Stu1=student("Penx", 13) 
Stu1.name=2017
Stu1.age="Alice"
Stu1.print_info()

运行,

[penx@ali01 python2]$ ./example_wrong_attr.py 
Student
Name: 2017
Age: Alice
[penx@ali01 python2]$

代码中,类定义没有做任何限制,直接修改就很任意,name修改为数字,age修改为字符串。

所以,我们修改属性时,可以把属性的修改通过方法来封装,那么就可以在修改属性时,检查属性数据的合法性。


使用@property进行属性数据封装(Python2不可用)

使用常规的封装,在思维上不怎么人类。因为我们都喜欢直接修改属性,而不是用方法来修改。
那么有没有一种既可以直接修改属性,又可以检查属性的合法呢?
答案是,有,那就是使用@property

代码,

/usr/bin/python3 #python

class student():
        def __init__(self, name, age):
                self.name=name
                self.age=age

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

        @name.setter
        def name(self, value):
                if not isinstance(value, str):
                        raise ValueError("name must be a string!")

        def print_info(self):
                print("Student")
                print("Name: %s"%(self.name))
                print("Age: %s"%(self.age))

Stu1=student(23, 13)
Stu1.print_info()

在第8行开始,定义了方法name,然后我们在第7行用装饰器@property装饰了name,使name能返回一个值。@property还创建了另一个装饰器@name.setter。

13行的方法name是检查name修改时,传入的值是否合法,它被12行的@name.setter装饰,使name的“=”重载(赋值重载)。

利用以上两点,实例在创建后,就可以直接获取和传入实例的属性被检查。

注,
1、@property是把方法装饰成读取属性。

2、@xxx.setter是把方法装饰成修改属性。

3、装饰的方法名字一定要一样。(测试过,不一样的话,运行失败。)

4、可以只用@property,那样属性就变成只读属性。

剖析,
@property的内部使用了装饰器和类定制的知识。(待我过一段时间看官方文档时,再开另一篇博客详细实现@property)


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值