1、解释下什么是面向对象编程
class Person(object):
__slots__ = ('name', 'gender')
def __init__(self, name, gender):
self.name = name
self.gender = gender
class Student(Person):
__slots__ = ('score',)
def __init__(self, name, gender, score):
self.name = name
self.gender = gender
self.score = score
s = Student('Bob', 'male', 59)
s.name = 'Tim'
s.score = 99
print(s.score)
注:__slots__ = ('name', 'gender') 限定属性,不能动态添加属性
通过type()函数,可以获得变量的类型。
通过dir()方法,可以获取变量的所有属性:在dir列出的属性中,有很多是以下划线开头和结尾的,这些都是特殊的方法,称为内建方法,如果已知一个属性名称,要获取或者设置对象的属性,就需要用 getattr() 和 setattr( )函数了。
>>> getattr(p, 'name') # 获取name属性
'Alice'
>>> setattr(p, 'name', 'Adam') # 设置新的name属性
>>> s.name
'Adam'
函数isinstance()可以判断一个变量的类型。
>>> isinstance(s, Person)
True # s是Person类型
>>> isinstance(s, Student)
True # s是Student类型
>>> isinstance(s, Teacher)
False # s不是Teacher类型
对人类的抽象可以定义为Person类,而学生、老师等,也都是人类,所以,在Python当中,如果定义学生Student的类,可以继承Person类。
接着定义Student类,在定义Student类的时候,由于继承了Person类,所以Student类自动拥有name、gender属性,因此,在定义Student类的时候,只需要把额外的属性加上即可。
class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
student = Student('Alice', 'girl', 100)
print(student.name) # ==> Alice
print(student.gender) # ==> girl
print(student.score) # ==> 100
在定义继承类的时候,有几点是需要注意的:
1. class Student()定义的时候,需要在括号内写明继承的类Person
2. 在__init__()方法,需要调用super(Student, self).__init__(name, gender),来初始化从父类继承过来的属性
为了操作实例对象的私有属性,我们定义了实例方法;同样的,如果需要需要操作类的私有属性,则应该定义类的方法。
默认的,在class中定义的全部是实例方法,实例方法第一个参数 self 是实例本身。
要在class中定义类方法,需要这么写:
class Animal(object):
__localtion = 'Asia'
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def set_localtion(cls, localtion):
cls.__localtion = localtion
@classmethod
def get_localtion(cls):
return cls.__localtion
print(Animal.get_localtion()) # ==> Asia
Animal.set_localtion('Afica')
print(Animal.get_localtion()) # ==> Africa
和实例方法不同的是,这里有两点需要特别注意:
类方法需要使用@classmethod来标记为类方法,否则定义的还是实例方法
类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.__localtion 实际上相当于Animal.__localtion。
因为是在类上调用,而非实例上调用,因此类方法无法获得任何实例变量,只能获得类的引用。
总结:
实例方法def 方法(self,); 类方法def 方法(cls),且前面须加上@classmethod。
类方法只能访问类变量引用,不能访问实例内的变量。
把Animal类的age、name、localtion定义成私有属性,并定义对应的方法修改和获取他们的值。
class Animal(object):
def __init__(self, name, age, localtion):
self.__name = name
self.__age = age
self.__localtion = localtion
def set_name(self, name):
self.__name = name
def get_name(self):
return self.__name
def set_age(self, age):
self.__age = age
def get_age(self):
return self.__age
def set_localtion(self, localtion):
self.__localtion =localtion
def get_localtion(self):
return self.__localtion
p=Animal("ww","12","we")
print(p.get_name(),p.get_age(),p.get_localtion())
注:本例中如果去除def set_name(self, name):等,程序也能正常运行,待解。
def get_info(self):
return 'name = {}, age = {}, localtion = {}'.format(self.name, self.age, self.localtion)
这个语句可以同时取得多个属性
并不是所有的属性都可以被外部访问的,这种不能被外部访问的属性称为私有属性。私有属性是以双下划线'__'开头的属性。
# 类私有属性
class Animal(object):
__localtion = 'Asia'
print(Animal.__localtion)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Animal' has no attribute '__localtion'
# 实例私有属性
class Animal(object):
def __init__(self, name, age, localtion):
self.name = name
self.age = age
self.__localtion = localtion
dog = Animal('wangwang', 1, 'GuangDong')
print(dog.name) # ==> wangwang
print(dog.age) # ==> 1
print(dog.__localtion)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Animal' object has no attribute '__localtion'
# Enter a code
class Animal(object):
localtion = 'Asia'
def __init__(self, name, age, localtion):
self.name = name
self.age = age
self.localtion = localtion
dog = Animal('wangwang', 1, 'GuangDong')
print(dog.localtion)
print(Animal.localtion)
以上localtion为公共属性
class Animal(object):
__count = 0
def __init__(self, name):
Animal.__count = Animal.__count + 1
self.name = name
print(Animal.__count)
p1 = Animal('Cat')
p2 = Animal('Dog')
print(Animal.__count)
以上__count为私有属性,实例不能访问
class Animal(object):
count = 0
def __init__(self, name, age):
self.name = name
self.age = age
Animal.count += 1
dog = Animal('wangwang', 1)
print(Animal.count)
cat = Animal('mimi', 3)
print(Animal.count)
pig = Animal('panpan', 1)
print(Animal.count)
请给 Animal类添加一个类属性 count,每创建一个实例,count 属性就加 1,这样就可以统计出一共创建了多少个 Animal的实例。
在Python中,通过class关键字定义一个类,比如我们需要定义一个人的类。按照 Python 的编程习惯,类名以大写字母开头。因此可以这样定义:
class Person: pass
注意,在这个Person类的定义里面,并没有继承任何类,除了这样定义以外,还可以有以下两种定义方式。
class Person(): pass class Person(object): pass
这三种情况有什么区别呢?在Python3中,是没有区别的,但是在Python2中,则有一定的区别。
在Python2中,对于第一种定义的方法,Person类只有有限的几个内建函数'__doc__', '__module__', 'name',而对于第二种、第三种定义的方法,则会继承Python object对象的更多的内建函数,可以更便捷的操作对象。这是Python2版本的差异。在Python3中,我们只需要知道这三种方式都可以定义一个类即可。
请定义一个动物类,抽象出名字、年龄两个属性,并实例化两个实例dog, cat。
class Animal(object):
def __init__(self, name, age):
self.name = name
self.age = age
dog = Animal('wangwang', 1)
cat = Animal('mimi', 3)
print(dog.name)
print(dog.age)
print(cat.name)
print(cat.age)
需要注意的是,__init__() 方法的第一个参数必须是 self(也可以用别的名字,但建议使用习惯用法),后续参数则可以自由指定,和定义函数没有任何区别。
定义类后,就可以相应的实例化对象了,需要注意的是,在实例化的时候,需要提供除self以外的所有参数。
斐波那契数列
数学函数
有必要注意的是,返回函数和返回函数值的语句是非常类似的,返回函数时,不能带小括号,而返回函数值时,则需要带上小括号以调用函数。
# 返回函数
def myabs():
return abs
# 返回函数值
def myabs(x):
return abs(x)
math 就相当于一个工具箱,import math,相当于把工具箱搬到家中了,但是你工具箱不打开是用不了工具的。或者说家里还有别的工具箱,你要用工具的话,必须先找到对工具箱math,然后再用工具sin,所以用 math.sin().
sin()相当于一件具体的工具,from math import sin,相当于你直接从工具箱中拿出了工具,所以可以直接用。如:sin(100)
而 from math import * ,相当于把工具箱工具一股脑倒在了地上,你可以直接用,想用哪一个就用哪一个。
a=0
b=1
注意
a=b
b=a+b 与 a,b = b,a+b 两个句式的区别。
Python判断类型
随着我们学习步伐的前进,我们的程序会出现越来越多的类型,有我们自己定义的类,也有Python自有的str、list、dict等,他们的本质都是都是Python中的一种数据类型,这时有必要去判断数据的类型,通过函数isinstance()可以判断一个变量的类型。
class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender class Student(Person): def __init__(self, name, gender, score): super(Student, self).__init__(name, gender) self.score = score class Teacher(Person): def __init__(self, name, gender, course): super(Teacher, self).__init__(name, gender) self.course = course p = Person('Tim', 'Male') s = Student('Bob', 'Male', 88) t = Teacher('Alice', 'Female', 'English')
当我们拿到变量 p、s、t 时,可以使用 isinstance 判断类型:
>>> isinstance(p, Person) True # p是Person类型 >>> isinstance(p, Student) False # p不是Student类型 >>> isinstance(p, Teacher) False # p不是Teacher类型
这说明在继承链上,一个父类的实例不能是子类类型,因为子类比父类多了一些属性和方法。
我们再考察 s:
>>> isinstance(s, Person) True # s是Person类型 >>> isinstance(s, Student) True # s是Student类型 >>> isinstance(s, Teacher) False # s不是Teacher类型
s 是Student类型,不是Teacher类型,这很容易理解。但是,s 也是Person类型,因为Student继承自Person,虽然它比Person多了一些属性和方法,但是,把 s 看成Person的实例也是可以的。
这说明在一条继承链上,一个实例可以看成它本身的类型,也可以看成它父类的类型。
isinstance也可以用于Python自有数据类型的判断。
s = 'this is a string.' n = 10 isinstance(s, int) # ==> False isinstance(n, str) # ==> False
通过函数isinstance()可以判断一个变量的类型。
lass Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
student = Student('Alice', 'girl', 100)
print(student.name) # ==> Alice
print(student.gender) # ==> girl
print(student.score) # ==> 100
在定义继承类的时候,有几点是需要注意的:
class Student()定义的时候,需要在括号内写明继承的类Person
在__init__()方法,需要调用super(Student, self).__init__(name, gender),来初始化从父类继承过来的属性
Python定义类方法
在上一节课,为了操作实例对象的私有属性,我们定义了实例方法;同样的,如果需要需要操作类的私有属性,则应该定义类的方法。
默认的,在class中定义的全部是实例方法,实例方法第一个参数 self 是实例本身。
要在class中定义类方法,需要这么写:
class Animal(object): __localtion = 'Asia' def __init__(self, name, age): self.name = name self.age = age @classmethod def set_localtion(cls, localtion): cls.__localtion = localtion @classmethod def get_localtion(cls): return cls.__localtion print(Animal.get_localtion()) # ==> Asia Animal.set_localtion('Afica') print(Animal.get_localtion()) # ==> Africa
和实例方法不同的是,这里有两点需要特别注意:
类方法需要使用@classmethod来标记为类方法,否则定义的还是实例方法
类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.__localtion 实际上相当于Animal.__localtion。
Python定义实例方法
上一节课提到,私有属性没有办法从外部访问,只能在类的内部操作;那如果外部需要操作私有属性怎么办?这个时候可以通过定义类或者实例的方法来操作私有属性,本节课先来介绍实例方法。
实例的方法指的就是在类中定义的函数,实例方法的第一个参数永远都是self,self是一个引用,指向调用该方法的实例对象本身,除此以外,其他参数和普通函数是完全一样的。
class Person(object): def __init__(self, name): self.__name = name def get_name(self): return self.__name
在上面的定义,name是实例的私有属性,从外部是无法访问的,而get_name(self) 就是一个实例方法,在实例方法里面是可以操作私有属性的,注意,它的第一个参数是self。
另外,__init__(self, name)其实也可看做是一个特殊的实例方法。
通过定义get_name(self)方法,在外部就可以通过这个方法访问私有属性了。
p = Person('Alice') print(p.get_name()) # ==> Alice
注意,在外部调用实例方法时,是不需要显式传递self参数的。
在类属性和实例属性同时存在的情况下,实例属性的优先级是要高于类属性的,
__init__ 这里是双下划线
Python类的定义与实例化
class Person: pass
class Person(): pass
class Person(object): pass
定义了类之后,就可以对类进行实例化了,实例化是指,把抽象的类,赋予实物的过程。比如,定义好Person这个类后,就可以实例化多个Person出来了。
创建实例使用类名+(),类似函数调用的形式创建:
class Person(object): pass xiaohong = Person() xiaoming = Person()
class A(object):
def __init__(self, a):
print ('init A...')
self.a = a
class B(A):
def __init__(self, a):
super(B, self).__init__(a)
print ('init B...')
class C(A):
def __init__(self, a):
super(C, self).__init__(a)
print ('init C...')
class D(C, B):
def __init__(self, a):
super(D, self).__init__(a)
print ('init D...')
d=D('d')
结果(class D(C,B) ==> 先执行B再执行C):
init A...
init B...
init C...
init D...
在类属性和实例属性同名的情况下,实例属性的优先级是要高于类属性的,在操作实例的时候,优先是操作实例的属性。
import time
def performance(unit):
def perf_decorator(f):
def wrapper(*args, **kwargs):
t1 = time.time()
r = f(*args, **kwargs)
t2 = time.time()
t = (t2 - t1) * 1000
if unit == 'ms':
t = (t2 - t1) * 1000 * 1000
print('call {}() in {}{}'.format(f.__name__,t,unit))
return r
return wrapper
return perf_decorator
@performance('ms')
def factorial(n):
return reduce(lambda x,y:x + y,range(1, n+1))
factorial(10)
import time
def performance(f):
def fn(*args, **kw):
t1 = time.time()
r = f(*args, **kw)
t2 = time.time()
print('call %s() in %fs' %(f.__name__,(t2 - t1)))
return r
return fn
@performance
def ffa(n):
return reduce(lambda x,y: x + y, range(1,n+1))
print(ffa(10))
# Enter a code
import socket
server = socket.socket() # 1.新建 socket
server.bind(('127.0.0.1', 8999)) # 2.绑定IP和端口(其中127.0.0.1为本机回环IP)
server.listen(5) # 3.监听连接
s, addr = server.accept() #4. 接受连接
print('connect addr :{}'.format(addr))
content = s.recv(1024)
print(str(content, encoding = 'utf-8')) #接受来自客户端的消息,并编码打印出来\
s.close()
import socket
client = socket.socket() #1.新建socket
client.connect(('127.0.0.1', 8999)) #2.连接服务端(注意,IP和端口要和服务端一致)
client.send(bytes('hello world, hello socket', encoding = 'utf-8')) #发送内容,注意发送的是字节字符串
client.close()