1.类和对象
类的定义:具有相同的属性和方法的对象的集合。
对象的定义:在python中,万物皆对象。一个对象的特征也称为属性(attribute)。它所具有的行为也称为方法(method),所以:对象=属性+方法
比如:人类,动物,植物等,这都是一个类。而,某个人,你家的那只狗和门外的那棵树都是一个对象。
2.创建和使用类
创建Dog类,赋予dog蹲下sit()
和打滚roll_over()
的能力
class Dog():
def __init__(self,name,age):
self.name=name;
self.age=age;
def sit(self):
print(self.name.title()+" is now sitting.")
def roll_over(self):
print(self.name.title()+" rolled over!")
在Python中,创建一个类的语法为:
class 类名:
属性
方法
3.通过类实例化对象
一个类可以实例化出多个对象,这些对象都具有相同的属性。
class Dog():
def __init__(self,name,age):
self.name=name
self.age=age
def sit(self):
print(self.name+" is now sitting.")
def roll_over(self):
print(self.name+" rolled over!")
#一个类可以实例化出多个对象
dog1=Dog('Tom',2)
dog2=Dog('Jack',3)
#通过(对象.方法)调用该方法
dog1.sit()
dog2.roll_over()
以上实例输出结果为:
Tom is now sitting.
Jack rolled over!
4.普通字段和静态字段
类里可以有多个属性,也可以有多个方法。同时也有自己的字段。
这里的属性 官方语言叫做 类变量,属于这个类的公用部分,谁都可以来用,所以通常不作为实例变量使用,就是一个符号。而方法,则是在类中定义的函数,可以理解为类的行为部分。
class Province:
# 静态字段
country='中国'
def __init__(self, name):
# 普通字段 普通字段在每个对象中都要保存一份
self.name = name
# 直接访问普通字段
obj = Province('河北省')
print(obj.name)
# 直接访问静态字段 静态字段在内存中只保存一份
print(Province.country)
以上实例输出结果为:
河北省
中国
5.@classmethod和@staticmethod
一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。
而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。
@classmethod 表示下面的方法是类方法 将类本身作为对象进行操作的方法。不需要self参数,但第一个参数需要是表示自身类的cls参数。
@staticmethod 标明这是一个静态方法,不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
class Foo:
def __init__(self, name):
self.name = name
def ord_func(self):
""" 定义普通方法,至少有一个self参数 """
# print(self.name)
print('普通方法')
@classmethod #表示下面的方法是类方法 将类本身作为对象进行操作的方法
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """
print('类方法')
@staticmethod #标明这是一个静态方法
def static_func():
""" 定义静态方法 ,无默认参数"""
print('静态方法')
# 调用普通方法
f = Foo('tom')
f.ord_func()
# 调用类方法
Foo.class_func()
# 调用静态方法
Foo.static_func()
以上实例输出结果为:
普通方法
类方法
静态方法
6.python私有变量与封装
1、 _xx 以单下划线开头的表示的是protected类型的变量。即保护类型只能允许其本身与子类进行访问。若内部变量标示,如: 当使用“from M import”时,不会将以一个下划线开头的对象引入 。
2、 __xx 双下划线的表示的是私有类型的变量。只能允许这个类本身进行访问了,连子类也不可以用于命名一个类属性(类变量),调用时名字被改变(在类FooBar内部,__boo变成_FooBar__boo,如self._FooBar__boo)
3、 __ xx __定义的是特列方法。用户控制的命名空间内的变量或是属性,如__ init __ , __import__或是__file__ 。只有当文档有说明时使用,不要自己定义这类变量。 (就是说这些是python内部定义的变量名)
4、get/set方法:不写init()方法:
基本语法为:
set_name(self,new_name):
self.name=new_name
get_name(self):
return self.name
下面看段代码:
class Gs:
def set_name(self,name):
self.__name=name
def get_name(self):
return self.__name
def set_age(self,age):
if type(age)==int and age>0:
self.__age=age
else:
self.__age=None
print("年龄只能为纯数字且不能小于0")
def get_age(self):
return self.__age
def set_sex(self,sex):
if sex=="男" or sex=="女":
self.__sex=sex
else:
self.__sex="{您的性别输入有误}"
print("您只能输入男或女")
def get_sex(self):
return self.__sex
zhangsan=Gs()
zhangsan.set_age(20)
zhangsan.set_sex("nan")
zhangsan.set_name("张三")
print("姓名是{0},年龄为{1},性别是{2}".format(zhangsan.get_name(),zhangsan.get_age(),zhangsan.get_sex()))
以上代码运行结果为:
您只能输入男或女
姓名是张三,年龄为20,性别是{您的性别输入有误}
需要注意的是:
外部不能直接访问私有属性,比如:
class A(object):
def __init__(self):
self.__data=[] #翻译成 self._A__data=[]
def add(self,item):
self.__data.append(item) #翻译成 self._A__data.append(item)
def printData(self):
print(self.__data) #翻译成 self._A__data
a=A()
a.add('hello')
a.add('python')
a.printData()
#print(a.__data) #外界不能访问私有变量,此处执行会报错 AttributeError: 'A' object has no attribute '__data'
#如果想直接在外部调用私有属性如下
print a._A__data #通过这种方式,在外面也能够访问“私有”变量;这一点在调试中是比较有用的!
输出结果为:
['hello', 'python']
['hello', 'python']
7.python中面向对象之魔法方法(__init__,__str__方法,__del__方法,__new__方法)
魔法方法: 以两个_下划线开头 和以两个_下划线结尾的方法
魔法方法是python提供给我们的 由龟叔定义的好的方法 程序员直接使用即可
在特殊的情况下(不同的魔法方法 被调用的条件不同) 被python调用。
7.1__init__() 初始化对象
创建类时,可以定义一个特定的方法,名为init(),只要创建这个类的一个实例
就会运行这个方法。可以向__init__()方法传递参数,
这样创建对象时就可以把属性设置为你希望的值
__init__()这个方法会在创建对象时完成初始化。
class Peo:
def __init__(self,name,age,sex):
self.Name = name
self.Age = age
self.Sex = sex
def speak(self):
print "my name" + self.Name
#实例化这个类的对象时:
zhangsan=Peo("zhangsan",24,'man')
print(zhangsan.Age)
#输出结果为 24
print(zhangsan.Name)
#输出结果为 zhangsan
print(zhangsan.Sex)
#输出结果为 man
7.2__str__()方法
作用: 是追踪对象属性信息变量 一般用于程序员调试代码
特点: 有且只有一个形参 那就是self
他必须有返回值 返回值类型为字符串
什么时候被python调用: 在当前监听到程序员打印这个类创建的对象的时候.在我们没有实现str方法的时候 打印对象 会输出十六进制地址
print(zhangsan)
输出结果为:
<object at 0x00000247ED3B5080>
如果我们实现了str方法 打印对象 会输出str方法中的字符串
def __str__(self):
return "名字:%s 性别:%s 年龄:%d" %(zhangsan.Name,zhangsan.Sex,zhangsan.Age)
print(zhangsan)
此时输出结果为:
名字:zhangsan 性别:man 年龄:24
7.3__del__()方法
当程序的代码执行完成后 将要结束 那么会执行del huanghzong 杀死对象 系统释放内存
在当前对象的引用计数为0的时候才会执行
当有变量保存一个对象的引用,这个变量的引用计数就会+1
当用del()删除变量指向的对象时,会减少对象的引用计数。如果对象的引用计数不为1,那么会让这个对象的引用计数减1,当对象的引用计数为0的时候,则对象才会真正被删除(内存被回收)
def __del__(self):
print("再见!!!")
7.4__new__()方法
class Person(object):
#一个对象的生成是在new方法中完成的
def __new__(cls, *args, **kwargs):
print("__new__")
#委托父类帮我们创建一个对象 然后子类返回对象
return object.__new__(cls)
'''
构造方法(构造函数)
调用的时间: 当使用这个类创建一个对象成功 就会调用
作用: 给这个对象添加属性并赋值
'''
def __init__(self):
print("__init__")
self.name = "小明"
#追踪对象属性信息变化
def __str__(self):
return "名字:%s" % self.name
#监听对象销毁后执行del方法
def __del__(self):
print("再见")
xiaoming = Person()
print(xiaoming)
实例化对象的时候,调用__init__()初始化之前,先调用了__new__()方法
__new__()必须要有返回值,返回实例化出来的实例,需要注意的是,可以return父类__new__()出来的实例,也可以直接将object的__new__()出来的实例返回。
__init__()有一个参数self,该self参数就是__new__()返回的实例,__init__()在__new__()的基础上可以完成一些其它初始化的动作,__init__()不需要返回值。
若__new__()没有正确返回当前类cls的实例,那__init__()将不会被调用,即使是父类的实例也不行。
我们可以将类比作制造商,__new__()方法就是前期的原材料购买环节,__init__()方法就是在有原材料的基础上,加工,初始化商品环节。
实际应用过程中,我们可以这么使用:
class LxmlDocument(object_ref):
cache = weakref.WeakKeyDictionary()
__slots__ = ['__weakref__']
def __new__(cls, response, parser=etree.HTMLParser):
cache = cls.cache.setdefault(response, {})
if parser not in cache:
obj = object_ref.__new__(cls)
cache[parser] = _factory(response, parser)
return cache[parser]
该类中的new()方法的使用,就是再进行初始化之前,检查缓存中是否存在该对象,如果存在则将缓存存放对象直接返回,如果不存在,则将对象放至缓存中,供下次使用。
也可以实现单例模式:
class SingleDemo:
__sd=False
def __new__(cls):
if cls.__sd==False:
cls.__sd=object.__new__(cls)
return cls.__sd
a=SingleDemo()
b=SingleDemo()
print(a,b)
此时会发现输出结果对象a和b都指向了同一个地址。