今天在敲代码的时候碰到一个问题。关于import和from....import...的区别。
eg
import random
表示引入的是random模块或者说random.py文件,那么自然random里的类都可以使用。使用方式
random.randint(0, last_pos)
而from random import randint
表示将random中randint函数导入,在使用时直接使用即可。但如果要使用该py文件中的其他类或者函数就需要重新导入。
randint(0,last_pos)
总的来说,尽量还是使用import更好。
类和对象较为正式的说法:
"把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)和泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派。"
简单的说,类是对象的蓝图和模板,而对象是类的实例。这个解释虽然有点像用概念在解释概念,但是从这句话我们至少可以看出,类是抽象的概念,而对象是具体的东西。在面向对象编程的世界中,一切皆为对象,对象都有属性和行为,每个对象都是独一无二的,而且对象一定属于某个类(型)。当我们把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定义出一个叫做“类”的东西。
在pyhon中使用class来修饰类,在类中通过函数来定义方法,可以将对象的动态特征表现出来。
eg
class Student(object):
#__init__是一个特殊的方法用于在创建对象时进行初始化操作
#通过这个方法我们可以为学生对象绑定name和age两个属性
def __init__(self,name,age):
self.name=name
self.age=age
def study(self,course_name):
print("%s正在学习%s."%(self.name,course_name))
def watch_movie(self):
if self.age < 18:
print("%s只能观看熊出没" % self.name)
else:
print("%s观看美国大片" % self.name)
具体的实例化
eg
def main():
#创建学生对象并指定姓名和年龄
stu1 = Student('Aug',38)
#给对象发study消息
stu1.study("Python程序设计")
#给对象发watch消息
stu1.watch_movie()
方法和属性私有化
在Python中,属性和方法的访问权限只有两种,也就是公开的和私有的,如果希望属性是私有的,在给属性命名时可以用两个下划线作为开头。
eg
class Test:
def __init__(self,foo):
self.__foo =foo
def __bar(self):
print(self.__foo)
print('__bar')
def main():
test = Test('hello')
test.__bar()#当打印时会显示在test中没有这个方法。
print(test.__foo)#显示没有这个属性
但实际上python中并没有真正的私有,只是将其换了一个访问方式。
eg
def main():
"""
test = Test('hello')
test.__bar()
print(test.__foo)
:return:
"""
#找寻其真正的名字规则并打印
test=Test('hello')
test._Test__bar()
print(test._Test__foo)
可以将其打印。
封装:隐藏一切可以隐藏的实现细节,只向外界暴露(提供)简单的编程接口"。我们在类中定义的方法其实就是把数据和对数据的操作封装起来了,在我们创建了对象之后,只需要给对象发送一个消息(调用方法)就可以执行方法中的代码,也就是说我们只需要知道方法的名字和传入的参数(方法的外部视图),而不需要知道方法内部的实现细节(方法的内部视图)。
@property装饰器
在上面提到封装,但是python对于封装本身的设置仅仅为以_开头给人暗示,有没有像java那样的get,set那?
自然是有的。如果想通过getter和setter来获取属性,可以考虑使用@propetry包装器来包装getter和setter方法,使得对属性的访问既安全又方便。
eg
class Person(object):
def __init__(self, name, age):
self._name = name
self._age = age
# 访问器 - getter方法
@property
def name(self):
return self._name
# 访问器 - getter方法
@property
def age(self):
return self._age
# 修改器 - setter方法
@age.setter
def age(self, age):
self._age = age
def play(self):
if self._age <= 16:
print('%s正在玩飞行棋.' % self._name)
else:
print('%s正在玩斗地主.' % self._name)
def main():
person = Person('王大锤', 12)
person.play()
person.age = 22
person.play()
# person.name = '白元芳' # AttributeError: can't set attribute
if __name__ == '__main__':
main()
猛一看上去没有什么区别,但实际上我们仔细看会发现,对于属性age由于我们设置了@age.setter 所以可以直接对age进行修改。而属性name只设置了getter方法所以不能更改。
__slots__
Python是一门动态语言。通常,动态语言允许我们在程序运行时给对象绑定新的属性或方法,当然也可以对已经绑定的属性和方法进行解绑定。但是如果我们需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义__slots__变量来进行限定。需要注意的是__slots__的限定只对当前类的对象生效,对子类并不起任何作用。
实际上动态语言是可以在创建实例后,给实力邦上一个以前未曾定义的属性。
eg
class Student(object):
... pass
>>> s = Student()
>>> s.name = 'Michael' # 动态给实例绑定一个属性
>>> print s.name
当添加__slots__后:
class Person(object):
#限定Person对象只能绑定_name,_age和_gender属性
__slots__ = ('_name','_age','_gender')
def __init__(self,name,age):
self._name=name
self._age=age
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self,age):
self._age = age
def play(self):
if self._age <=16:
print('%s正在玩飞行棋.' % self._name)
else:
print('%s正在斗地主' % self._name)
def main():
person = Person('王大锤',22)
person.play()
person._gender ='男'
运行没有问题,因为已经在类中使用__slots__定义过了。但如下则会报错:
person = Person('王大锤',22)
person.play()
person._gender ='男'
person._is_gay=True
是因为在类中限定了可以动态添加的属性。其中并没有_is_gay所以错误。
静态方法和类方法
在上面的类中,我们定义的方法都是对象方法,所谓对象方法即,创建实例后将消息传送给对象,对象对其进行处理。然而有的时候我们需要在该实例一创建就执行一个方法。即无需调用,一个实例一旦创建就会执行该方法。此时我们便需要@staticmethod来修饰该方法。
eg
import math
class Triangle(object):
def __init__(self,a,b,c):
self._a=a
self._b=b
self._c=c
@staticmethod
def is_valid(a,b,c):
return a+b>c and a+c>b and b+c>a
def perimeter(self):
return self._a+self._b+self._c
def area(self):
half = self.perimeter()/2
return math.sqrt(half*(half-self._a)*(half-self._b)*(half-self._c))
def main():
a,b,c=3,4,5
#静态方法都是通过给类发消息来调用对用的函数的
if Triangle.is_valid(a,b,c):
t=Triangle(a,b,c)
print(t.perimeter())
#也可以通过给类发消息来调用对象方法但需要传入接收消息的对象作为参数
#print(Triangle.perimeter())
print(t.area())
else:
print('无法构成三角形')
if __name__ == "__main__":
main()
类方法
与静态方法相似,还可以定义类方法通过@classmethod,类方法的第一个参数约定名为cls,它代表的是当前类相关的信息的对象(类本身也是一个对象,有的地方也称之为类的元数据对象),在此不再举例。
类之间的关系
类之间大致分为三类关系
1,继承
2,关联
3,依赖
继承和多态
继承:让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写。提供继承信息的我们称之为父类,也叫超类或基类;得到继承信息的我们称之为子类,也叫派生类或衍生类。子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力。
对于python来说当一个类继承另一个类时,在括号内加上即可。
eg
class Student(Person):
student类继承了person类。而student创建的实例可以直接使用person里的方法。同时其子类也可以使用父类的属性。例如定义
eg
def __init__(self, name, age, grade):
super().__init__(name, age)
self._grade = grade
多态
子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态。
同时在python中并没有如同java中接口一样的抽象类,而我们有时会需要抽象类,此时我们要做的是将该类中放入抽象方法,这样这个类就无法实例化对象。
eg
from abc import ABCMeta, abstractmethod
class Pet(object, metaclass=ABCMeta):
"""宠物"""
def __init__(self, nickname):
self._nickname = nickname
@abstractmethod
def make_voice(self):
"""发出声音"""
pass
class Dog(Pet):
"""狗"""
def make_voice(self):
print('%s: 汪汪汪...' % self._nickname)
class Cat(Pet):
"""猫"""
def make_voice(self):
print('%s: 喵...喵...' % self._nickname)
def main():
pets = [Dog('旺财'), Cat('凯蒂'), Dog('大黄')]
for pet in pets:
pet.make_voice()
if __name__ == '__main__':
main()
上面的代码中,Dog和Cat两个子类分别对Pet类中的make_voice抽象方法进行了重写并给出了不同的实现版本,当我们在main函数中调用该方法时,这个方法就表现出了多态行为(同样的方法做了不同的事情)。
isinstance() 函数来判断一个对象是否是一个已知的类型。
eg
>>>a = 2
>>> isinstance (a,int)
True
>>> isinstance (a,str)
False

2089

被折叠的 条评论
为什么被折叠?



