- 1.类与对象的定义
- 1.1 全都是对象
- 1.2 创建第一个完整的类
- 1.3 构造方法
- 2.私有属性和方法
- 2.1 定义私有属性
- 2.2 定义私有方法
- 3.继承
- 3.1 单继承
- 3.2 子类对父类方法的重写
- 3.3 多继承(继承下的多态)
- 4.静态方法
- 5.魔法方法和特殊属性
- 5.1 __dict__
- 5.2 __slots__
- 5.3 __str__()
- 5.4 __iter__()
- 5.5 __getitem__()
- 5.6 __getattr__()
- 6.可调用对象
- 7.补充Python内置类属性
1.类与对象的定义 1.1 全都是对象
- python完全支持面向对象的基本功能:如封装、继承、多态以及对基类的重写和覆盖
- python中一切内容都是对象,包括字符串、列表、元组、字典、集合、range对象等,函数也是对象、类也是对象
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Employee:
'所有员工的基类'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
"创建 Employee 类的第一个对象"
emp1 = Employee("Zara", 2000)
"创建 Employee 类的第二个对象"
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount
1.3 构造方法
Python中的构造函数时__init__(),一般来说时给类的属性设置初值或者对其它必要的初始化工作,在创建对象的时候会被自动执行。在__init__()方法中定义的属性是实例属性,可以记录这个对象的特别信息。在类的方法中可以通过对self属性的方式获得__init__()方法中初始的值。
class people(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def func(self):
print(f"{self.name}的性别是{self.gender}")
面向对象编程的一个特点就是数据封装,在people类的__init__方法中初始化的实例属性name和gender,可以在类的方法通过类的对象访问类的实例属性。
if __name__ == '__main__':
xiaoming = people("小明", "男")
xiaoming.func()
输出结果:小明的性别是男
也可以通过类的对象访问实例属性,类的实例属性可以被类的对象访问和修改
if __name__ == '__main__':
xiaoming = people("小明", "男")
xiaoming.name = "张三"
xiaoming.func()
结果:张三的性别是男2.私有属性和方法
在类的内部中可以定义属性和方法,在方法内封装复杂的业务逻辑,可以通过类的对象访问方法。但是类的属性可以在类的内部进行访问和修改,也可以通过类的对象进行访问和修改,这样会破坏类的封装性。
在java中我们可以设置javabean,用private修改属性的访问权限,给属性添加get和set方法。那么在python中我们要私用属性和方法改怎么做呢?我们可以在属性的名称前面加上两个下划线"__"。
2.1 定义私有属性python中定义类的属性时,如果属性的名称以两个下划线开头则是表示为私有属性。私有属性在类的外部不能访问,需要通过类调用对象的公有方法进行访问。子类可以继承父类的公有成员,但是不能继承私有成员。
class people(object):
def __init__(self, name, gender):
self.__name = name
self.__gender = gender
def func(self):
print(f"{self.__name}的性别是{self.__gender}")
if __name__ == '__main__':
xiaoming = people("小明", "男")
xiaoming.name = "张三"
xiaoming.func()
输出结果:小明的性别是男
我们发现不能再通过对象.属性方式修改类的成员变量,并且当我们打印print(xiaoming.__name) 发现程序报错:
2.2 定义私有方法AttributeError: ‘people’ object has no attribute ‘__name’
除了定义私有属性,还可以定义私有方法,在方法名前面加上两个下划线即可。那么我们如何访问私有方法呢,很简单,通过一个公有方法去调用私有方法即可。
class people(object):
def __init__(self, name, gender):
self.__name = name
self.__gender = gender
def __func(self):
print(f"{self.__name}的性别是{self.__gender}")
def info(self):
self.__func()
if __name__ == '__main__':
xiaoming = people("小明", "男")
xiaoming.info()
输出结果:小明的性别是男3.继承
在OOP(面向对象程序设计)中继承是为了代码复用和设计复用而设计的。设计一个新类时,如果可以继承一个已有的设计好的类进行二次开发,可以大幅度减少代码量。在继承关系中,已有的,设计好的类被称为父类或者基类,新设计的类被成为子类或者派生类,享有父类的属性和方法。在python中同时支持单继承和多继承(在java中只支持单继承,多继承要通过接口来实现)
3.1 单继承python中单继承语法:
class newclass(parentclass): pass
当子类继承父类时,在子类的构造函数中调用父类的构造函数有两种写法:
- 经典类的写法:父类._init_(self,kwargs1,kwargs2,…)
- 新式类的写法: super(子类,self)._init_(self,kwargs1,kwargs2,…)
本例编写两个类,一个people类,一个student,student继承people
class people(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def func(self):
print(f"{self.name}的性别是{self.gender}")
class student(people):
def __init__(self,name,gender,age):
super(student, self).__init__(name, gender)
self.age = age
def stu_fun(self):
print(f"{self.name}的性别是{self.gender},年龄是{self.age}")
if __name__ == '__main__':
stu = student("小明","男","18")
stu.stu_fun()
stu.func()
结果: 小明的性别是男,年龄是18 小明的性别是男3.2 子类对父类方法的重写
有时候,子类不想继承父类的方法,而是对父类的方法进行一定的修改,这个时候就要对父类方法进行重写。如果子类和父类方法有相同的方法名,输入参数和返回类型,那么新方法会覆盖旧方法。
如果在子类中要调用父类的方法,可以用super()方法名的方式进行调用。
class people(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def func(self):
print(f"{self.name}的性别是{self.gender}")
class student(people):
def __init__(self, name, gender, age):
super(student, self).__init__(name, gender)
self.age = age
def func(self):
super().func()
print(f"{self.name}的性别是{self.gender},年龄是{self.age}")
if __name__ == '__main__':
stu = student("小明", "男", "18")
stu.func()
结果: 小明的性别是男 小明的性别是男,年龄是18
本例中,student类继承了people类,在student类中重写了父类的方法func(),还在子类重写的方法中调用了父类的方法。
3.3 多继承(继承下的多态)什么叫做多态呢?
当子类和父类都有相同的方法时,子类的方法覆盖父类的方法,在代码运行的时候,总是会调用子类的方法,这就是多态。
python中多继承语法:
class newclass(parentclass1,parentclass2,...) pass
需要注意的是newclass后面的父类顺序,如果父类中有相同的方法名,而在子类中没有使用指定的父类名,则python解释器会从左向右按顺序进行搜索,如果方法在子类中没找到,则会从左向右查找父类中是否包含该方法。
class Man(object):
def __init__(self, name):
self.name = name
self.gender = "男"
def func(self):
print(f"{self.name}的性别是{self.gender}")
class Woman(object):
def __init__(self, name):
self.name = name
self.gender = "女"
def func(self):
print(f"{self.name}的性别是{self.gender}")
class Student(Man, Woman):
def __init__(self, name, age):
super(Student, self).__init__(name)
self.age = age
# def func(self):
# super().func()
# print(f"{self.name}的性别是{self.gender},年龄是{self.age}")
if __name__ == '__main__':
stu = Student("小明", "18")
stu.func()
结果:小明的性别是男4.静态方法
静态方法是类中的函数,不需要实例。静态方法主要放一些逻辑性代码,主要是一些逻辑属类,但是和类本身没有什么交互,即在静态方法中,不会涉及类中方法和属性的操作。静态方法定义的时候要用@staticmethod装饰器
静态方法可以通过类名访问,也可以通过实例访问
class OperateNum(object):
def __init__(self,num1,num2):
self.num1 = num1
self.num2 = num2
@staticmethod
def sum(a,b):
return a+b
def fun_sum(self):
res = OperateNum.sum(self.num1,self.num2)
print(res)
if __name__ == '__main__':
test = OperateNum(1,2)
test.fun_sum()
print(test.sum(1,2))
结果: 3 3
静态方法不需要创建对象就可以访问类中的方法。
5.魔法方法和特殊属性魔法方法也被称为特殊方法,总是被双下划线包围,如:_init_(),特殊属性也是以双下划线包围的属性,如:_dict_(),_slots_()。
5.1 _dict___dict__可以访问类的所有属性,以字典的方式返回
class Student(object):
def __init__(self, name, gender, age):
self.name = name
self.gender = gender
self.age = age
def func(self):
print(f"{self.name}的性别是{self.gender},年龄是{self.age}")
if __name__ == '__main__':
xiaoming = Student("小明", "男", 18)
print(xiaoming.__dict__)
print(xiaoming.__dict__['name'])
xiaoming.func()
结果:
{'name': '小明', 'gender': '男', 'age': 18}
小明
小明的性别是男,年龄是18
5.2 _slots_
Python中新类增加了__slots__内置属性,可以把实例属性锁定到__slots__规定的范围内。在python中,我们创建一个类的实例后,可以给这个实例绑定任何属性和方法,这就是动态语言的灵活性。
class Student(object): pass
给动态实例绑定一个属性
s = Student() s.name = 'zhangsan' print(s.name)
如果要限制实例的属性怎么办呢?例如只对Student实例添加name和age属性。限制实例的属性就要用到__slots__特殊属性,这个属性可以用元组定义允许绑定的属性名称。只有这个元组中出现的属性可以被类实例调用。
class Student(object):
__slots__ = ("name", "age", "gender")
def __init__(self, name, gender, age):
self.name = name
self.gender = gender
self.age = age
if __name__ == '__main__':
s = Student("张三", "18", "男")
print(f"{s.name},{s.age},{s.gender}")
s.score = 90
print(s.score)
结果: AttributeError: 'Student' object has no attribute 'score' 张三,男,18
报错的原因是:score没有在__slots__中,不能绑定score属性。值得注意的是:__slots__定义的属性仅能对当前的类实例起作用,对继承它的子类是不起作用的。
class People(object):
__slots__ = ("name", "age", "gender")
def __init__(self, name, gender, age):
self.name = name
self.gender = gender
self.age = age
class Student(People):
def __init__(self,name, gender, age):
super(Student, self).__init__(name, gender, age)
if __name__ == '__main__':
s = Student("张三", "18", "男")
print(f"{s.name},{s.age},{s.gender}")
s.score = 90
print(s.score)
运行结果: 张三,男,18 90
输出结果显示,子类的实例不受父类__slots__束缚
5.3 _str_()不知道大家再写程序是,打印一个实例化对象时,打印的其实时一个对象的地址。而通过__str__()函数就可以帮助我们打印对象中具体的属性值,或者你想得到的东西。
因为再python中调用print()打印实例化对象时会调用__str__()如果__str__()中有返回值,就会打印其中的返回值。
class ss:
def __init__(self,age,name):
self.age = age
self.name = name
def __str__(self):
return str(self.age)+",,wozenmezhemeshuai,,"+self.name
if __name__=="__main__":
s = ss(21,'aitebao')
print(s)
结果: 21,,wozenmezhemeshuai,,aitebao5.4 _iter_()
如果想要一个类用于for…in循环,类似元组或者列表,就必须实现__iter__()方法。该方法返回一个迭代对象,python中的for循环会不断调用该迭代对象的__next__()方法,获得循环的下一个值,下面以斐波那契数列为例,写一个可以作用与for循环的Fib类。
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > 100:
raise StopIteration
return self.a
for n in Fib():
print(n)
结果: 1 1 2 3 5 8 13 21 34 55 895.5 _getitem_()
Fib实例虽然可以作用于for循环,但是,不能将它作为列表来用,比如获取第四个元素。
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > 100:
raise StopIteration
return self.a
for n in Fib()[3]:
print(n)
发现报错: for n in Fib()[3]: TypeError: 'Fib' object is not subscriptable
如果要获取第四个元素,需要实现__getitem__()方法,代码如下:
class Fib(object):
def __getitem__(self, item):
a, b = 1, 1
for x in range(item):
a, b = b, a + b
return a
fib = Fib()
print(fib[3]) # 结果是: 3
5.6 _getattr_()
如果调用类的方法或者属性时,类的方法或者属性不存在,就会报错。要避免这个错误,可以使用__getattr_()方法动态的返回一个属性。
class Student(object):
def __init__(self, name):
self.name = name
def __getattr__(self, item):
if item == 'age':
return 18
stu = Student(name="xiaoming")
print(stu.age)
# 18
当调用不存在的属性age时,python解释器会调用__getattr__(self,‘age’)以尝试获取属性,这样就会返回age属性的值。
6.可调用对象在python中函数也是一个对象。实际上,任何一个有__call__()特殊方法的对象都是函数,示例如下:
class Add(object):
def __call__(self, *args):
return sum(*args)
add = Add() # 定义函数对象,可以把函数对象看作函数
print(add([1,2,3,4])) # 调用函数,结果为:10
所有的函数都是可调用函数。由于add可以调用,所以add被称为可调用对象。
一个实例也可以变成一个可调用对象,只需要实现__call__()方法,比如把People类变成一个可调用对象。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __call__(self, friend):
print(self.name, self.age)
print(friend)
if __name__ == '__main__':
p = Person("小明", 18)
p("张三")
结果: 小明 18 张三
仅仅看p(“张三”)无法确定Person是一个函数还是一个类实例,所以在python中,函数也是对象,对象和函数区别不显著,这也是python灵活的地方。
那么如何判断一个变量是函数还是对象呢?
很多时候判断一个对象能否被调用,可以使用callable()函数。
print(callable(p)) # True print(callable(["a"])) # False print(callable(max)) # True
由输出结果可以知道,通过callable()函数可以判断一个对象是否是可调用对象。
7.补充Python内置类属性#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Employee:
'所有员工的基类'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
print "Employee.__doc__:", Employee.__doc__
print "Employee.__name__:", Employee.__name__
print "Employee.__module__:", Employee.__module__
print "Employee.__bases__:", Employee.__bases__
print "Employee.__dict__:", Employee.__dict__
执行结果如下:
Employee.__doc__: 所有员工的基类
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount': , 'empCount': 0, 'displayEmployee': , '__doc__': 'xe6x89x80xe6x9cx89xe5x91x98xe5xb7xa5xe7x9ax84xe5x9fxbaxe7xb1xbb', '__init__': }



