|
|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 AKARocco 于 2018-5-14 00:14 编辑
#这个是基类.
class Restaurant():
def __init__(self,restaurant_name,cuisine_type,):
self.name = restaurant_name
self.type = cuisine_type
self.number_served = 0
def describe_restaurant(self):
print('The restaurant name is ' + self.name + " ")
print('It has ' + self.type + ' ')
print('现在一共有' + str(self.number_served) + '人')
def open_restaurant(self):
print('The restaurant is open!')
def set_number_served(self,people):
self.number_served = people
print('现在一共有' + str(self.number_served) + '人')
def incre_number_served(self,people):
self.number_served += people
print('现在一共有' + str(self.number_served) + '人')
my_restaurant = Restaurant('金拱门','快餐')
my_restaurant.open_restaurant()
my_restaurant.describe_restaurant()
my_restaurant.set_number_served(100)
my_restaurant.incre_number_served(20)
#这个是子类
class IceCreamStand(Restaurant):
def __init__ (self,restaurant_name,cuisine_type,*flavors):
super().__init__(restaurant_name,cuisine_type)
self.flavors = flavors
def show_icecream(self):
print(self.flavors)
eat_ic = IceCreamStand('香草','草莓','蓝莓')
eat_ic.show_icecream()
主要问题是继承和传递多个实参
想给*flavors传多个实参,但是下面的香草,蓝莓被上面的restaurant_name和cuisine_type顶掉了.
最后打出来只能显示蓝莓.
怎么搞啊
本帖最后由 ABC23 于 2018-5-14 10:32 编辑
class IceCreamStand(Restaurant):
def __init__ (self,restaurant_name,cuisine_type,*flavors):
super().__init__(restaurant_name,cuisine_type)
self.flavors = flavors
======================
既然在init函数中写了参数,就要用。这是基本的考虑——不然你为什么要传递呢?对吗。
如果不想传递父类的init相关的参数,可以在这之前先把相关参数固定好。
比如可以为父类参数指定默认值。
class Restaurant:
def __init__(self, restaurant_name,cuisine_type)
...
你担心的不就是父类的restaurant_name和cuisine_type参数嘛?首先,既然 IceCreamStand类继承了饭店类,就是它的子类。
其次,【子类不一定非要调用父类的init方法】。
请看下面的例子;
>>> class A:
def __init__(self, a):
self.a = a
>>> class B(A):
def __init__(self, b):
self.b = b
>>> class C(A):
def __init__(self, c):
super().__init__(1)
self.c = c
B、C都继承自A,其中C比较传统,调用了A的init方法进行初始化,而B却没有。
>>> b = B(1)
>>> b.__dict__
{'b': 1}
>>> c = C(1)
>>> c.__dict__
{'a': 1, 'c': 1}
看到了么?C类的实例对象拥有来自A类的【实例属性】a,但是B类的实例对象却没有。因为B类没有调用A类的init方法。
这就是代码语言的灵活。一点和包括Java等一些语言都不同,它们在构造方法中要传入父类的构造方法,还要写在子类construcor的第一行。
(这样说不严谨,实际上是调用了父类的__new__方法,隐式的传递了构造实例的基本“配置信息”,但是却没有传递别的【用户自定义参数】(如这里的xxname),Java做了简化在constructor中实际上做了new和init的工作)。
所以呢,回归主题。
你这里【既可以传递父类的属性,调用父类的init方法,也可以不这样做】。
>>> class A:
def __init__(self, a):
self.a = a
def fa(self):
print('function of a...')
>>> class B(A):
def __init__(self, b):
self.b = b
>>> class C(A):
def __init__(self, c, ap=1):
super().__init__(ap)
self.c = c
>>> b = B(1)
>>> c = C(1)
>>> dir(b)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'b', 'fa']
>>> dir(c)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'c', 'fa']
>>> b.fa()
function of a...
>>> c.fa()
function of a...
上面b对象没有调用父类的init方法,于是没有得到A的实例属性:a。对象c做了于是得到了。
不论是b、c,都得到了来自A()的fa()方法。
解释:Python的函数,包括在类中加载的方法是【一等公民】,和对应的模块、类处于同等地位(在加载的时候)。
【但是属性不同,我是说实例属性】。
==============================
最后总结,如果你不想在子类的init方法中传递父类参数,可以对指定子类传递默认父类参数(还是调用父类的init方法吧,免得到时候要用A()的实例属性):
方法一
def __init__(self, 子类参数):
super().__init(父类参数)
...
方法二
def __init__(self, 子类参数, 父类参数=默认值):
super().__init(父类参数)
...
还是建议使用方法二,灵活性更大。
>>> dis(B)
Disassembly of __init__:
3 0 LOAD_FAST 1 (b)
2 LOAD_FAST 0 (self)
4 STORE_ATTR 0 (b)
6 LOAD_CONST 0 (None)
8 RETURN_VALUE
>>> dis(C)
Disassembly of __init__:
3 0 LOAD_GLOBAL 0 (super)
2 CALL_FUNCTION 0
4 LOAD_ATTR 1 (__init__)
6 LOAD_FAST 2 (ap)
8 CALL_FUNCTION 1
10 POP_TOP
4 12 LOAD_FAST 1 (c)
14 LOAD_FAST 0 (self)
16 STORE_ATTR 2 (c)
18 LOAD_CONST 0 (None)
20 RETURN_VALUE
这是B、C的字节码。其中B压根就没有执行父类的初始化函数。
【Python的初始化函数不等于构造方法,在实例对象<font color=red>创建完成后</font>调用】。
|
|