python编程语言简明教程,翻译自以下仓库:
Python-Lectures
原仓库是一系列的jupyter notebook,可以直接在jupyter环境下运行程序示例。我添加了中文注释,并改为了兼容python3
类
变量、列表、字典等都是python中的对象;对象是类的实例,类是对象的模板。
例如:“大学”是一个类,“清华大学”是“大学”这个类的一个实例。
如下所示,定义一个新的类:
class class_name:
Functions
class FirstClass:
pass
pass 意思是说不做任何操作。
以上就是一个名为FirstClass的类,下面给这个类创建一个名为egclass的实例:
egclass = FirstClass()
type(egclass)
### type函数返回括号内对象的类型,可以看到,返回了FirstClass
__main__.FirstClass
现在我们来给这个FirstClass增添一些功能。类可以增添一些函数来丰富功能,这些函数被叫做这个类的“方法”。
大多数类都会定义一个叫 “__init__” 的函数。在这个起给实例初始化的作用的函数里,可以给类内部的变量初始化,给一些算法初始化,这些初始化的变量、算法可以被类内的其他方法使用。一个类内部的变量通常被成为一个类的“属性”。
例如,可以让FirstClass包含两个变量name和symbol:
关于以下的“self”稍后会解释。
class FirstClass:
def __init__(self,name,symbol):
self.name = name
self.symbol = symbol
现在我们增添了 __init__ 方法,本质上是一个接受变量的函数。我们可以通过传递函数的方式来创建一个类的实例:
eg1 = FirstClass('one',1)
eg2 = FirstClass('two',2)
print(eg1.name, eg1.symbol)
print(eg2.name, eg2.symbol)
one 1
two 2
dir( ) 函数用来查看一个类的所有方法:
dir(FirstClass)
### 以下除了已定义的init外,还有很多声明了一个类以后,自动内置的方法,这些方法来自在python中定义类时默认继承的基类(注:以下结果的返回基于python 3.5版本):
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__']
dir( ) 也可以返回一个实例的方法和属性
dir(eg1)
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'name',
'symbol']
注意类中属性的名称,在创建实例后访问时要对应得上:
class FirstClass:
def __init__(self,name,symbol):
self.n = name
self.s = symbol
把内部的属性名字现在改为了n和s,
eg1 = FirstClass('one',1)
eg2 = FirstClass('two',2)
print(eg1.name, eg1.symbol)
print(eg2.name, eg2.symbol)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-11-4ab7dec1c737> in <module>
----> 1 print(eg1.name, eg1.symbol)
2 print(eg2.name, eg2.symbol)
AttributeError: 'FirstClass' object has no attribute 'name'
返回了一个AttributeError, 因为实例中的属性名字叫n和s了,所以找不到name和symbol
dir(eg1)
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'n',
's']
print(eg1.n, eg1.s)
print(eg2.n, eg2.s)
one 1
two 2
现在之前的error就不再出现了。我们可以比较以上的例子:
当声明 self.name 和 self.symbol 时,用 eg1.name 和 eg1.symbol 获取属性的值就不会报错,当声明了 self.n 和 self.s时,用 eg1.n 和 eg1.s 就不会报错。
从以上例子可以看出,声明一个类时的“self”就是指的该类的实例自身。
注意,self不是事先定义好的,是需要写类的人自己定义的。也可以不用“self”这个词,但是使用self这个单词是一种约定俗成的习惯。
class FirstClass:
def __init__(asdf1234,name,symbol):
asdf1234.n = name
asdf1234.s = symbol
### 这里用asdf1234代替self的位置,功能一样
eg1 = FirstClass('one',1)
eg2 = FirstClass('two',2)
print(eg1.n, eg1.s)
print(eg2.n, eg2.s)
one 1
two 2
虽然eg1和eg2是FirstClass类的两个实例,但是eg1和eg2不一定要局限于FirstClass类具有的那些内容。他们可以直接声明一些FirstClass类里没有的其他属性,比如:
eg1.cube = 1
eg2.cube = 8
dir(eg1)
### 实例eg1直接增加了一个cube属性:
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'cube',
'n',
's']
和全局变量与局部变量类似,类的属性也有不同的种类。
类属性 : 在一个类中任何的方法之外定义的变量,任何一个该类的实例都可以访问这个变量的值。
实例属性 : 在一个类的方法中定义的变量,只能在该方法中使用,在不同的实例中值都是独有的。
class FirstClass:
test = 'test'
def __init__(self,name,symbol):
self.name = name
self.symbol = symbol
test就是一个类属性,name是实例属性。
eg3 = FirstClass('Three',3)
print(eg3.test, eg3.name)
### 在创建eg3时,没有对test属性做任何赋值等操作,但是也可以访问,但是name属性需要赋值才行
test Three
给FirstClass添加更多方法:
class FirstClass:
def __init__(self,name,symbol):
self.name = name
self.symbol = symbol
def square(self):
return self.symbol * self.symbol
def cube(self):
return self.symbol * self.symbol * self.symbol
def multiply(self, x):
return self.symbol * x
eg4 = FirstClass('Five',5)
print(eg4.square())
print(eg4.cube())
25
125
eg4.multiply(2)
10
以上的操作也可以写作:
FirstClass.multiply(eg4,2)
10
继承
有时候,一个新的类想要使用一个已经写好的类的特性,这个新的类可以通过“继承”这个已有类来实现这一目的。
例如以下的SoftwareEngineer类具有一个叫salary的方法:
class SoftwareEngineer:
def __init__(self,name,age):
self.name = name
self.age = age
def salary(self, value):
self.money = value
print(self.name,"earns",self.money)
a = SoftwareEngineer('Kartik',26)
a.salary(40000)
Kartik earns 40000
dir(SoftwareEngineer)
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'salary']
现在再写一个Artist类,包含money和artform两个方法:
class Artist:
def __init__(self,name,age):
self.name = name
self.age = age
def money(self,value):
self.money = value
print(self.name,"earns",self.money)
def artform(self, job):
self.job = job
print(self.name,"is a", self.job)
b = Artist('Nitin',20)
b.money(50000)
b.artform('Musician')
Nitin earns 50000
Nitin is a Musician
dir(Artist)
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'artform',
'money']
可以看出,salary这个函数和money这个函数其实执行的操作是完全一样的。因此我们可以通过让Artist类继承SoftwareEngineer类来让Artist也具有salary方法,这样就不用在Artist类中再写一遍了。
class Artist(SoftwareEngineer):
def artform(self, job):
self.job = job
print(self.name,"is a", self.job)
### 使用Artist(SoftwareEngineer)这种写法,就是让Artist继承了SoftwareEngineer类,不但继承了salary这个函数,也继承了init方法中的属性
c = Artist('Nishanth',21)
dir(Artist)
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'artform',
'salary']
c.salary(60000)
c.artform('Dancer')
Nishanth earns 60000
Nishanth is a Dancer
假如某个继承来的方法不适合新的类,也可以通过重写同名函数的方法来将该类方法覆盖。
class Artist(SoftwareEngineer):
def artform(self, job):
self.job = job
print(self.name,"is a", self.job)
def salary(self, value):
self.money = value
print(self.name,"earns",self.money)
print("I am overriding the SoftwareEngineer class's salary method")
### 在这里salary这个方法被重写了
c = Artist('Nishanth',21)
c.salary(60000)
c.artform('Dancer')
Nishanth earns 60000
I am overriding the SoftwareEngineer class’s salary method
Nishanth is a Dancer
如果不确定将调用多少次方法,则很难声明这么多变量来储存每次调用产生的不同的值。所以最好是声明一个列表,每次向列表中增加元素。
class emptylist:
def __init__(self):
self.data = [] ### 声明了一个空列表,后续不论多少次调用以下的one two three方法,都可以把结果放在这个列表里。
def one(self,x):
self.data.append(x)
def two(self, x ):
self.data.append(x**2)
def three(self, x):
self.data.append(x**3)
xc = emptylist()
xc.one(1)
print(xc.data)
[1]
因为写emptylist的时候,已经声明了data是一个列表,所以列表的各种操作也适用于data,例如可以直接追加数据:
xc.data.append(8)
print(xc.data)
[1, 8]
xc.two(3)
print(xc.data)
[1, 8, 9]
如果想让一个类可以处理不同数量的属性,可以像之前那样用星号变量的方式来处理:
class NotSure:
def __init__(self, *args):
self.data = ''.join(list(args))
yz = NotSure('I', 'Do' , 'Not', 'Know', 'What', 'To','Type')
yz.data
‘IDoNotKnowWhatToType’
(注:以下是作者写在最后的话,属于纯机翻,只是为了好玩)
从这往哪儿走
单独练习可以帮助您掌握python的窍门:给出自己的问题并加以解决。您也可以注册任何竞争性编码平台以获取竞赛编程题。您编写的代码越多,发现的内容就越多,您对这门语言的欣赏也就越多。
现在,您已经了解了python,可以在您感兴趣的领域尝试使用不同的python库。我强烈建议您查看这份精选的Python框架,库和软件列表http://awesome-python.com
python官方文档 : https://docs.python.org/2/
因为寿命短,所以解决问题,您需要python!
和平.
Rajath Kumar M.P ( rajathkumar dot exe at gmail dot com)