整理自小甲鱼鱼C论坛
self 是什么
Python的self相当于C++的this指针。同一个类可以生成无数个对象,当一个对象的方法被调用时,对象会将自身的引用作为第一个参数传给该方法,python就知道需要操作哪个对象的方法了。以下代码为例,
class People:
def setName(self, name):
self.name = name
def intro(self):
print('My name is %s' % self.name)
A = People()
A.setName('A') # 这里将name = 'A'传入了实例对象的self.name属性
B.setName('B')
A.intro() # 这里'()'中为A的隐藏属性,即将A的name属性传入了self.name
B.intro()
构造方法
init()方法称为构造方法,init()只需要实例化一个对象,这个方法就会在对象被创建时自动调用(类似于C的构造函数)。实例化对象是可以传入参数的,这些参数会自动传入__init__()中,可以通过这个方法来自定义对象的初始化操作。
class People():
def __init__(self, name)
self.name = name
def intro(self):
print('I am %s' % self.name)
>>>A = People("A")
>>>A.intro()
I am A
Name Mangling
对象的属性方法可以通过’.’来进行访问。如下代码:
class People:
name = "A"
>>>A = People()
>>>A.name
'A'
这里A的name属性是共有的。下面讲一个利用Name Mangling来对实例属性私有化并进行隐藏的例子:
class People:
__name = "A"
>>>A = People()
>>>A.__name
AttributeError: 'People' object has no attribute '__name'
想要访问这个私有属性的方法有两种:
- 从内部调用该属性,例如通过定义一个函数来将这个属性从内部return出来
- 使用”_类名__变量名”的方法来访问私有化的属性
>>>A._People__name
'A'
问题1
class MyClass:
name = 'FishC'
def myFun(self):
print("Hello FishC!")
>>> MyClass.name
TypeErr: myFun() missing 1 required positional argument: 'self'
>>>
这里报错的原因,我们常说的类指的是类定义,当类定义完之后,自然就是类对象。在这个时候,你可以对类的属性(变量)进行直接访问(MyClass.name)。
一个类可以实例化出无数个实例对象,**Python为了区分是哪个实例对象调用了方法,于是要求必须绑定(通过self参数)才可以调用,而未实例化的类对象直接调用方法,因为缺少self参数,所以会报错。
这里有两种解决方案,第一种创建一个实例对象:
P = MyClass()
第二种方式为给类MyClass加入self参数:
MyClass.self.MyFun()
问题0 按照以下要求定义一个游乐园门票的类,并尝试计算2个成人和1个小孩的平日票价。
- 平日票价100元
- 周末票价为平日的120%
- 儿童半票
代码如下:
class Ticket():
def __init__(self, child = False, weekend = False):
self.price = 100
if weekend:
self.inc1 = 1.2
else:
self.inc1 = 1
if child:
self.inc2 = 0.5
else:
self.inc2 = 1
def calculatePrice(self, num): #注意类中函数必须要绑定self参数, 不然后面实力对象无法正确调用
return self.price*self.inc1*self.inc2*num
adult = Ticket()
child = Ticket(child = True)
print('2个成人与1一个小孩的票价为%.2f元' % (adult.calculatePrice(2)+child.calculatePrice(1)))
要按要求定义一个乌龟类和一个鱼类并尝试编写游戏。
- 假设游戏场景为范围(x, y)为0 <= x <= 10, 0 <= y <= 10
- 游戏生成1只乌龟和10条鱼
- 他们的移动方法均随机
- 乌龟的最大移动能力是2(可以随机选择移动1还是移动2),鱼的最大移动能力是1
- 当移动到场景边缘,自动向反方向移动
- 乌龟初始化体力为100
- 乌龟每移动一次,体力消耗1
- 当乌龟和鱼坐标重叠,乌龟吃掉鱼,乌龟体力增加20
- 鱼暂不计算体力
- 当乌龟体力为0或者鱼数量为0时,游戏结束
代码如下:
import random as r
legalX = [0, 10]
legalY = [0, 10]
class Turtle():
def __init__(self):
self.HP = 100
self.x = r.randint(legalX[0], legalX[1])
self.y = r.randint(legalY[0], legalY[1])
def move(self):
self.newX = self.x + r.choice([2, 1, 0, -1, -2])
self.newY = self.y + r.choice([2, 1, 0, -1, -2])
if self.newX > 10:
self.newX = legalX[1] - (self.newX - legalX[1])
elif self.newX < 0:
self.newX = legalX[0] + (legalX[0] - self.newX)
else:
self.x = self.newX
if self.newY > 10:
self.newY = legalY[1] - (self.newY - legalY[1])
elif self.newY < 0:
self.newY = legalY[0] + (legalY[0] - self.newY)
else:
self.y = self.newY
self.HP -= 1
return (self.x, self.y)
def eat(self):
self.HP += 20
if self.HP > 100:
self.HP = 100
class Fish():
def __init__(self):
self.x = r.randint(legalX[0], legalX[1])
self.y = r.randint(legalY[0], legalY[1])
def move(self):
self.newX = self.x + r.choice([1, 0, -1])
self.newY = self.y + r.choice([1, 0, -1])
if self.newX > 10:
self.newX = legalX[1] - (self.newX - legalX[1])
elif self.newX < 0:
self.newX = legalX[0] + (legalX[0] - self.newX)
else:
self.x = self.newX
if self.newY > 10:
self.newY = legalY[1] - (self.newY - legalY[1])
elif self.newY < 0:
self.newY = legalY[0] + (legalY[0] - self.newY)
else:
self.y = self.newY
return (self.x, self.y) #注意使用return来返回数值的方法
turtle = Turtle()
fish = []
for i in range(10):
new_fish = Fish()
fish.append(new_fish)
while True:
if not len(fish):
print('鱼被吃完了,游戏结束!')
break
if not turtle.HP:
print('乌龟累死了,游戏结束!')
break
pos = turtle.move() #这里的while可以反复调用实例对象turtle的move方法
#在迭代器中删除列表元素是非常危险的,经常会出现意想不到的效果,因为迭代器是直接饮用列表的数据进行引用的
#针对这一问题,我们通常把列表拷贝给迭代器,然后对原列表进行删除就不会有问题了。
#关于在迭代器中直接删除列表的具体风险。比如我在列表[0, 1, 2, 3]中,迭代器中直接删除了[0], 下次循环时i += 1, 但这个列表为[1, 2, 3],而i = 1, 指向的第二项, 会跳过[1]
for each in fish:
if new_fish.move() == pos:
turtle.eat()
fish.remove(each)
print('有条鱼被吃了!')