一、先理解cls和self
此部分原文:python中self和cls的区别_python self()当成一个函数-CSDN博客
假如你有个类MyClass,其中有个fun(arg1,arg2),以及一个实例obj,
当你应用中要通过实例类的方法,创建函数时必须加self参数,因为,当你调用方法obj.fun(arg1,arg2)的时候,会自动转成MyClass.fun(obj,arg1,arg2)
当你直接通过类调用方法时,可以不用sefl参数,如直接MyClass.fun(arg1,arg2),需加@staticmethod 修饰,否则会报错
若不想修饰,则建个module.py文件,不建类,则可直接如下方法使用:
import module
mudule.fun(arg1,arg2)
1、self表示一个具体的实例本身。如果用了staticmethod,那么就可以无视这个self,将这个方法当成一个普通的函数使用。
2、cls表示这个类本身。
>>> class A(object):
def foo1(self):
print "Hello",self
@staticmethod
def foo2():
print "hello"
@classmethod
def foo3(cls):
print "hello",cls
>>> a = A()
>>> a.foo1() #最常见的调用方式,但与下面的方式相同
Hello <__main__.A object at 0x9f6abec>
>>> A.foo1(a) #这里传入实例a,相当于普通方法的self
Hello <__main__.A object at 0x9f6abec>
>>> A.foo2() #这里,由于静态方法没有参数,故可以不传东西
hello
>>> A.foo3() #这里,由于是类方法,因此,它的第一个参数为类本身。
hello <class '__main__.A'>
>>> A #可以看到,直接输入A,与上面那种调用返回同样的信息。
<class '__main__.A'>
3、whats more,类先调用__new__方法,返回该类的实例对象,这个实例对象就是__init__方法的第一个参数self,即self是__new__的返回值。
二、再理解__new__和__init__
参考1:https://juejin.im/post/5add4446f265da0b8d4186af
参考2:https://zhuanlan.zhihu.com/p/21379984
__init__ 方法为初始化方法, __new__方法才是真正的构造函数
__new__方法用于创建对象并返回对象,当返回对象时会自动调用__init__方法进行初始化
调用过程,先__new__ 再 __init__
# coding:utf-8
class Foo(object):
'''黄哥python培训,黄哥所写'''
price = 50
def how_much_of_book(self, n):
print(self)
return self.price * n
foo = Foo()
print(foo.how_much_of_book(8))
print(dir(Foo))
分析上面的代码,这个类实例化过程,Foo类继承object类,继承了object的__new__方法。
当你没有重写这个方法(通俗来说,你没有在Foo类中没有定义__new__方法),Foo实例化是默认自动调用父类__new__方法,这个方法返回值为类的实例提供这个函数how_much_of_book,默认的第一个参数self。
本质上,__new__ 中可以实现 __init__ 中的所有逻辑,但反过来不行。__init__通常更关注业务逻辑的初始化。
单例模式的实现:
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls, *args, **kwargs)
#或 cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
s1 = Singleton()
s2 = Singleton()
print(s1)
print(s2)
上面的代码输出
<__main__.Singleton object at 0x7fdef58b1190>
<__main__.Singleton object at 0x7fdef58b1190>
可以看到s1和s2都指向同一个对象,实现了单例模式。
工厂模式的实现
class Fruit(object):
def __init__(self):
pass
def print_color(self):
pass
class Apple(Fruit):
def __init__(self):
pass
def print_color(self):
print("apple is in red")
class Orange(Fruit):
def __init__(self):
pass
def print_color(self):
print("orange is in orange")
class FruitFactory(object):
fruits = {"apple": Apple, "orange": Orange}
def __new__(cls, name):
if name in cls.fruits.keys():
return cls.fruits[name]()
else:
return Fruit()
fruit1 = FruitFactory("apple")
fruit2 = FruitFactory("orange")
fruit1.print_color()
fruit2.print_color()
上面的代码输出
apple is in red
orange is in orange
cls可以传参数的:
class PriceLog(object):
def __init__(self, timestamp, product_id, price):
self.timestamp = timestamp
self.product_id = product_id
self.price = price
def __repr__(self):
return '<PriceLog ({}, {}, {})>'.format(self.timestamp,self.product_id, self.price)
@classmethod
def parse(cls, text_log):
'''
Parse from a text log with the format
[<Timestamp>] - SALE - PRODUCT: <product id> - PRICE: $<price>
to a PriceLog object
'''
divide_it = text_log.split(' - ')
tmp_string, _, product_string, price_string = divide_it
timestamp = delorean.parse(tmp_string.strip('[]'))
product_id = int(product_string.split(':')[-1])
price = Decimal(price_string.split('$')[-1])
return cls(timestamp=timestamp, product_id=product_id,price=price)
So, the parsing can be done as follows:
>>> log = '[2018-05-05T12:58:59.998903] - SALE - PRODUCT: 897 - PRICE:
$17.99'
>>> PriceLog.parse(log)
<PriceLog (Delorean(datetime=datetime.datetime(2018, 5, 5, 12, 58, 59,
998903), timezone='UTC'), 897, 17.99)>