在众多语言中,在定义函数时,有的参数类型能够随意传入,有的只能传入指定的类型。这种随意的语言的表明就是python,而规规矩矩的传入指定类型的参数的语言,就如java、c#、c++。下面就拿C++和python作个对比。java
如下代码是C++代码:python
liukai@bogon:~$ cat test1.cpp #include <iostream> using namespace std; int add(int x, int y) { return (x+y); } int main() { cout<<add(3,5); }
代码解析:C++这类语言的函数参数都要注明传入的类型,假如类型不对就会报错。
如下代码是python代码:ios
def func(arg): print(arg) func(123) func("hello") func([1,3,4]) func(dict)
执行结果以下:c++
123 hello [1, 3, 4] <class 'dict'>
代码解析:从上能够看到,python的函数参数能够是任意类型。这个就很随意了,不过也有一点弊端,就是当别人看你的代码的时候,会发现这个参数能够是任意类型,就会比较困惑这个参数究竟是作什么的。因此,有利必有弊嘛。
#静态字段 class Province: country = "中国" def __init__(self,name): # self.name = name pass def show(self): # print(self.name) print("经过类调用:",Province.country) print("类内部调用:",self.country) hlj = Province("黑龙江") hlj.show() print("对象调用:",hlj.country)
执行结果以下:c#
经过类调用: 中国
类内部调用: 中国
对象调用: 中国
class Province: country = "中国" def __init__(self,name): self.name = name self.size = 100000 pass def show(self): print("类内部调用:",self.size) hlj = Province("黑龙江") hlj.show() print("对象调用:",hlj.size)
执行结果以下:设计模式
类内部调用: 100000
对象调用: 100000
代码解析:普通字段属于对象,能够经过类内部访问:self.普通字段名;能够经过对象直接访问:对象名.普通字段名,可是不能经过类来访问,由于对象属于类,但类不属于对象。
##普通方法 class Province: def __init__(self,name): self.name = name def show(self): print(self.name) p = Province("黑龙江") p.show()
执行结果以下:app
黑龙江
代码解析:普通方法就是代码中的show()方法,要注意:第一个参数必须是self,self会把实例化出来的对象传入。上个例子,self就等于"p"这个对象。
##静态方法 class Province: def __init__(self,name): self.name = name def show(self): print(self.name) @staticmethod def main(args): print(args) p = Province("黑龙江") p.main(123) Province.main([1,3,4])
执行结果以下:函数
123
[1, 3, 4]
代码解析:静态方法就是上述代码的main(args),要想把普通方法变成静态方法,须要在方法上一行加上@staticmethod装饰器,在把普通方法的self参数去掉便可,后边能够加任意参数。静态方法能够类直接调用:类名.静态方法名;能够对象调用:对象名.静态方法名。
##类方法 class Province: def __init__(self,name): self.name = name def show(self): print(self.name) @staticmethod def main(args): print(args) @classmethod def clsmain(cls,args): print("class method") print(cls) print(args) p = Province("lk") Province.clsmain("123")
执行结果以下:工具
class method <class '__main__.Province'> 123
代码解析:类方法属于类,类方法的定义格式,在普通方法的上边加上@classmethod装饰器,而且方法的第一个参数self去掉,换成cls。这个cls默认就是类名,和普通方法的self相似。调用类方法,能够用类直接调用:类名.类方法名;能够经过对象调用:对象名.类方法名。
#属性 class Pager: def __init__(self,count): self.count = count @property def main(self): a1, a2 = divmod(self.count,10) if a2 == 0: return a1 else: return a1 + 1 p = Pager(158) result = p.main print(result)
执行结果以下:spa
16
代码解析:属性的定义格式是:在方法名上一行加上@property的装饰器。而后在调用的时候,直接类名/对象名.属性名。
class Pager: def __init__(self,count): self.count = count @property def main(self): a1, a2 = divmod(self.count,10) if a2 == 0: return a1 else: return a1 + 1 @main.setter def main(self,value): print("赋值时调用的方法:",value) @main.deleter def main(self): print("del 时调用的方法") p = Pager(191) ret = p.main print(ret) p.main = 200 del p.main
执行结果以下:
20 赋值时调用的方法: 200 del 时调用的方法
代码解析:在方法上一行加上@方法名.setter 的装饰器,会添加用途:当调用方式为:对象名.方法名 = value 时才会调用该方法。 在方法上加上@方法名.deleter 的装饰器,会添加用途:当调用方式为: del 对象名.方法名 时,才会调用改方法。 也能够这样定义这些特殊的属性:方法名 = property(fget=f1,fset=f2,fdel=f3),fget、fset、fdel参数都是固定的,f一、f二、f3是方法名。效果和加装饰器相似。代码以下:
class Pager: def __init__(self,num): self.num = num def f1(self): return 123 def f2(self,value): print(value) def f3(self): print(789) foo = property(fget=f1,fset=f2,fdel=f3) p = Pager(100) ret = p.foo print(ret) p.foo = "fuck" del p.foo
执行结果以下:
123
fuck
789
公有的成员包括:公有字段、公有方法、公有属性。这些成员就是以前介绍过的
定义一个私有字段的格式为: __xx = oo
##私有字段 class Pager: __cc = 123 def __init__(self,value): self.__value = value def f1(self): print("类内对象调用私有静态字段:",self.__cc) print("类内对象调用私有普通字段:",self.__value) def f2(self): print("类内利用类直接调用私有静态字段:",Pager.__cc) p = Pager("fuck") # p.__value ##error p.f1() # Pager.__cc ##error p.f2()
执行结果以下:
类内对象调用私有静态字段: 123
类内对象调用私有普通字段: fuck
类内利用类直接调用私有静态字段: 123
代码解析:私有字段,只能在类内部调用,不能够类、对象直接在外部调用。固然也有例外,python能够强行调用私有字段,不过不推荐!!!
##私有字段 class Pager: __cc = 123 def __init__(self,value): self.__value = value def f1(self): print("类内对象调用私有静态字段:",self.__cc) print("类内对象调用私有普通字段:",self.__value) def f2(self): print("类内利用类直接调用私有静态字段:",Pager.__cc) p = Pager("fuck") print(p._Pager__value) ##不推荐 print(Pager._Pager__cc) ##不推荐
这样也能够强行调用私有字段。不过不推荐!!!
###私有方法 class Pager2: def __init__(self,value): self.value = value def __f1(self): print(123) @staticmethod def __f2(): print(456) @classmethod def __f3(cls): print(789) def f4(self): self.__f1() def f5(self): Pager2.__f2() def f6(self): Pager2.__f3() p = Pager2("fuck") p.f4() p.f5() p.f6()
执行结果以下:
123 456 789
代码解析:私有方法的定义格式:在类内部,在普通方法的前边加上双下划线:__ ;私有方法只能在类内部调用,在这里只能由对象调用类内部方法来使用。
### __init__ class Foo: def __init__(self,name,age): self.name = name self.age = age def show(self): print(self.name,self.age) f = Foo("lk",25) f.show()
执行结果以下:
lk 25
代码解析:类的__init__方法的做用是初始化数据,叫作构造方法,方便其余类内部方法使用。
__del__叫作析构方法,当对象被回收时自动执行的方法。
__doc__方法的做用是打印类内部的注释
### __doc__ class Foo: """ 我是注释!!!! """ def __init__(self,name,age): self.name = name self.age = age def show(self): print(self.name,self.age) f = Foo("lk",25) print(f.__doc__)
执行结果以下:
我是注释!!!!
### __call__ class Foo: def __init__(self,name,age): self.name = name self.age = age def show(self): print(self.name,self.age) def __call__(self, *args, **kwargs): print("我是__call__方法") f = Foo("lk",25) f()
执行结果以下:
我是__call__方法
代码解析:f 是 Foo 的一个对象,在对象f 后边加上小括号,就会执行类内部的__call__方法。这个比较坑,很容易被忽略。
## __str__ class Foo: def __init__(self,name,age): self.name = name self.age = age def show(self): print(self.name,self.age) def __str__(self): return self.name f = Foo("lk",25) print(f)
执行结果以下:
lk
代码解析:f 是 Foo类的一个对象,当直接print(f) 的时候,就会调用类内部的__str__方法。
__dict__方法也很是实用,它能够看到构造方法中的全部字段,包括私有字段!
## __dict__ class Foo: def __init__(self,name,age,salary): self.name = name self.age = age self.__salary = salary def show(self): print(self.name,self.age) f = Foo("lk",25,3000) print(f.__dict__)
执行结果以下:
{'name': 'lk', 'age': 25, '_Foo__salary': 3000}
代码解析:在构造方法中构造了三个字段,执行__dict__,能够以字典的形式打印出全部字段。
# __item__ class Foo: ##必须是个迭代器才能循环,当循环一个对象时,就会执行__iter__方法. def __iter__(self): yield 2 yield 3 f = Foo() for i in f: print(i)
执行结果以下:
2 3
代码解析:要循环一个对象,必须类内部有一个__iter__方法,且它必须是一个迭代器。才能循环。
## __getitem__ __setitem__ __delitem__ class Foo: def __init__(self,name,age): self.name = name self.age = age def __getitem__(self, item): # return self.age print("==get_item==") print(item) print(type(item)) print(item.start,item.stop,item.step) def __setitem__(self, key, value): print("==set_item==") print(type(key),type(value)) print(key.start,key.stop,key.step) def __delitem__(self, key): print("==del_item==") print(type(key))
执行结果以下:
==get_item== slice(1, 4, 2) <class 'slice'> 1 4 2 ==set_item== <class 'slice'> <class 'list'> 1 4 2 ==del_item== <class 'slice'>
代码解析:__getitem__方法:当执行对象[] 的时候,会执行类中的__getitem__方法,[]中的内容能够是字符串、数字(这时就没有item.start、stop、step了),能够是列表分片的形式。当传入字符串、数字就是相应类型。当传入列表分片的形式时,它是一个slice类型。 __setitem__方法:当执行对象[] = xxx 的时候,会执行类内部的__setitem__方法,这个方法有两个参数,一个key,一个value。和__getitem__方法同样,传入的参数能够是字符串、数字、列表分片,列表分片的参数才有start、stop、step的功能。 __delitem__方法:当执行 del 对象[] 的时候,会执行类内部的__delitem__方法,这个方法有一个参数,参数类型和上边两个同样的。
#super class Foo(): def f1(self): print("Foo.f1") class Bar(Foo): def f1(self): super(Bar,self).f1() print("Bar.f1") b = Bar() b.f1()
执行结果以下:
Foo.f1
Bar.f1
代码解析:super方法用在类继承中,格式为super(子类,self).父类的方法()。它的做用是能够在不修改父类的状况下,添加本身的功能。下面是个有序字典的例子。
##有序字典,利用super class Mydict(dict): def __init__(self): self.li = [] super(Mydict,self).__init__() def __setitem__(self, key, value): self.li.append(key) super(Mydict,self).__setitem__(key,value) def __str__(self): temp_list = [] for i in self.li: value = self.get(i) temp_list.append("'%s':%s" % (i,value)) temp_str = "{" + ",".join(temp_list) + "}" return temp_str obj = Mydict() obj["name"] = "lk" obj["age"] = 23 obj["salary"] = 3000 print(obj) print(type(obj)) print(isinstance(obj,dict))
执行结果以下:
{'name':lk,'age':23,'salary':3000} <class '__main__.Mydict'> True
代码解析:定义一个本身的新字典类型Mydict类,继承字典类;首先要在字典中传值,调用__init__方法,这个要用到字典类的__init__方法,因此要在Mydict类的__init__方法中写入super(Mydict,self).__init__(),而咱们想要个有序字典,就是要把传入的key,存到一个列表中,最后循环列表把相应的value从字典中取到就能够了。因此新建个空列表要在子类中的__init__方法中执行。而后,传值的过程当中,执行了对象[] = xxx的形式,这就会调用类内部的__setitem__方法,这个方法也要在子类中定义,不过依然要执行父类字典类的方法,因此要写上super(Mydict,self).__setitem__(key,value),不过在这里,咱们能够把每一个key加入到空列表中去。最后在打印的时候,形式为print(对象),这个形式就会调用类内部的__str__方法,在子类的__str__方法里,就能够根据key,利用字典的get方法,循环打印相应的value值。能够看到,输出的结果是Mydict类,也就是dict的子类。这个结果也能够进行任何字典的操做。
概念:单例模式是一种经常使用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。经过单例模式能够保证系统中一个类只有一个实例。 简介:单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的惟一实例。要实现这一点,能够从客户端对其进行实例化开始。所以须要用一种只容许生成对象类的惟一实例的机制,“阻止”全部想要生成对象的访问。使用工厂方法来限制实例化过程。这个方法应该是静态方法(类方法),由于让类的实例去生成另外一个惟一实例毫无心义。 动机:对于系统中的某些类来讲,只有一个实例很重要,例如,一个系统中能够存在多个打印任务,可是只能有一个正在工做的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。若是不使用机制对窗口对象进行惟一化,将弹出多个窗口,若是这些窗口显示的内容彻底一致,则是重复对象,浪费内存资源;若是这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪个才是真实的状态。所以有时确保系统中某个对象的惟一性即一个类只能有一个实例很是重要。
#设计模式之单例模式 class Foo(): instance = None def __init__(self,name): self.name = name @classmethod def get_instance(cls,name): if cls.instance: return cls.instance else: obj = cls(name) cls.instance = obj return obj obj1 = Foo.get_instance("lk") obj2 = Foo.get_instance("lk") print(obj1,obj2)
执行结果以下:
<__main__.Foo object at 0x107704e48> <__main__.Foo object at 0x107704e48>
代码解析:第一次执行obj1 = Foo.get_instance("lk")的时候,会调用类方法get_instance,经过判断静态字段instance = None,会生成一个对象:obj = cls(name),把这个对象给静态字段instance,返回这个对象。此时建立成功对象obj1。 第二次执行obj2 = Foo.get_instance("lk")的时候,由于静态字段非空,表明以前建立过对象,因此直接返回第一次建立的对象。 再次输出的时候,能够看到两次对象的内存地址是相同的,这就是单例模式的在Python中的简单实现。