Day07 - 面向对象进阶

Day07的课程要点记录
详细教程地址:Day7 - 面向对象编程进阶

一、静态方法、类方法、属性方法

1.1 静态方法 @staticmethod

通过@staticmethod装饰器,可把其装饰的方法变为一个静态方法。
静态方法是不可以访问实例变量或类变量的。
一个不能访问实例变量和类变量的方法,跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法。
只是名义上归类管理,但上在静态方法里访问不了类或实例中的任何属性。

class Dog(object):
    def __init__(self, name):
        self.name = name
 
    @staticmethod
    def eat(self):
        print("%s is eating" % (self.name))

d = Dog("Wangcai")
d.eat()

以上调用会出错,提示eat需要一个self参数,但调用时却没有传递。
没错,当eat变成静态方法后,实例调用时就不再把实例本身当作一个参数传给self了。

TypeError: eat() missing 1 required positional argument: 'self'

想让上面的代码可以正常工作有两种办法

  1. 调用时主动传递实例本身给eat方法,即d.eat(d)
  2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了
class Cat(object):
    def __init__(self, name):
        self.name = name
 
    @staticmethod
    def eat():
        print("%s is eating %s" % ("Kitty", "fish"))

    @staticmethod
    def talk(self):
        print("%s is talking" % self.name)
 
c = Cat("Meo")
c.eat()
c.talk(c)

1.2 类方法 @classmethod

类方法通过@classmethod装饰器实现,类方法和普通方法的区别是:
类方法只能访问类变量,不能访问实例变量

class Dog(object):
    def __init__(self, name):
        self.name = name

    @classmethod
    def eat(self):
        print("%s is eating %s" % (self.name, "food"))

d = Dog("Doggy")
d.eat()

执行后报错,说Dog没有name属性,因为name是个实例变量,类方法是不能访问实例变量的

AttributeError: type object 'Dog' has no attribute 'name'

此时可以定义一个类变量,也叫name。

class Dog(object):
    name = 'Wangwang'

    def __init__(self, name):
        self.name = name

    @classmethod
    def eat(self):
        print("%s is eating %s" % (self.name, "food"))

d = Dog("Doggy")
d.eat()

# 执行效果
Wangwang is eating food

1.3 属性方法 @property

属性方法:通过@property把一个方法变成一个静态属性

class Dog(object):
    def __init__(self, name):
        self.name = name

    @property
    def eat(self):
        print("%s is eating %s" % (self.name, "food"))

d = Dog("Doggy")
d.eat()

调用会出以下错误, 说NoneType is not callable。

TypeError: 'NoneType' object is not callable

因为eat此时已经变成一个静态属性了,不是方法了,想调用已经不需要加()号了,直接d.eat就可以了

class Dog(object):
    def __init__(self, name):
        self.name = name
 
    @property
    def eat(self):
        print("%s is eating %s" % (self.name, "food"))
 
d = Dog("Doggy")
d.eat

# 输出
Doggy is eating food
class Dog(object):
    def __init__(self, name):
        self.name = name
        self.__food = None  # 设置私有属性 food 为 None
 
    @property  # 设置属性方法,将方法变为静态属性
    def eat(self):
        print("%s is eating %s" % (self.name, self.__food))
 
    @eat.setter  # 为静态属性传值
    def eat(self, food):
        print("set %s to food %s" % (self.name, food))
        self.__food = food  # 将值赋给私有属性 food
 
    @eat.deleter  # 删除属性方法,普通方式无法删除。
    def eat(self):
        del self.__food
        print("It is deleted.")
 
d = Dog("Doggy")
d.eat
d.eat = 'pork'
d.eat
del d.eat  # 删除属性方法

二、类的特殊成员方法

2.1 __doc__ 表示类的描述信息

class Dog(object):
    """This is a class for dog."""
 
    def __init__(self, name):
        self.name = name
 
print(Dog.__doc__)
#输出:类的描述信息

2.2 __module____class__

__module__ 表示当前操作的对象在哪个模块
__class__ 表示当前操作的对象的类是什么

class C:
 
    def __init__(self):
        self.name = 'Will'
from lib.aa import C
 
obj = C()
print(obj.__module__)  # 输出 lib.aa,即:输出模块
print(obj.__class__)  # 输出 lib.aa.C,即:输出类

2.3 __init__ 构造方法,通过类创建对象时,自动触发执行。

2.4 __del__ 析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的

2.5 __call__ 对象后面加括号,触发执行。

构造方法的执行是由创建对象触发的,即:对象 = 类名() ;
而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:
    def __init__(self):
        pass
 
    def __call__(self, *args, **kwargs):
        print("call", args, kwargs)
 
obj = Foo()  # 执行 __init__
obj(1234, name='abc')  # 执行 __call__

2.6 __dict__ 查看类或对象中的所有成员

class Dog(object):
    """This is a class for dog."""
 
    def __init__(self, name):
        self.name = name
 
d = Dog("Wangwang")

print(Dog.__dict__)
# 输出:{'__module__': '__main__', '__doc__': 'This is a class for dog.', '__init__': <function Dog.__init__ at 0x0000022ABB64B8C8>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>}

print(d.__dict__)
# 输出:{'name': 'Wangwang'}

2.7 __str__ 如果一个类中定义了str方法,那么在打印对象时,默认输出该方法的返回值。

class Foo:

    def __str__(self):
        return 'alex li'

obj = Foo()
print obj
# 输出:alex li

2.8 __getitem__, __setitem__, __delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

class Foo(object):
 
    def __getitem__(self, key):
        print('__getitem__',key)
 
    def __setitem__(self, key, value):
        print('__setitem__',key,value)
 
    def __delitem__(self, key):
        print('__delitem__',key)

obj = Foo()
 
result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'] = 'alex'   # 自动触发执行 __setitem__
del obj['k1']   

2.9 __new__, __metaclass__

class Foo(object):

    def __init__(self,name):
        self.name = name

obj = Foo("alex")

上述代码中,obj 是通过 Foo 类实例化的对象。
其实,不仅 obj 是一个对象,Foo类本身也是一个对象。
因为在Python中一切事物都是对象
按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的构造方法创建。

print type(f) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
print type(Foo) # 输出:<type 'type'>              表示,Foo类对象由 type 类创建

所以,obj 对象是Foo类的一个实例,Foo类对象是 type 类的一个实例
即:Foo类对象是通过type类的构造方法创建。

def func(self):
    print("Hello, %s" % self.name)
 
def __init__(self, name, age):
    self.name = name
    self.age = age
 
Foo = type('Foo', (object,), {'__init__': __init__, 'func': func})
f = Foo("Will", 30)
print(type(Foo))
f.func()

类是由type类实例化产生
那么type类中如何实现的创建类?类又是如何创建对象?

类中有一个属性 metaclass,其用来表示该类由 谁 来实例化创建,所以,我们可以为 metaclass 设置一个type类的派生类,从而查看 类 创建的过程。

class MyType(type):
    def __init__(self, child_cls, bases=None, dict=None):
        print("--MyType init---", child_cls, bases, dict)
        # super(MyType, self).__init__(child_cls, bases, dict)
 
    # def __new__(cls, *args, **kwargs):
    #     print("in mytype new:",cls,args,kwargs)
    #     type.__new__(cls)
 
    def __call__(self, *args, **kwargs):
        print("in mytype call:", self, args, kwargs)
        obj = self.__new__(self, args, kwargs)
 
        self.__init__(obj, *args, **kwargs)
 
 
class Foo(object, metaclass=MyType):  # in python3
    # __metaclass__ = MyType  # in python2
 
    def __init__(self, name):
        self.name = name
        print("Foo ---init__")
 
    def __new__(cls, *args, **kwargs):
        print("Foo --new--")
        return object.__new__(cls)  # 继承父类的__new__方法
 
    def __call__(self, *args, **kwargs):
        print("Foo --call--", args, kwargs)
 
 
# 第一阶段:解释器从上到下执行代码创建Foo类
# 第二阶段:通过Foo类创建obj对象
obj = Foo("Alex")
# print(obj.name)

类的生成 调用 顺序依次是 __new__ --> __call__ --> __init__

三、异常处理

参考

3.1 异常基础

在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!

li = []
 
try:
   li[1]
except IndexError as e:
    print("Index error: ", e)

3.2 异常种类

3.2.1 常用异常

AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError 语法错误
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的

3.2.2 更多异常
ArithmeticError AssertionError AttributeError BaseException
BufferError BytesWarning DeprecationWarning EnvironmentError
EOFError Exception FloatingPointError FutureWarning
GeneratorExit ImportError ImportWarning IndentationError
IndexError IOError KeyboardInterrupt KeyError
LookupError MemoryError NameError NotImplementedError
OSError OverflowError PendingDeprecationWarning ReferenceError
RuntimeError RuntimeWarning StandardError StopIteration
SyntaxError SyntaxWarning SystemError SystemExit
TabError TypeError UnboundLocalError UnicodeDecodeError
UnicodeEncodeError UnicodeError UnicodeTranslateError UnicodeWarning
UserWarning ValueError Warning ZeroDivisionError

3.3 异常实例

3.3.1 单个异常处理

实例:IndexError

dic = ["wupeiqi", 'alex']
try:
    dic[10]
except IndexError as e:
    print('错误', e)

实例:KeyError

dic = {'k1':'v1'}
try:
    dic['k20']
except KeyError as e:
    print('错误', e)

实例:ValueError

s1 = 'hello'
try:
    int(s1)
except ValueError as e:
    print('错误', e)
3.3.2 多个异常处理
# 未捕获到异常,程序直接报错
 
s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print('错误', e)

上述实例中,异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。
所以,写程序时需要考虑到try代码块中可能出现的任意异常,可以这样写:

s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print('错误', e)
except KeyError as e:
    print('错误', e)
except ValueError as e:
    print('错误', e)

也可以合并,写为以下形式:

s1 = 'hello'
try:
    int(s1)
except (IndexError, KeyError, ValueError) as e:
    print('错误', e)

但这样写会分不清错误类型。除非出错类型的处理方式相同,不然不要这样写。

3.3.3 万能异常

在Python的异常中,有一个万能异常 Exception,可以捕获任意异常。

s1 = 'hello'
try:
    int(s1)
except Exception as e:
    print('未知错误', e)

但有了这个万能异常,其他异常就不是可以忽略了。
对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行。

s1 = 'hello'
try:
    int(s1)
except KeyError as e:
    print('键错误', e)
except IndexError as e:
    print('索引错误', e)
except Exception as e:
    print('未知错误', e)

3.4 异常的其他结构

num = 1
try:
    # 主代码块
    print(num)
except Exception as e:
    # 异常时,执行该块
    print('未知错误', e)
else:
    # 主代码块执行完,执行该块
    print("It's work.")
finally:
    # 无论异常与否,最终执行该块
    print("No matter it's error or not, I'll run it.")

3.5 主动触发异常

try:
    raise Exception('错误了。。。')
except Exception as e:
    print(e)

3.6 自定义异常

class OwnException(Exception):
    def __init__(self, msg):
        self.message = msg
 
    def __str__(self):
        return self.message
 
try:
    raise OwnException("Cannot connect the database")
except OwnException as e:
    print(e)

四、Socket编程

参考

4.1

Socket Families 地址簇

  • socket.AF_INET  IPv4(默认)
  • socket.AF_INET6  IPv6
  • socket.AF_UNIX  只能够用于单一的Unix系统进程间通信

Socket Types 类型

  • socket.SOCK_STREAM  流式socket , for TCP (默认)
  • socket.SOCK_DGRAM  数据报式socket , for UDP
  • socket.SOCK_RAW   原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
  • socket.SOCK_RDM   是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
  • socket.SOCK_SEQPACKET 可靠的连续数据包服务

Socket Protocol 协议

五、作业:简单FTP

开发简单的FTP:

  1. 用户登陆
  2. 上传/下载文件
  3. 不同用户家目录不同
  4. 查看当前目录下文件
  5. 充分使用面向对象知识
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,493评论 18 399
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,028评论 0 62
  • 史上最全的iOS面试题及答案 迷途的羔羊--专为路痴量身打造的品牌。史上最精准的定位。想迷路都难!闪电更新中......
    南虞阅读 1,491评论 0 8
  • 有志者,事竟成,破釜沉舟,百二秦关终属楚 苦心人,天不负,卧薪尝胆,三千越甲可吞吴
    辣翅坚果阅读 227评论 0 0