python类、super函数
#PYTHON语言及其应用学习笔记
1、创建简单的类
class Person():
#python中特殊的对象初始化方法__init__,一个特殊的函数名
#当你在类声明里定义__init__()方法时,第一个参数必须为self。
def __init__(self,name):
self.name=name
someone=Person('elmer fudd')
#上面一行代码实际做了如下工作:
1、查看Person类的定义
2、在内存中实例化(创建)一个新的对象
3、调用对象的__init__方法,将这个新创建的对象作为self传入,并将另一个参数
(‘elmer fudd’)作为name传入;
4、将name的值存入对象;
5、返回这个新的对象;
6、将名字hunter与这个对象关联。
2、类对象当做参数传递给函数,当做函数返回结果
#这个新对象与其他的python对象一样。你可以把它当做列表、元组、字典或集合中的元素,也可以把它当做参数传递给函数,或者把它作为函数的返回结果
class Person:
def __init__(self,name):
self.name=name
def run(self):
print(self.name + 'is running!')
hunter=Person('elmer fudd')
def hi(x):
print(x.name)
print(x.run())
hi(hunter) #elmer fudd elmer fuddis running! None
#在Person类定义的内部,你可以直接通过self.name访问name属性,而当你创建了一个实际的对象后,例如这里的hunter,需要通过hunter.name来访问它
#在类的定义中,__init__并不是必需的。只有当需要区分由该类创建的不同对象时,才需要指定__init__方法。
3、继承
在你编写代码解决实际问题时,经常能找到一些已有的类,它们能够实现你所需的大部分
功能,但不是全部。这时该怎么办?当然,你可以对这个已有的类进行修改,但这么做很
容易让代码变得更加复杂,一不留神就可能会破坏原来可以正常工作的功能。
当然,也可以另起炉灶重新编写一个类:复制粘贴原来的代码再融入自己的新代码。但这
意味着你需要维护更多的代码。 同时,新类和旧类中实现同样功能的代码被分隔在了不同
的地方(日后修改时需要改动多处)。
更好的解决方法是利用类的继承:从已有类中衍生出新的类, 添加或修改部分功能。这是
代码复用的一个绝佳的例子。 使用继承得到的新类会自动获得旧类中的所有方法,而不需
要进行任何复制。
你只需要在新类里面定义自己额外需要的方法, 或者按照需求对继承的方法进行修改即
可。修改得到的新方法会覆盖原有的方法。 我们习惯将原始的类称为父类、 超类或基类,
将新的类称作孩子类、 子类或衍生类。这些术语在面向对象的编程中不加以区分。
class Car:
def exclaim(self):
print('i am a car!')
class Yugo(Car):
pass
#为每一个类各创建一个对象,并调用刚刚声明的 exclaim 方法
give_me_a_car=Car()
give_me_a_yugo=Yugo()
give_me_a_car.exclaim() #i am a car!
give_me_a_yugo.exclaim() #i am a car!
#我们不需要进行任何特殊的操作,Yugo就自动从Car那里继承了exclaim()方法。但事
#实上,我们并不希望Yugo在exlaim()方法里宣称它是一个Car,这可能会造成身份危机
#(无法区分Car和Yugo)。让我们来看看怎么解决这个问题。
4、覆盖方法
在子类中,可以覆盖任何父类的方法,包括__init__()
class Car:
def exclaim(self):
print('i am a car!')
class Yugo(Car):
def exclaim(self):
print('i am a yugo! much like a car, but more yugo-ish')
#为每一个类各创建一个对象,并调用刚刚声明的 exclaim 方法
give_me_a_car=Car()
give_me_a_yugo=Yugo()
give_me_a_car.exclaim() #i am a car!
give_me_a_yugo.exclaim() #i am a yugo! much like a car, but more yugo-ish #在子类中,可以覆盖任何父类的方法,包括 __init__()。
#医生( MDPerson)和律师( JDPerson)
class Person():
def __init__(self,name):
self.name=name class MDPerson(Person):
def __init__(self,name):
self.name=',Doctor '+name class JDPerson(Person):
def __init__(self,name):
self.name=', '+name+' esquire'
person=Person('fudd')
doctor=MDPerson('fund')
lawyer=JDPerson('fund')
print(person.name,doctor.name,lawyer.name) #fudd ,Doctor fund , fund esquire
5、添加新方法
子类还可以添加父类中没有的方法。
class Car():
def exclaim(self):
print("I'm a Car!") class Yugo(Car):
def exclaim(self):
print("I'm a Yugo! Much like a Car, but more Yugo-ish.")
def need_a_push(self):
print("A little help here?")
6、使用super从父类得到帮助
我们知道如何在子类中覆盖父类的方法,但如果想要调用父类的方法怎么办? ##继承可以直接调用父类的方法,这里方法是初始化方法(__init__)。
“哈哈!终于等到你问这个了。” super() 站出来说道。下面的例子将定义一个新的类
EmailPerson,用于表示有电子邮箱的 Person。
class Person():
def __init__(self,name,age):
self.name=name
self.age=age
#下面是子类的定义,注意,子类的初始化方法__init__()中添加了一个额外的email参数:
class EmailPerson(Person):
def __init__(self,name,age,email):
super().__init__(name,age)
self.email=email
email=EmailPerson('yangqie',18,'qq.com')
print(email.name,email.email,email.age) #yangqie qq.com 18
在子类中定义__init__()方法时,父类的__init__()方法会被覆盖。因此,在子类中,
父类的初始化方法并不会被自动调用,我们必须显示地调用它。
只能全部调用或者全部不调用,上面例子要不就全部调用name、age,要不就都不调用。
以上代码实际上做了这样几件事情:
1、通过super()方法获取了父类Person的定义
2、子类的__init__()调用了Person.__init__()方法。它会自动将self参数传递给父类。
因此,你只需传入其余参数即可(除去self后的参数)。上面例子即name、age
3、self.email=email这行新的代码才真正起到了将EmailPerson与Person区别开的作用。
#为什么不像下面这样定义EmailPerson类呢?
class EmailPerson(Person):
def __init__(self,name,age,email):
self.name=name
self.age=age
self.email=email
确实可以这样做,但这有悖我们使用继承的初衷。我们应该使用super()来让Person完成它应该做的事情,
就像任何一个单纯的Person对象一样。此外,如果Person类的定义在未来发生改变,使用super()可以
保证这些改变会自动反映到EmailPerson类上,而不需手动修改。
子类可以按照自己的方式处理问题,但如果仍需要借助父类的帮助,使用super()是最佳选择。
super写法注意:
1、子类的初始化方法__init__()中需要添加父类中init实例特性property,如上例中:
def __init__(self,name,age,email) name age 均为父类中init实例特性
2、Python3与Python2写法不同
Python2:super(Person,self).__init__(name,age)
Python3:super().__init__(name,age)
3、有如下几个问题:子类继承父类,创建子类实例时,要输入父类中的实例特性参数。
问题1:如果子类没有init方法,父类有init方法,构建实例时要输入父类的实例特性参数吗?需要,子类继承了父类的init方法,需要输入!!!
如下面代码1,修改为child=Child('yq')即可。子类没有init方法时,继承父类init方法。
问题2:如果子类有和父类相同的实例特性参数,构建实例时需要输入两个实例特性参数吗?如下面代码2,不用输入两个,输入一个即可。
子类覆盖了父类的init方法,所以不需要输入!!
问题3:如果子类中有init方法,父类中有init方法,构建实例时需要输入子类和父类中的实例特性参数吗?如下面代码3,只用输入子类实例特性参数。
总结:在没有使用super情况下,子类有init,就用子类的,子类没有找父类,父类有,用父类的,父类没有,就不用管了。
问题4:在使用super情况下,子类和父类中有相同实例特性参数,输入多少个呢?相同的输入一个即可,如代码4
代码1
class Model:
def __init__(self,name):
self.name=name
class Child(Model):
def save(self):
print('ok')
child=Child()
#TypeError: __init__() missing 1 required positional argument: 'name'
代码2
class Model:
def __init__(self,name):
self.name=name
class Child(Model):
def __init__(self,name):
self.name=name
def save(self):
print('ok')
child=Child('yq') #ok
代码3
class Model:
def __init__(self,age):
self.age=age
class Child(Model):
def __init__(self,name):
self.name=name
def save(self):
print('ok')
child=Child('yq',20)
child.save() #__init__() takes 2 positional arguments but 3 were given
代码4
class Model:
def __init__(self,name,age):
self.name=name
self.age=age
class Child(Model):
def __init__(self,name,age):
super().__init__(name,age)
self.name=name
def save(self):
print('ok')
child=Child('yq',20)
child.save() #ok
下面再给出一个例子,用super调用父类方法,上面例子为__init__()方法,下面为super方法来调用父类中非__init__()方法
不过我们应该不会这样写,直接用子类覆盖掉父类方法即可,这样写感觉比较混乱。
class A:
def read(self,name2):
self.name2=name2
print('{} is read'.format(self.name2))
class B(A):
def read(self,name1,name2):
self.name1=name1
print(self.name1)
super().read(name2)
print('{} and {} read:python is very good!'.format(self.name1,self.name2))
a=B()
a.read('cmj','yq')
# cmj
# yq is read
# cmj and yq read:python is very good!
7、self的自辩
python中经常被争议一点就是必须把self设置为实例方法的第一个参数。python使用self参数来找到正确的对象所包含的特性和方法。
car=Car()
car.exclaim() #i am a Car!
python在背后做了以下两件事情:
1、查找car对象所属的类(Car);
2、把car对象作为self参数传给Car类所包含的exclaim()方法
8、使用属性对特性进行访问和设置 装饰器
# 修饰符( decorator)。下一个例子会定义两个不同的方法,它
# 们都叫 name(),但包含不同的修饰符:
# • @property,用于指示 getter 方法;
# • @name.setter,用于指示 setter 方法。
class Duck:
def __init__(self,input_name):
self.hidden_name=input_name
@property
def name(self):
print('inside the getter')
return self.hidden_name
#如果你没有指定某一特性的 setter 属性( @diameter.setter),
#那么将无法从类的外部对它的值进行设置。
@name.setter
def name(self,input_name):
print('inside the setter')
self.hidden_name=input_name
fowl=Duck('yang')
fowl.name='abc' #输出 inside the setter 调用了name.setter属性
print(fowl.name) #输出inside the getter abc
9、使用名称重整保护私有属性
怎么写怎么调用即可
10、方法的类型
有些属性和方法是类本身的一部分,还有一些是由类创建的实例的一部分。
在类的定义中,以self作为第一个参数的方法都是实例方法(instance method)。他们在创建自定义类时最常用。实例方法的首个参数是self,
当它被调用时,python会把调用该方法的对象作为self参数传入。
与之相对,类方法(classmethod)会作用于整个类,对类作出的任何改变会对它的所有实例对象产生影响。在类定义内部,用前缀修饰符
@classmethod指定的方法都是类方法。与实例方法类似,类方法的第一个参数都是类本身。在Python中,这个参数常被写作cls,因为全称
class是保留字,在这里无法使用。
类方法不能访问实例属性!!参数必须传入cls!!(即代表了此类对象与self代表实例对象区别),并且用此来调用类属性:cls.类属性名
静态方法不能访问实例属性!!参数不能传入self!!与类相关当事不依赖类与实例的方法!!
##静态方法与类方法都可以通过类火灾实例来调用,其两个特点都是不能调用实例属性。
类定义三种类型:类属性、类方法和静态方法
class A():
count=0
def __init__(self):
A.count+=1
def exclaim(self):
print("i'm an A!")
@classmethod
def kids(cls):
print('A has',cls.count,'little objects') #cls.count 等价于 A.count
#print('A has',A.count,'little objects')
@staticmethod
def hi():
print('hi,jim!')
easy_a=A()
print(A.kids()) #A has 1 little objects
breezy_a=A()
print(A.kids()) #A has 2 little objects
wheezy_a=A()
A.kids() #A has 3 little objects
A.hi() #hi,jim!
注意,上面的代码中,我们使用的是A.count(类属性,有别于实例属性self.count),在kids()
方法中,我们使用的是cls.count,它与A.count的作用一样
类定义中的静态方法(static method),用@staticmethod修饰,既不会影响类的对象,
出现只是为了方便
思考如下代码
class A:
a=10
def run():
print('a is running')
a=A()
a.run()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-60-c7e444286c71> in <module>()
4 print('a is running')
5 a=A()
----> 6 a.run() TypeError: run() takes 0 positional arguments but 1 was given
class A:
a=10
def run(self):
print('a is running')
a=A()
a.run() #a is running
class A:
a=10
@classmethod
def run(cls): #必须要cls参数,否则报TypeError: run() takes 0 positional arguments but 1 was given
print('a is running')
a=A()
a.run() #a is running
使用类方法来调用类属性
class A:
a='jim'
@classmethod
def run(cls):
b=a
print('{} is running'.format(b))
x=A()
print(x.run()) #<__main__.A object at 0x00000188456C6470> is running
class A:
a='jim'
@classmethod
def run(cls):
b=cls.a
print('{} is running'.format(b))
x=A()
print(x.run()) #jim is running
11、鸭子类型
当我们输入像 a = 3 + 8 这样的式子时,整数 3 和 8 是怎么知道如何实现 + 的?同样, a又是怎么知道如何使用 = 来获取计算结果的?你可以使用 Python 的特殊方法( special method),有时也被称作魔术方法( magic method),来实现这些操作符的功能。
这些特殊方法的名称以双下划线( __)开头和结束。没错,你已经见过其中一个: __init__,它根据类的定义以及传入的参数对新创建的对象进行初始化。假设你有一个简单的 Word 类,现在想要添加一个 equals() 方法来比较两个词是否一致,忽略大小写。也就是说,一个包含值 'ha' 的 Word 对象与包含 'HA' 的是相同的。
class Word():
def __init__(self,text):
self.text=text
def equals(self,word2):
return self.text.lower()==word2.text.lower()
first=Word('ha')
second=Word('HA')
third=Word('eh')
print(first==second) #False
print(first.equals(second)) #True
print(first.equals(third)) #False
class Word():
def __init__(self,text):
self.text=text
def __eq__(self,word2):
return self.text.lower()==word2.text.lower()
def __add__(self,word3):
return self.text+word3.text
def __mul__(self,word4):
return self.text*word4.text
first=Word('ha')
second=Word('HA')
third=Word('eh')
four=Word('yq')
five=Word(4)
if __name__=='__main__':
print(first==second) #True
print(first==third) #False
print(four+third) #yqeh
print(first*five) #hahahaha
# 太神奇了!是不是如同魔术一般?仅需将方法名改为 Python 里进行相等比较的特殊方法名
# __eq__() 即可。
12、组合
如果你想要创建的子类在大多数情况下的行为都和父类相似的话(子类是父类的一种特
殊情况,它们之间是 is-a 的关系),使用继承是非常不错的选择。建立复杂的继承关系确
实很吸引人, 但有些时候使用组合( composition) 或聚合( aggregation) 更加符合现实的
逻辑( x 含有 y,它们之间是 has-a 的关系)。
class Tail():
def __init__(self,length):
self.length=length
class Duck():
def __init__(self,bill,tail):
self.bill=bill
self.tail=tail
def about(self):
print('this duck has a',bill.description,'bill and a',
tail.length,'tail')
tail=Tail('long')
bill=Bill('wide orange')
duck=Duck(bill,tail)
duck.about() #this duck has a wide orange bill and a long tail
13、何时使用类和对象而不是模块
当你需要许多具有相似行为( 方法)但不同状态(特性)的实例时,使用对象是最好的选择。
类支持继承,但模块不支持。
用最简单的方式解决问题。 使用字典、列表和元组往往要比使用模块更加简单、简洁且
快速。而使用类则更为复杂。
python类、super函数的更多相关文章
- python之super()函数
python之super()函数 python的构造器奇特, 使用魔方. 构造器内对基类对象的初始化同样也很奇特, 奇特到没有半点优雅! 在构造器中使用super(class, instance)返回 ...
- 由Python的super()函数想到的
python-super *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !im ...
- Python中super函数的用法
之前看python文档的时候发现许多单继承类也用了super()来申明父类,那么这样做有何意义? 从python官网文档对于super的介绍来看,其作用为返回一个代理对象作为代表调用父类或亲类方法.( ...
- python 类成员函数
http://cowboy.1988.blog.163.com/blog/static/75105798201091141521583/ 这篇文章总结的非常好 主要注意的地方是 1,在类内调用成员函数 ...
- Python类call函数的作用
call函数可以把类变成函数来调用call方法 class Demo(): def __init__(self, name): self.name = name def __call__(self): ...
- python的super函数学习
一.为什么要用super? 在Python 2.2以前,通常的做法: class A: def __init__(self): print "enter A" print &quo ...
- Python关于super()函数的理解
看下面的例子: class A: def __init__(self, name): self.name = name def bb(self): print('没事就爱瞎BB') class B(A ...
- python 中 super函数的使用
转载地址:http://python.jobbole.com/86787/ 1.简单的使用 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我 ...
- 动态调用python类和函数
类 class test1(object): def __init__(self): print "i am test1" class test2(object): def __i ...
- python 类、函数的引用
类的引用 一.同级目录引用: from 文件名 import 类名 如果报错,原因基本上就是:pycharm不会将当前文件目录自动加入自己的sourse_path. 解决方法: ...
随机推荐
- android 桌面透明
目录(?)[-] public void setWallpaperOffsetSteps float xStep float yStep Parameters public void setWal ...
- wumii 爆款总结经验
在正式创办无秘之前,我们反思前几次创业失败的教训,深刻领悟两点: 第一,内容推荐的精准度取决于平台收集用户数据的能力,如果没有用户行为数据,产品无法做内容推荐,而通过简单的新闻排序,延长用户浏览单篇文 ...
- Unity ShaderLab 学习笔记(一)
因为项目的问题,有个效果在iOS上面无法实现出来- 因为shader用的HardSurface的,在android上面跑起来没有问题- 以为在iOS上也不会有问题,但是悲剧啊,技能效果一片漆黑- 而且 ...
- SQL注入的原理及分析
注入攻击的本质:将用户输入的数据当做代码执行. 有2个限制条件: 1.用户能够控制输入. 2.原本程序要执行的代码,拼接了用户输入的数据后进行执行. 定义:用户输入的数据被当做SQL语句执行. 以下面 ...
- lambda表达式-很好---《转载》
Lambda表达式详解 前言 1.天真热,程序员活着不易,星期天,也要顶着火辣辣的太阳,总结这些东西. 2.夸夸lambda吧:简化了匿名委托的使用,让你让代码更加简洁,优雅.据说它是微软自c#1.0 ...
- HiBench成长笔记——(9) Centos安装Maven
Maven的下载地址是:http://maven.apache.org/download.cgi 安装Maven非常简单,只需要将下载的压缩文件解压就可以了. cd /home/cf/app wget ...
- SelectList类的构造函数
SelectList类的构造函数 2016年05月23日 17:29:52 FrankyJson 阅读数 272 标签: MVC函数 更多 个人分类: MVC SelectList 构造函数 (I ...
- CSAPP读书笔记--第八章 异常控制流
第八章 异常控制流 2017-11-14 概述 控制转移序列叫做控制流.目前为止,我们学过两种改变控制流的方式: 1)跳转和分支: 2)调用和返回. 但是上面的方法只能控制程序本身,发生以下系统状态的 ...
- 《新标准C++程序设计》4.4(C++学习笔记14)
运算符重载为友元函数 一般情况下,将运算符重载为类的成员函数,是较好的选择. 但有时,重载为成员函数不能满足使用要求,重载为普通函数,又不能访问类的私有成员,所以需要将运算符重载为友元. class ...
- 删除C代码中的注释行【状态机】
今天在学ruby时遇到的一个经典的题目,一直都知道但从来没有实现过.呈上状态机,代码略.(写代码的时候还是需要注意一些小情况的)